-
Notifications
You must be signed in to change notification settings - Fork 8
lateral tables - basic select, batch insert #236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
516b06f
08a9ee4
c28ee2b
b1ac189
f705c01
c227ad0
ac23a0d
88191eb
fdd3420
33ca7fa
f2dbea3
280fe4b
89d99b4
e5bb9d9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,6 +1,6 @@ | ||||||
| use super::functions::{is_date_function, is_numeric_function, is_type_polymorphic_function}; | ||||||
| use crate::common::lazy::DB_SCHEMA; | ||||||
| use crate::common::logger::warning; | ||||||
| use crate::common::logger::{error, warning}; | ||||||
| use crate::core::connection::DBConn; | ||||||
| use crate::ts_generator::errors::TsGeneratorError; | ||||||
| use crate::ts_generator::sql_parser::expressions::translate_data_type::translate_value; | ||||||
|
|
@@ -180,20 +180,46 @@ pub async fn translate_expr( | |||||
| Expr::Identifier(ident) => { | ||||||
| let column_name = DisplayIndent(ident).to_string(); | ||||||
| let table_name = single_table_name.expect("Missing table name for identifier"); | ||||||
|
|
||||||
| // First check if this is a table-valued function column | ||||||
| if let Some(tvf_columns) = ts_query.table_valued_function_columns.get(table_name) { | ||||||
| if let Some(ts_type) = tvf_columns.get(&column_name) { | ||||||
| let field_name = alias.unwrap_or(column_name.as_str()); | ||||||
| ts_query.insert_result( | ||||||
| Some(field_name), | ||||||
| &[ts_type.to_owned()], | ||||||
| is_selection, | ||||||
| false, // Table-valued function columns are not nullable by default | ||||||
| expr_for_logging, | ||||||
| )?; | ||||||
| return Ok(()); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Fall back to database schema | ||||||
| let table_details = &DB_SCHEMA.lock().await.fetch_table(&vec![table_name], db_conn).await; | ||||||
|
|
||||||
| // TODO: We can also memoize this method | ||||||
| if let Some(table_details) = table_details { | ||||||
| let field = table_details.get(&column_name).unwrap(); | ||||||
|
|
||||||
| let field_name = alias.unwrap_or(column_name.as_str()); | ||||||
| ts_query.insert_result( | ||||||
| Some(field_name), | ||||||
| &[field.field_type.to_owned()], | ||||||
| is_selection, | ||||||
| field.is_nullable, | ||||||
| expr_for_logging, | ||||||
| )? | ||||||
| if let Some(field) = table_details.get(&column_name) { | ||||||
| let field_name = alias.unwrap_or(column_name.as_str()); | ||||||
| ts_query.insert_result( | ||||||
| Some(field_name), | ||||||
| &[field.field_type.to_owned()], | ||||||
| is_selection, | ||||||
| field.is_nullable, | ||||||
| expr_for_logging, | ||||||
| )? | ||||||
| } else { | ||||||
| error!( | ||||||
| "Column '{}' not found in table '{}'. If '{}' is a table-valued function, verify that the column is defined in its alias. Otherwise, the column may not exist in the table.", | ||||||
| column_name, table_name, table_name | ||||||
| ); | ||||||
| } | ||||||
| } else { | ||||||
| error!( | ||||||
| "Table '{}' not found in schema. This may be a table-valued function.", | ||||||
|
JasonShin marked this conversation as resolved.
|
||||||
| table_name | ||||||
| ); | ||||||
| } | ||||||
| Ok(()) | ||||||
| } | ||||||
|
|
@@ -203,32 +229,67 @@ pub async fn translate_expr( | |||||
|
|
||||||
| let table_name = translate_table_from_expr(table_with_joins, expr)?; | ||||||
|
|
||||||
| // First check if this is a table-valued function column | ||||||
| if let Some(tvf_columns) = ts_query.table_valued_function_columns.get(&table_name) { | ||||||
| if let Some(ts_type) = tvf_columns.get(&ident) { | ||||||
| // if the select item is a compound identifier and does not has an alias, we should use `table_name.ident` as the key name | ||||||
| let key_name = format!("{table_name}_{ident}"); | ||||||
| let key_name = &alias.unwrap_or_else(|| { | ||||||
| warning!( | ||||||
| "Missing an alias for a compound identifier, using {} as the key name. Prefer adding an alias for example: `{} AS {}`", | ||||||
| key_name, expr, ident | ||||||
| ); | ||||||
| key_name.as_str() | ||||||
| }); | ||||||
|
|
||||||
| ts_query.insert_result( | ||||||
| Some(key_name), | ||||||
| &[ts_type.to_owned()], | ||||||
| is_selection, | ||||||
| false, // Table-valued function columns are not nullable by default | ||||||
| expr_for_logging, | ||||||
| )?; | ||||||
| return Ok(()); | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Fall back to database schema | ||||||
| let table_details = &DB_SCHEMA | ||||||
| .lock() | ||||||
| .await | ||||||
| .fetch_table(&vec![table_name.as_str()], db_conn) | ||||||
| .await; | ||||||
|
|
||||||
| if let Some(table_details) = table_details { | ||||||
| let field = table_details.get(&ident).unwrap(); | ||||||
|
|
||||||
| // if the select item is a compound identifier and does not has an alias, we should use `table_name.ident` as the key name | ||||||
| let key_name = format!("{table_name}_{ident}"); | ||||||
| let key_name = &alias.unwrap_or_else(|| { | ||||||
| warning!( | ||||||
| "Missing an alias for a compound identifier, using {} as the key name. Prefer adding an alias for example: `{} AS {}`", | ||||||
| key_name, expr, ident | ||||||
| ); | ||||||
| key_name.as_str() | ||||||
| }); | ||||||
|
|
||||||
| ts_query.insert_result( | ||||||
| Some(key_name), | ||||||
| &[field.field_type.to_owned()], | ||||||
| is_selection, | ||||||
| field.is_nullable, | ||||||
| expr_for_logging, | ||||||
| )?; | ||||||
| if let Some(field) = table_details.get(&ident) { | ||||||
|
||||||
| // if the select item is a compound identifier and does not has an alias, we should use `table_name.ident` as the key name | ||||||
| let key_name = format!("{table_name}_{ident}"); | ||||||
| let key_name = &alias.unwrap_or_else(|| { | ||||||
| warning!( | ||||||
| "Missing an alias for a compound identifier, using {} as the key name. Prefer adding an alias for example: `{} AS {}`", | ||||||
| key_name, expr, ident | ||||||
| ); | ||||||
| key_name.as_str() | ||||||
| }); | ||||||
|
|
||||||
| ts_query.insert_result( | ||||||
| Some(key_name), | ||||||
| &[field.field_type.to_owned()], | ||||||
| is_selection, | ||||||
| field.is_nullable, | ||||||
| expr_for_logging, | ||||||
| )?; | ||||||
| } else { | ||||||
| error!( | ||||||
| "Column '{}' not found in table '{}' for compound identifier '{}.{}'. This may be a table-valued function.", | ||||||
|
||||||
| "Column '{}' not found in table '{}' for compound identifier '{}.{}'. This may be a table-valued function.", | |
| "Column '{}' not found in table '{}' for compound identifier '{}.{}'. This is unexpected: column not found in either table-valued function columns or database schema.", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The nested if-let chain (lines 202-217) should use if-let-else chaining or early returns to reduce nesting depth and improve readability.