From 2a4305e7fa5f9d1410b5d5690780fb5d7665d595 Mon Sep 17 00:00:00 2001 From: Leo5878 Date: Sun, 30 Nov 2025 19:29:07 +0300 Subject: [PATCH 1/2] Replace any with unknown --- .../expressions/translate_data_type.rs | 10 +-- .../sql_parser/expressions/translate_expr.rs | 26 ++++---- src/ts_generator/types/ts_query.rs | 65 +++++++++++++++++-- 3 files changed, 77 insertions(+), 24 deletions(-) diff --git a/src/ts_generator/sql_parser/expressions/translate_data_type.rs b/src/ts_generator/sql_parser/expressions/translate_data_type.rs index 5e6948ff..dfeb311a 100644 --- a/src/ts_generator/sql_parser/expressions/translate_data_type.rs +++ b/src/ts_generator/sql_parser/expressions/translate_data_type.rs @@ -138,7 +138,7 @@ pub fn translate_data_type(data_type: &DataType) -> TsFieldType { DataType::Datetime64(_, _) => TsFieldType::Date, DataType::Timestamp(_, _) => TsFieldType::String, DataType::TimestampNtz => TsFieldType::String, - DataType::Interval { .. } => TsFieldType::Any, + DataType::Interval { .. } => TsFieldType::Unknown, // JSON types DataType::JSON => TsFieldType::Object, @@ -151,9 +151,9 @@ pub fn translate_data_type(data_type: &DataType) -> TsFieldType { DataType::TsQuery => TsFieldType::String, // Complex types - DataType::Custom(_, _) => TsFieldType::Any, + DataType::Custom(_, _) => TsFieldType::Unknown, DataType::Array(array_element_type_def) => match array_element_type_def { - sqlparser::ast::ArrayElemTypeDef::None => TsFieldType::Array(Box::new(TsFieldType::Any)), + sqlparser::ast::ArrayElemTypeDef::None => TsFieldType::Array(Box::new(TsFieldType::Unknown)), sqlparser::ast::ArrayElemTypeDef::AngleBracket(data_type) => { TsFieldType::Array(Box::new(translate_data_type(data_type))) } @@ -177,8 +177,8 @@ pub fn translate_data_type(data_type: &DataType) -> TsFieldType { DataType::LowCardinality(inner_type) => translate_data_type(inner_type), // Special types - DataType::Unspecified => TsFieldType::Any, - DataType::Trigger => TsFieldType::Any, + DataType::Unspecified => TsFieldType::Unknown, + DataType::Trigger => TsFieldType::Unknown, DataType::AnyType => TsFieldType::Any, } } diff --git a/src/ts_generator/sql_parser/expressions/translate_expr.rs b/src/ts_generator/sql_parser/expressions/translate_expr.rs index 9233c74b..b166e147 100644 --- a/src/ts_generator/sql_parser/expressions/translate_expr.rs +++ b/src/ts_generator/sql_parser/expressions/translate_expr.rs @@ -431,13 +431,13 @@ pub async fn translate_expr( ts_query.insert_param(&inferred_type, &false, &Some(placeholder.to_string())) } Expr::JsonAccess { value: _, path: _ } => { - ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging)?; - ts_query.insert_param(&TsFieldType::Any, &false, &None) + ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging)?; + ts_query.insert_param(&TsFieldType::Unknown, &false, &None) } Expr::IsNotDistinctFrom(_, placeholder) | Expr::IsDistinctFrom(_, placeholder) => { // IsDistinctFrom and IsNotDistinctFrom are the same and can have a placeholder ts_query.insert_param(&TsFieldType::String, &false, &Some(placeholder.to_string()))?; - ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging) + ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging) } Expr::SimilarTo { negated: _, @@ -523,10 +523,10 @@ pub async fn translate_expr( ts_query.insert_result(alias, &[TsFieldType::String], is_selection, false, expr_for_logging) } Expr::Collate { expr: _, collation: _ } => { - ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging) + ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging) } - Expr::TypedString(_) => ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging), - Expr::Map(_) => ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging), + Expr::TypedString(_) => ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging), + Expr::Map(_) => ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging), // Note: AggregateExpressionWithFilter was removed in sqlparser 0.59.0 // Aggregate functions with filters are now part of the Function variant Expr::Case { @@ -535,7 +535,7 @@ pub async fn translate_expr( else_result: _, case_token: _, end_token: _, - } => ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging), + } => ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging), Expr::Exists { subquery, negated: _ } => { ts_query.insert_result(alias, &[TsFieldType::Boolean], is_selection, false, expr_for_logging)?; translate_query(ts_query, &None, subquery, db_conn, alias, false).await @@ -543,14 +543,14 @@ pub async fn translate_expr( // Note: ListAgg and ArrayAgg were removed in sqlparser 0.59.0 // They are now represented as Function variants Expr::GroupingSets(_) | Expr::Cube(_) | Expr::Rollup(_) | Expr::Tuple(_) | Expr::Array(_) => { - ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging) + ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging) } // Note: ArrayIndex was replaced with CompoundFieldAccess in sqlparser 0.59.0 // CompoundFieldAccess handles array indexing, map access, and composite field access Expr::CompoundFieldAccess { root: _, access_chain: _, - } => ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging), + } => ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging), Expr::Interval(_) => ts_query.insert_result(alias, &[TsFieldType::Number], is_selection, false, expr_for_logging), Expr::MatchAgainst { columns: _, @@ -655,7 +655,7 @@ pub async fn translate_expr( } // Fallback to Any if we couldn't infer the type - return ts_query.insert_result(Some(alias), &[TsFieldType::Any], is_selection, false, expr_for_logging); + return ts_query.insert_result(Some(alias), &[TsFieldType::Unknown], is_selection, false, expr_for_logging); } // Handle other function types @@ -684,7 +684,7 @@ pub async fn translate_expr( expr_for_logging, )?; } else { - ts_query.insert_result(Some(alias), &[TsFieldType::Any], is_selection, false, expr_for_logging)?; + ts_query.insert_result(Some(alias), &[TsFieldType::Unknown], is_selection, false, expr_for_logging)?; } Ok(()) @@ -717,8 +717,8 @@ pub async fn translate_expr( expr: _, array_expr: _, negated: _, - } => ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging), - _ => ts_query.insert_result(alias, &[TsFieldType::Any], is_selection, false, expr_for_logging), + } => ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging), + _ => ts_query.insert_result(alias, &[TsFieldType::Unknown], is_selection, false, expr_for_logging), } } diff --git a/src/ts_generator/types/ts_query.rs b/src/ts_generator/types/ts_query.rs index 228f7cf0..3b8e9080 100644 --- a/src/ts_generator/types/ts_query.rs +++ b/src/ts_generator/types/ts_query.rs @@ -20,6 +20,7 @@ pub enum TsFieldType { Null, Enum(Vec), Any, + Unknown, #[allow(dead_code)] Array2D(Array2DContent), Array(Box), @@ -38,6 +39,7 @@ impl fmt::Display for TsFieldType { TsFieldType::Any => write!(f, "any"), TsFieldType::Null => write!(f, "null"), TsFieldType::Never => write!(f, "never"), + TsFieldType::Unknown => write!(f, "unknown"), TsFieldType::Array(ts_field_type) => { let ts_field_type = ts_field_type.clone(); let ts_field_type = *ts_field_type; @@ -90,7 +92,7 @@ impl TsFieldType { "character" | "character varying" | "bytea" | "uuid" | "text" => Self::String, "boolean" => Self::Boolean, "json" | "jsonb" => Self::Object, - "ARRAY" | "array" => Self::Any, + "ARRAY" | "array" => Self::Unknown, "date" => Self::Date, "USER-DEFINED" => { if let Some(enum_values) = enum_values { @@ -98,9 +100,9 @@ impl TsFieldType { } let warning_message = format!("Failed to find enum values for field {field_name} of table {table_name}"); warning!(warning_message); - Self::Any + Self::Unknown } - _ => Self::Any, + _ => Self::Unknown, } } @@ -122,9 +124,9 @@ impl TsFieldType { let warning_message = format!("Failed to find enum values for field {field_name} of table {table_name}"); warning!(warning_message); - Self::Any + Self::Unknown } - _ => Self::Any, + _ => Self::Unknown, } } @@ -140,7 +142,56 @@ impl TsFieldType { } else if annotated_type == "null" { return Self::Null; } - Self::Any + Self::Unknown + } + + /// Converts a sqlparser DataType from table alias column definitions to TsFieldType + /// This is used to infer types from table-valued function aliases like: + /// `jsonb_to_recordset($1) AS t(id INT, name TEXT)` + pub fn from_sqlparser_datatype(data_type: &sqlparser::ast::DataType) -> Self { + use sqlparser::ast::DataType; + + match data_type { + // Integer types + DataType::SmallInt(_) | DataType::SmallIntUnsigned(_) | + DataType::Int(_) | DataType::Int2(_) | DataType::Int4(_) | DataType::Int8(_) | + DataType::Integer(_) | DataType::IntUnsigned(_) | DataType::IntegerUnsigned(_) | + DataType::BigInt(_) | DataType::BigIntUnsigned(_) | + DataType::TinyInt(_) | DataType::TinyIntUnsigned(_) | + DataType::MediumInt(_) | DataType::MediumIntUnsigned(_) | + DataType::Int16 | DataType::Int32 | DataType::Int64 | DataType::Int128 | DataType::Int256 | + DataType::UInt8 | DataType::UInt16 | DataType::UInt32 | DataType::UInt64 | DataType::UInt128 | DataType::UInt256 | + // Floating point types + DataType::Real | DataType::Float(_) | DataType::Float4 | DataType::Float8 | + DataType::Double(_) | DataType::DoublePrecision | DataType::Float64 | + DataType::Decimal(_) | DataType::Dec(_) | DataType::Numeric(_) | + DataType::BigNumeric(_) | DataType::BigDecimal(_) => Self::Number, + + // String types + DataType::Character(_) | DataType::Char(_) | + DataType::CharacterVarying(_) | DataType::CharVarying(_) | + DataType::Varchar(_) | DataType::Nvarchar(_) | + DataType::Text | DataType::String(_) | + DataType::Uuid | + DataType::Bytea | DataType::Binary(_) | DataType::Varbinary(_) | + DataType::Blob(_) | DataType::Clob(_) => Self::String, + + // Boolean type + DataType::Boolean | DataType::Bool => Self::Boolean, + + // JSON types + DataType::JSON | DataType::JSONB => Self::Object, + + // Date/Time types + DataType::Date | DataType::Datetime(_) | DataType::Timestamp(_, _) | + DataType::Time(_, _) => Self::Date, + + // Array types + DataType::Array(_) => Self::Any, + + // Everything else defaults to Any + _ => Self::Any, + } } /// Converts a sqlparser DataType from table alias column definitions to TsFieldType @@ -449,6 +500,8 @@ impl fmt::Display for TsQuery { let query = format!("export interface I{name}Query {{\n\tparams: {name}Params;\n\tresult: I{name}Result;\n}}"); + // let jenericResult = format!("export interface I{name}Results {{\n\t{result_str}\n}}"); + let final_code = format!("{params}\n\n{result}\n\n{query}"); writeln!(f, "{final_code}") From b8b0420c2073aac03e17576bae93a5756650a8c6 Mon Sep 17 00:00:00 2001 From: Leo5878 Date: Sun, 30 Nov 2025 20:22:58 +0300 Subject: [PATCH 2/2] Remove unnecessary --- src/ts_generator/types/ts_query.rs | 51 ------------------------------ 1 file changed, 51 deletions(-) diff --git a/src/ts_generator/types/ts_query.rs b/src/ts_generator/types/ts_query.rs index 3b8e9080..a0f84781 100644 --- a/src/ts_generator/types/ts_query.rs +++ b/src/ts_generator/types/ts_query.rs @@ -193,55 +193,6 @@ impl TsFieldType { _ => Self::Any, } } - - /// Converts a sqlparser DataType from table alias column definitions to TsFieldType - /// This is used to infer types from table-valued function aliases like: - /// `jsonb_to_recordset($1) AS t(id INT, name TEXT)` - pub fn from_sqlparser_datatype(data_type: &sqlparser::ast::DataType) -> Self { - use sqlparser::ast::DataType; - - match data_type { - // Integer types - DataType::SmallInt(_) | DataType::SmallIntUnsigned(_) | - DataType::Int(_) | DataType::Int2(_) | DataType::Int4(_) | DataType::Int8(_) | - DataType::Integer(_) | DataType::IntUnsigned(_) | DataType::IntegerUnsigned(_) | - DataType::BigInt(_) | DataType::BigIntUnsigned(_) | - DataType::TinyInt(_) | DataType::TinyIntUnsigned(_) | - DataType::MediumInt(_) | DataType::MediumIntUnsigned(_) | - DataType::Int16 | DataType::Int32 | DataType::Int64 | DataType::Int128 | DataType::Int256 | - DataType::UInt8 | DataType::UInt16 | DataType::UInt32 | DataType::UInt64 | DataType::UInt128 | DataType::UInt256 | - // Floating point types - DataType::Real | DataType::Float(_) | DataType::Float4 | DataType::Float8 | - DataType::Double(_) | DataType::DoublePrecision | DataType::Float64 | - DataType::Decimal(_) | DataType::Dec(_) | DataType::Numeric(_) | - DataType::BigNumeric(_) | DataType::BigDecimal(_) => Self::Number, - - // String types - DataType::Character(_) | DataType::Char(_) | - DataType::CharacterVarying(_) | DataType::CharVarying(_) | - DataType::Varchar(_) | DataType::Nvarchar(_) | - DataType::Text | DataType::String(_) | - DataType::Uuid | - DataType::Bytea | DataType::Binary(_) | DataType::Varbinary(_) | - DataType::Blob(_) | DataType::Clob(_) => Self::String, - - // Boolean type - DataType::Boolean | DataType::Bool => Self::Boolean, - - // JSON types - DataType::JSON | DataType::JSONB => Self::Object, - - // Date/Time types - DataType::Date | DataType::Datetime(_) | DataType::Timestamp(_, _) | - DataType::Time(_, _) => Self::Date, - - // Array types - DataType::Array(_) => Self::Any, - - // Everything else defaults to Any - _ => Self::Any, - } - } } /// TsQuery holds information required to generate typescript type definition @@ -500,8 +451,6 @@ impl fmt::Display for TsQuery { let query = format!("export interface I{name}Query {{\n\tparams: {name}Params;\n\tresult: I{name}Result;\n}}"); - // let jenericResult = format!("export interface I{name}Results {{\n\t{result_str}\n}}"); - let final_code = format!("{params}\n\n{result}\n\n{query}"); writeln!(f, "{final_code}")