diff --git a/crates/cli/src/lib.rs b/crates/cli/src/lib.rs index 10dcf8e..690f75b 100644 --- a/crates/cli/src/lib.rs +++ b/crates/cli/src/lib.rs @@ -153,7 +153,8 @@ async fn update(context: Context) -> anyhow::Result<()> { let existing_configuration = configuration::parse_configuration(&context.context_path).await?; let output = - configuration::introspect(&existing_configuration.clone(), &context.environment).await?; + configuration::introspect(&existing_configuration.clone(), &context.environment) + .await?; // Check that the input file did not change since we started introspecting, let input_again_before_write = diff --git a/crates/configuration/src/configuration.rs b/crates/configuration/src/configuration.rs index 22a5fe2..3548be3 100644 --- a/crates/configuration/src/configuration.rs +++ b/crates/configuration/src/configuration.rs @@ -24,4 +24,4 @@ pub struct Configuration { // pub provider_name: String, pub region: String, // pub mutations_version: Option, -} \ No newline at end of file +} diff --git a/crates/configuration/src/connection_settings.rs b/crates/configuration/src/connection_settings.rs index f92a46d..fd5743e 100644 --- a/crates/configuration/src/connection_settings.rs +++ b/crates/configuration/src/connection_settings.rs @@ -1,6 +1,6 @@ //! Database connection settings. -use crate::values::{Secret, AccessKeyId, SecretAccessKey, Region}; +use crate::values::{AccessKeyId, Region, Secret, SecretAccessKey}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; diff --git a/crates/configuration/src/lib.rs b/crates/configuration/src/lib.rs index 611c6f6..b4e61cc 100644 --- a/crates/configuration/src/lib.rs +++ b/crates/configuration/src/lib.rs @@ -1,12 +1,14 @@ -pub mod version1; -pub mod connection_settings; pub mod configuration; +pub mod connection_settings; pub mod environment; pub mod error; -mod values; mod to_runtime_configuration; +mod values; +pub mod version1; pub use configuration::Configuration; +pub use to_runtime_configuration::make_runtime_configuration; +pub use values::connection_info::{AccessKeyId, ProviderName, Region, SecretAccessKey}; pub use version1::{ introspect, parse_configuration, @@ -18,5 +20,3 @@ pub use version1::{ // PoolSettings, ParsedConfiguration, }; -pub use values::connection_info::{AccessKeyId, Region, SecretAccessKey, ProviderName}; -pub use to_runtime_configuration::make_runtime_configuration; diff --git a/crates/configuration/src/to_runtime_configuration.rs b/crates/configuration/src/to_runtime_configuration.rs index 1bb4fad..69b27ec 100644 --- a/crates/configuration/src/to_runtime_configuration.rs +++ b/crates/configuration/src/to_runtime_configuration.rs @@ -4,7 +4,7 @@ use super::version1::ParsedConfiguration; use crate::environment::Environment; use crate::error::MakeRuntimeConfigurationError; -use crate::values::{Secret, AccessKeyId, Region, SecretAccessKey}; +use crate::values::{AccessKeyId, Region, Secret, SecretAccessKey}; use query_engine_metadata::{self, metadata}; // use crate::VersionTag; diff --git a/crates/configuration/src/values/connection_info.rs b/crates/configuration/src/values/connection_info.rs index 907cfad..ba71cca 100644 --- a/crates/configuration/src/values/connection_info.rs +++ b/crates/configuration/src/values/connection_info.rs @@ -61,4 +61,4 @@ impl From<&str> for Region { fn from(value: &str) -> Self { Self::from(value.to_string()) } -} \ No newline at end of file +} diff --git a/crates/configuration/src/values/mod.rs b/crates/configuration/src/values/mod.rs index b7f2999..9793a0a 100644 --- a/crates/configuration/src/values/mod.rs +++ b/crates/configuration/src/values/mod.rs @@ -1,6 +1,6 @@ -mod secret; -mod pool_settings; pub mod connection_info; +mod pool_settings; +mod secret; +pub use connection_info::{AccessKeyId, Region, SecretAccessKey}; pub use secret::Secret; -pub use connection_info::{AccessKeyId, SecretAccessKey, Region}; \ No newline at end of file diff --git a/crates/configuration/src/version1.rs b/crates/configuration/src/version1.rs index c552dbc..bc71a7e 100644 --- a/crates/configuration/src/version1.rs +++ b/crates/configuration/src/version1.rs @@ -1,9 +1,9 @@ //! Internal Configuration and state for our connector. -use crate::{connection_settings, AccessKeyId, SecretAccessKey}; use crate::environment::Environment; use crate::error::WriteParsedConfigurationError; use crate::values::Secret; +use crate::{connection_settings, AccessKeyId, SecretAccessKey}; use super::error::ParseConfigurationError; use aws_sdk_dynamodb::types::KeyType; @@ -16,7 +16,9 @@ use std::collections::{BTreeMap, BTreeSet}; use std::path::Path; use tokio::fs; -use query_engine_metadata::metadata::{self, database, ColumnInfo, Nullable, ProjectionTypeInfo, ScalarTypes, TablesInfo}; +use query_engine_metadata::metadata::{ + self, database, ColumnInfo, Nullable, ProjectionTypeInfo, ScalarTypes, TablesInfo, +}; const CURRENT_VERSION: u32 = 1; pub const CONFIGURATION_FILENAME: &str = "configuration.json"; @@ -24,7 +26,6 @@ const CHARACTER_STRINGS: [&str; 3] = ["character", "text", "string"]; const UNICODE_CHARACTER_STRINGS: [&str; 3] = ["nchar", "ntext", "nvarchar"]; const CANNOT_COMPARE: [&str; 3] = ["text", "ntext", "image"]; - /// Initial configuration, just enough to connect to a database and elaborate a full /// 'Configuration'. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize, JsonSchema)] @@ -68,11 +69,15 @@ pub async fn introspect( ) -> anyhow::Result { let access_key_id = match &args.connection_settings.access_key_id { AccessKeyId(Secret::Plain(value)) => Cow::Borrowed(value), - AccessKeyId(Secret::FromEnvironment { variable }) => Cow::Owned(environment.read(variable)?), + AccessKeyId(Secret::FromEnvironment { variable }) => { + Cow::Owned(environment.read(variable)?) + } }; let secret_access_key = match &args.connection_settings.secret_access_key { SecretAccessKey(Secret::Plain(value)) => Cow::Borrowed(value), - SecretAccessKey(Secret::FromEnvironment { variable }) => Cow::Owned(environment.read(variable)?), + SecretAccessKey(Secret::FromEnvironment { variable }) => { + Cow::Owned(environment.read(variable)?) + } }; // let provider_name = match &args.connection_settings.provider_name { // ProviderName(Secret::Plain(value)) => Cow::Borrowed(value), @@ -80,7 +85,9 @@ pub async fn introspect( // }; let region = match &args.connection_settings.region { crate::Region(Secret::Plain(value)) => Cow::Borrowed(value), - crate::Region(Secret::FromEnvironment { variable }) => Cow::Owned(environment.read(variable)?), + crate::Region(Secret::FromEnvironment { variable }) => { + Cow::Owned(environment.read(variable)?) + } }; // let access_key_id = args.connection_settings.access_key_id.clone(); // let secret_access_key = args.connection_settings.secret_access_key.clone(); @@ -90,16 +97,16 @@ pub async fn introspect( let credentials = aws_sdk_dynamodb::config::Credentials::new( access_key_id.to_string(), secret_access_key.to_string(), - None, // Optional session token - None, // Expiration (None for non-expiring) - "my-provider", // Provider name + None, // Optional session token + None, // Expiration (None for non-expiring) + "my-provider", // Provider name ); - + // Configure AWS SDK with explicit credentials let config = Config::builder() - .region(aws_config::Region::new(region.to_string())) - .credentials_provider(credentials) - .build(); + .region(aws_config::Region::new(region.to_string())) + .credentials_provider(credentials) + .build(); // To use localhost url // let config = aws_config::defaults(aws_config::BehaviorVersion::latest()) @@ -114,13 +121,12 @@ pub async fn introspect( let client = aws_sdk_dynamodb::Client::from_conf(config); let tables_result = client.list_tables().send().await; // dbg!(&tables_result); - let tables = tables_result.map_err(|_op| { - ParseConfigurationError::IoErrorButStringified(format!( - "Failed to list tables:", - // op.error_message.unwrap() - )) - }).unwrap(); //TODO: handle error - // dbg!(&tables); + let tables = tables_result + .map_err(|_op| { + ParseConfigurationError::IoErrorButStringified("Failed to list tables:".to_string()) + }) + .unwrap(); //TODO: handle error + // dbg!(&tables); let table_names = tables.table_names.unwrap_or_default(); let mut scalars_list: BTreeSet = BTreeSet::new(); let mut tables_info: BTreeMap = BTreeMap::new(); @@ -147,7 +153,6 @@ pub async fn introspect( // "NULL" => ScalarTypeName::new("Null".into()), // "M" => ScalarTypeName::new("Object".into()), // "L" => ScalarTypeName::new("Array".into()), - _ => ScalarTypeName::new("Any".into()), }; scalars_list.insert(scalar_type_name.clone()); @@ -163,18 +168,13 @@ pub async fn introspect( //get non key attributes let result = client - .execute_statement() - .statement( - format!( - r#"select * from {}"#, - table_name - ) - ) - .set_parameters(None) - .set_limit(Some(20)) - .send() - .await - .unwrap(); + .execute_statement() + .statement(format!(r#"select * from {table_name}"#)) + .set_parameters(None) + .set_limit(Some(20)) + .send() + .await + .unwrap(); // let result = match row_1 // { @@ -190,29 +190,25 @@ pub async fn introspect( // dbg!(&result); // let row = result.first().unwrap(); - for item in result.items.unwrap().iter() { + for item in &result.items.unwrap() { for (key, attribute_value) in item { let column_name = FieldName::new(key.clone().into()); // dbg!(&column_name); - let column_type = - if attribute_value.is_s() { - let scalar_type_name = ScalarTypeName::new("String".into()); - scalars_list.insert(scalar_type_name.clone()); - metadata::Type::ScalarType(scalar_type_name) - } - else if attribute_value.is_n() { - let scalar_type_name = ScalarTypeName::new("Number".into()); - scalars_list.insert(scalar_type_name.clone()); - metadata::Type::ScalarType(scalar_type_name) - } - else if attribute_value.is_bool() { - let scalar_type_name = ScalarTypeName::new("Boolean".into()); - scalars_list.insert(scalar_type_name.clone()); - metadata::Type::ScalarType(scalar_type_name) - } - else { - metadata::Type::ScalarType(ScalarTypeName::new("Any".into())) - }; + let column_type = if attribute_value.is_s() { + let scalar_type_name = ScalarTypeName::new("String".into()); + scalars_list.insert(scalar_type_name.clone()); + metadata::Type::ScalarType(scalar_type_name) + } else if attribute_value.is_n() { + let scalar_type_name = ScalarTypeName::new("Number".into()); + scalars_list.insert(scalar_type_name.clone()); + metadata::Type::ScalarType(scalar_type_name) + } else if attribute_value.is_bool() { + let scalar_type_name = ScalarTypeName::new("Boolean".into()); + scalars_list.insert(scalar_type_name.clone()); + metadata::Type::ScalarType(scalar_type_name) + } else { + metadata::Type::ScalarType(ScalarTypeName::new("Any".into())) + }; let column_info = ColumnInfo { name: key.clone(), r#type: column_type, @@ -220,10 +216,8 @@ pub async fn introspect( description: None, }; columns_info.insert(column_name, column_info); - } - } - + } // let mut key_info: BTreeMap = BTreeMap::new(); @@ -239,7 +233,7 @@ pub async fn introspect( let partition_key = key_info.get(&KeyType::Hash).unwrap(); let sort_key = key_info.get(&KeyType::Range).unwrap(); - let mut gsi_indexes:BTreeMap = BTreeMap::new(); + let mut gsi_indexes: BTreeMap = BTreeMap::new(); let gsis = table.global_secondary_indexes.unwrap(); for gsi in gsis { let index_name = gsi.index_name.unwrap(); @@ -248,7 +242,7 @@ pub async fn introspect( for key in index_keys { let name = key.attribute_name; let key_type = key.key_type; - + if key_type == KeyType::Hash || key_type == KeyType::Range { index_keys_info.insert(key_type, name); } @@ -256,16 +250,30 @@ pub async fn introspect( let partition_key = index_keys_info.get(&KeyType::Hash).unwrap(); let sort_key: Option = index_keys_info.get(&KeyType::Range).cloned(); - let projection_type = gsi.projection.clone().unwrap().projection_type.unwrap().as_str().to_string(); - let non_key_attributes = gsi.projection.unwrap().non_key_attributes.unwrap_or_default(); - gsi_indexes.insert(index_name, metadata::GlobalSecondaryIndexInfo { - partition_key: partition_key.to_owned(), - sort_key, - projection_type: ProjectionTypeInfo { - projection_type, - non_key_attributes, - } - }); + let projection_type = gsi + .projection + .clone() + .unwrap() + .projection_type + .unwrap() + .as_str() + .to_string(); + let non_key_attributes = gsi + .projection + .unwrap() + .non_key_attributes + .unwrap_or_default(); + gsi_indexes.insert( + index_name, + metadata::GlobalSecondaryIndexInfo { + partition_key: partition_key.to_owned(), + sort_key, + projection_type: ProjectionTypeInfo { + projection_type, + non_key_attributes, + }, + }, + ); } let table_info = metadata::TableInfo { table_name: table_name.clone(), diff --git a/crates/ndc-dynamodb/bin/main.rs b/crates/ndc-dynamodb/bin/main.rs index 7caef65..d74e274 100644 --- a/crates/ndc-dynamodb/bin/main.rs +++ b/crates/ndc-dynamodb/bin/main.rs @@ -1,7 +1,7 @@ use std::process::ExitCode; -use ndc_dynamodb_configuration::environment::ProcessEnvironment; use ndc_dynamodb::connector::DynamoDBSetup; +use ndc_dynamodb_configuration::environment::ProcessEnvironment; use ndc_sdk::default_main::default_main_with; #[tokio::main] diff --git a/crates/ndc-dynamodb/src/health.rs b/crates/ndc-dynamodb/src/health.rs index 444f592..d4d5ebd 100644 --- a/crates/ndc-dynamodb/src/health.rs +++ b/crates/ndc-dynamodb/src/health.rs @@ -9,9 +9,7 @@ use aws_sdk_dynamodb::Client; /// For example, this function should check that the connector /// is able to reach its data source over the network. /// TODO -pub async fn health_check( - client: &Client, -) -> Result<(), ErrorResponse> { +pub async fn health_check(client: &Client) -> Result<(), ErrorResponse> { // Query // let mut rs = client // .job() @@ -24,18 +22,16 @@ pub async fn health_check( let tables_result = client.list_tables().send().await; let tables = tables_result.map_err(|_op| { - ndc_dynamodb_configuration::error::ParseConfigurationError::IoErrorButStringified(format!( - "Failed to list tables" - )) + ndc_dynamodb_configuration::error::ParseConfigurationError::IoErrorButStringified( + "Failed to list tables".to_string(), + ) }); //TODO: handle error match tables { - Ok(_res) => { - Ok(()) - } - Err(_e) => { - Err(ErrorResponse::new_internal_with_details(serde_json::Value::Null)) - } + Ok(_res) => Ok(()), + Err(_e) => Err(ErrorResponse::new_internal_with_details( + serde_json::Value::Null, + )), } // // silly check diff --git a/crates/ndc-dynamodb/src/schema.rs b/crates/ndc-dynamodb/src/schema.rs index 2e2074e..31e656c 100644 --- a/crates/ndc-dynamodb/src/schema.rs +++ b/crates/ndc-dynamodb/src/schema.rs @@ -82,7 +82,6 @@ pub async fn get_schema( collection_type: table_name.as_str().into(), uniqueness_constraints: BTreeMap::new(), foreign_keys: BTreeMap::new(), - }) .collect(); diff --git a/crates/ndc-dynamodb/src/state.rs b/crates/ndc-dynamodb/src/state.rs index a865464..d3fe72d 100644 --- a/crates/ndc-dynamodb/src/state.rs +++ b/crates/ndc-dynamodb/src/state.rs @@ -33,15 +33,15 @@ pub async fn create_state( let region = configuration.region.clone(); let credentials = aws_sdk_dynamodb::config::Credentials::new( - access_key_id.to_string(), - secret_access_key.to_string(), - None, // Optional session token - None, // Expiration (None for non-expiring) - "my-provider", // Provider name + access_key_id, + secret_access_key, + None, // Optional session token + None, // Expiration (None for non-expiring) + "my-provider", // Provider name ); let config = Config::builder() - .region(aws_config::Region::new(region.to_string())) + .region(aws_config::Region::new(region)) .credentials_provider(credentials) .build(); @@ -55,10 +55,7 @@ pub async fn create_state( // let dynamodb_local_config = aws_sdk_dynamodb::config::Builder::from(&config).build(); let client = aws_sdk_dynamodb::Client::from_conf(config); - Ok(State { - metrics, - client, - }) + Ok(State { metrics, client }) } /// State initialization error. diff --git a/crates/query-engine/execution/src/query.rs b/crates/query-engine/execution/src/query.rs index 74638ca..15d8688 100644 --- a/crates/query-engine/execution/src/query.rs +++ b/crates/query-engine/execution/src/query.rs @@ -4,9 +4,9 @@ use std::{collections::HashMap, vec}; use crate::error::Error; use crate::metrics; +use aws_sdk_dynamodb::Client; use bytes::{BufMut, Bytes, BytesMut}; use serde_json::{self, to_string, Value}; -use aws_sdk_dynamodb::Client; use query_engine_sql::sql; @@ -29,12 +29,7 @@ pub async fn execute( // Query let rs = client .execute_statement() - .statement( - format!( - r#"{}"#, - query_request - ) - ) + .statement(query_request.to_string()) .set_parameters(None) .set_limit(query_limit) .send() @@ -43,51 +38,47 @@ pub async fn execute( let mut res_map: Vec> = vec![]; - - for item in rs.items.unwrap().iter() { + for item in &rs.items.unwrap() { dbg!(item); let mut hashmap = HashMap::new(); - for (key, attribute_value) in item.clone(){ + for (key, attribute_value) in item.clone() { if attribute_value.is_s() { let s = attribute_value.as_s().unwrap().to_string(); - println!("String: {}", s); + println!("String: {s}"); hashmap.insert(key, s); } else if attribute_value.is_n() { let n = attribute_value.as_n().unwrap().to_string(); - println!("Number: {}", n); + println!("Number: {n}"); hashmap.insert(key, n); - } - else if attribute_value.is_bool() { + } else if attribute_value.is_bool() { let bool = attribute_value.as_bool().unwrap(); let bool_str = bool.to_string(); hashmap.insert(key, bool_str); - } - else { + } else { println!("Unknown"); } - }; + } dbg!(item); res_map.push(hashmap); } dbg!(&res_map); + let mut rows: HashMap>> = HashMap::new(); + rows.insert("rows".into(), res_map); - let mut foo: HashMap>> = HashMap::new(); - foo.insert("rows".into(), res_map); - - dbg!(&foo); + dbg!(&rows); - let bar = serde_json::to_string(&foo).unwrap(); - dbg!(&bar); + let rows_stringified = serde_json::to_string(&rows).unwrap(); + dbg!(&rows_stringified); - let row_value: Value = serde_json::from_str(&bar).unwrap(); + let row_value: Value = serde_json::from_str(&rows_stringified).unwrap(); let row_value_array = Value::Array(vec![row_value]); let final_row = to_string(&row_value_array).unwrap(); let b: Bytes = Bytes::from(final_row); - buffer.put(b); + buffer.put(b); } Some(_variable_sets) => { todo!("foreach/variables not implemented in query engine / execution") diff --git a/crates/query-engine/metadata/src/metadata/database.rs b/crates/query-engine/metadata/src/metadata/database.rs index c118dcf..085a821 100644 --- a/crates/query-engine/metadata/src/metadata/database.rs +++ b/crates/query-engine/metadata/src/metadata/database.rs @@ -115,7 +115,6 @@ pub struct TableInfo { pub sort_key: String, // pub uniqueness_constraints: UniquenessConstraints, - pub gsi: GlobalSecondaryIndexes, pub description: Option, diff --git a/crates/query-engine/sql/src/sql/convert.rs b/crates/query-engine/sql/src/sql/convert.rs index 384d050..84790e8 100644 --- a/crates/query-engine/sql/src/sql/convert.rs +++ b/crates/query-engine/sql/src/sql/convert.rs @@ -251,7 +251,10 @@ impl From { pub fn to_sql(&self, sql: &mut SQL) { sql.append_syntax("FROM "); match &self { - From::Table { reference, alias: _ } => { + From::Table { + reference, + alias: _, + } => { reference.to_sql(sql); // sql.append_syntax(" AS "); // alias.to_sql(sql); @@ -382,7 +385,10 @@ impl Expression { Expression::ColumnReference(column_reference) => column_reference.to_sql(sql), Expression::TableReference(table_reference) => table_reference.to_sql(sql), Expression::Value(value) => value.to_sql(sql), - Expression::Cast { expression, r#type: _ } => { + Expression::Cast { + expression, + r#type: _, + } => { // There is no cast expression in DynamoDB expression.to_sql(sql); } @@ -719,7 +725,6 @@ impl TableReference { sql.append_syntax("."); sql.append_identifier(&gsi.0); } - } } TableReference::AliasedTable(alias) => alias.to_sql(sql), @@ -753,7 +758,7 @@ impl TableAlias { impl ColumnReference { pub fn to_sql(&self, sql: &mut SQL) { match self { - ColumnReference::TableColumn {table: _, name } => { + ColumnReference::TableColumn { table: _, name } => { // table.to_sql(sql); // sql.append_syntax("."); sql.append_identifier(&name.0.to_string()); diff --git a/crates/query-engine/sql/src/sql/helpers.rs b/crates/query-engine/sql/src/sql/helpers.rs index 6fa9c7c..d605e86 100644 --- a/crates/query-engine/sql/src/sql/helpers.rs +++ b/crates/query-engine/sql/src/sql/helpers.rs @@ -110,11 +110,8 @@ pub fn star_from_select(table: TableReference, from: From) -> Select { with: empty_with(), select_list: SelectList::SelectStarFrom(table), from: Some(from), - // joins: vec![], where_: Where(empty_where()), - // group_by: empty_group_by(), order_by: empty_order_by(), - // limit: empty_limit(), } } @@ -125,11 +122,8 @@ pub fn where_exists_select(from: From, _joins: Vec, where_: Where) -> Expr with: empty_with(), select_list: SelectList::Select1, from: Some(from), - // joins, where_, - // group_by: empty_group_by(), order_by: empty_order_by(), - // limit: empty_limit(), }), } } @@ -143,160 +137,14 @@ pub enum ResultsKind { /// Given a set of rows, a set of aggregate queries and a variables from clause & table reference, /// combine them into one Select. -pub fn select_rowset( - // (_output_table_alias, output_column_alias): (TableAlias, ColumnAlias), - // (row_table_alias, row_inner_table_alias_): (TableAlias, TableAlias), - // (aggregate_table_alias, _aggregate_inner_table_alias): (TableAlias, TableAlias), - // _variables: &Option<(From, TableReference)>, - // output_agg_table_alias: &TableAlias, - // with: With, - select_set: SelectSet, - returns_field: &ReturnsFields, -) -> Select { +pub fn select_rowset(select_set: SelectSet, returns_field: &ReturnsFields) -> Select { match select_set { - SelectSet::Rows(row_select) => { - // let mut json_items = BTreeMap::new(); - - // json_items.insert( - // "rows".to_string(), - // Expression::FunctionCall { - // function: Function::Coalesce, - // args: vec![ - // Expression::FunctionCall { - // function: Function::ArrayAgg, - // args: vec![Expression::TableReference(TableReference::AliasedTable( - // row_table_alias.clone(), - // ))], - // }, - // Expression::ArrayConstructor(vec![]), - // ], - // }, - // ); - - // let row = vec![( - // output_column_alias, - // (Expression::JsonBuildObject(json_items)), - // )]; - - // // TableReference::AliasedTable(output_table_alias.clone()))), - - // let mut final_select = simple_select(row); - - let final_select = match returns_field { - ReturnsFields::FieldsWereRequested => - { - // let star_select = star_select(From::Select { - // alias: row_inner_table_alias_, - // select: Box::new(row_select), - // }); - // final_select.from = Some(From::Select { - // alias: row_table_alias, - // select: Box::new(star_select), - // }); - row_select - - } - ReturnsFields::NoFieldsWereRequested => { - todo!("not supported yet") - // let row1 = vec![( - // ColumnAlias { - // name: row_table_alias.to_aliased_string(), - // }, - // (Expression::JsonBuildObject(BTreeMap::new())), - // )]; - // let mut sel = simple_select(row1); - // sel.from = Some(From::Select { - // alias: row_inner_table_alias_.clone(), - // select: Box::new(row_select), - // }); - // final_select.from = Some(From::Select { - // alias: row_inner_table_alias_, - // select: Box::new(sel), - // }); - } - }; - final_select - } - // SelectSet::Aggregates(aggregate_select) => { - // let mut json_items = BTreeMap::new(); - - // json_items.insert( - // "aggregates".to_string(), - // Expression::TableReference(TableReference::AliasedTable( - // aggregate_table_alias.clone(), - // )), - // ); - - // let row = vec![( - // output_column_alias, - // (Expression::JsonBuildObject(json_items)), - // )]; - - // let mut final_select = simple_select(row); - - // final_select.from = Some(From::Select { - // alias: aggregate_table_alias, - // select: Box::new(aggregate_select), - // }); - // final_select - // } - // // _ => todo!("no select rowset for rows + aggregates"), - // SelectSet::RowsAndAggregates(row_select, aggregate_select) => { - // let mut json_items = BTreeMap::new(); - - // json_items.insert( - // "rows".to_string(), - // Expression::FunctionCall { - // function: Function::ArrayAgg, - // args: vec![Expression::TableReference(TableReference::AliasedTable( - // row_table_alias.clone(), - // ))], - // }, - // ); - - // json_items.insert( - // "aggregates".to_string(), - // Expression::JoinExpressions(vec![ - // Expression::FunctionCall { - // function: Function::ArrayAgg, - // args: vec![Expression::TableReference(TableReference::AliasedTable( - // aggregate_table_alias.clone(), - // ))], - // }, - // // ASSUMPTION (PY): This is a hack to get a single object for aggreagtes since cross join results in same aggregates for all rows - // Expression::SafeOffSet { offset: 0 }, - // ]), - // ); - - // let row = vec![( - // output_column_alias, - // (Expression::JsonBuildObject(json_items)), - // )]; - - // let mut final_select = simple_select(row); - - // let select_star = star_select(From::Select { - // alias: row_inner_table_alias_, - // select: Box::new(row_select), - // }); - - // let select_star2 = star_select(From::Select { - // alias: aggregate_table_alias.clone(), - // select: Box::new(aggregate_select), - // }); - - // final_select.from = Some(From::Select { - // alias: row_table_alias, - // select: Box::new(select_star), - // }); - - // final_select.joins = vec![Join::CrossJoin(CrossJoin { - // select: Box::new(select_star2), - // alias: aggregate_table_alias, - // })]; - - // final_select - // } + SelectSet::Rows(row_select) => match returns_field { + ReturnsFields::FieldsWereRequested => row_select, + ReturnsFields::NoFieldsWereRequested => { + todo!("not supported yet") + } + }, } } diff --git a/crates/query-engine/translation/src/translation/helpers.rs b/crates/query-engine/translation/src/translation/helpers.rs index 926548e..216740f 100644 --- a/crates/query-engine/translation/src/translation/helpers.rs +++ b/crates/query-engine/translation/src/translation/helpers.rs @@ -99,12 +99,8 @@ impl<'request> Env<'request> { } /// Create a new Env by supplying the metadata and relationships. - pub fn new( - metadata: &'request metadata::Metadata, - ) -> Self { - Env { - metadata, - } + pub fn new(metadata: &'request metadata::Metadata) -> Self { + Env { metadata } } /// Lookup a metadata object that may contain fields. This may be any of Tables, Native @@ -172,7 +168,7 @@ impl<'request> Env<'request> { /// Lookup type representation of a type. pub fn lookup_type_representation( &self, - scalar_type: &models::ScalarTypeName + scalar_type: &models::ScalarTypeName, ) -> Option<&metadata::TypeRepresentation> { self.metadata .scalar_types diff --git a/crates/query-engine/translation/src/translation/query/fields.rs b/crates/query-engine/translation/src/translation/query/fields.rs index 844f54b..60d1f5a 100644 --- a/crates/query-engine/translation/src/translation/query/fields.rs +++ b/crates/query-engine/translation/src/translation/query/fields.rs @@ -49,7 +49,7 @@ pub(crate) fn translate_fields( }) .collect::, Error>>()?; - let mut select = sql::helpers::simple_select(columns); + let mut select = sql::helpers::simple_select(columns); select.from = Some(from); diff --git a/crates/query-engine/translation/src/translation/query/filtering.rs b/crates/query-engine/translation/src/translation/query/filtering.rs index 1fb8b89..bab72b8 100644 --- a/crates/query-engine/translation/src/translation/query/filtering.rs +++ b/crates/query-engine/translation/src/translation/query/filtering.rs @@ -309,116 +309,116 @@ pub fn translate_expression_with_joins( // let mut joins = vec![]; // let RootAndCurrentTables { current_table, .. } = root_and_current_tables; - // let final_ref = path.iter().try_fold( - // current_table.clone(), - // |current_table_ref, - // models::PathElement { - // relationship, - // predicate, - // arguments, - // }| { - // // // get the relationship table - // // let relationship_name = &relationship; - // // let relationship = env.lookup_relationship(relationship_name)?; - - // // new alias for the target table - // // let target_table_alias: sql::ast::TableAlias = - // // state.make_boolean_expression_table_alias(relationship.target_collection.as_str()); - - // // let arguments = relationships::make_relationship_arguments( - // // relationships::MakeRelationshipArguments { - // // caller_arguments: arguments.clone(), - // // relationship_arguments: relationship.arguments.clone(), - // // }, - // // )?; - - // // // create a from clause and get a reference of inner query. - // // let (table, from_clause) = root::make_from_clause_and_reference( - // // &relationship.target_collection, - // // &arguments, - // // env, - // // state, - // // Some(target_table_alias.clone()), - // // )?; - - // // // build a SELECT querying this table with the relevant predicate. - // let mut select = sql::helpers::simple_select(vec![]); - // // select.from = Some(from_clause); - - // select.select_list = sql::ast::SelectList::SelectStar; - - // let new_root_and_current_tables = RootAndCurrentTables { - // root_table: root_and_current_tables.root_table.clone(), - // current_table: TableNameAndReference { - // reference: table.reference.clone(), - // name: table.name.clone(), - // }, - // }; - // // relationship-specfic filter - // let (rel_cond, rel_joins) = match predicate { - // None => (sql::helpers::true_expr(), vec![]), - // Some(predicate) => translate_expression_with_joins( - // env, - // state, - // &new_root_and_current_tables, - // predicate, - // )?, - // }; - - // // relationship where clause - // let cond = relationships::translate_column_mapping( - // env, - // ¤t_table_ref, - // &table.reference, - // rel_cond, - // relationship, - // )?; - - // select.where_ = sql::ast::Where(cond); - - // select.joins = rel_joins; - - // joins.push(sql::ast::Join::InnerJoin(sql::ast::InnerJoin { - // select: Box::new(select), - // alias: target_table_alias, - // })); - - // Ok(new_root_and_current_tables.current_table) - // }, - // )?; - - // let mut joins: VecDeque<_> = joins.into(); - // match joins.pop_front() { - // None => Ok((final_ref, vec![])), - - // // If we are fetching a nested column (we have joins), we wrap them in a select that fetches - // // columns from the last table in the chain. - // Some(first) => { - // let mut outer_select = sql::helpers::simple_select(vec![]); - // outer_select.select_list = sql::ast::SelectList::SelectStarFrom(final_ref.reference); - // let (select, alias) = first.get_select_and_alias(); - // outer_select.from = Some(sql::ast::From::Select { select, alias }); - // outer_select.joins = joins.into(); - - // let alias = state.make_boolean_expression_table_alias(final_ref.name.as_str()); - // let reference = sql::ast::TableReference::AliasedTable(alias.clone()); - - // Ok(( - // TableNameAndReference { - // reference, - // name: final_ref.name.clone(), - // }, - // // create a join from the select. - // // We use a full outer join so even if one of the sides does not contain rows, - // // We can still select values. - // // See a more elaborated explanation: https://github.com/hasura/ndc-postgres/pull/463#discussion_r1601884534 - // vec![sql::ast::Join::FullOuterJoin(sql::ast::FullOuterJoin { - // select: Box::new(outer_select), - // alias, - // })], - // )) - // } - // } +// let final_ref = path.iter().try_fold( +// current_table.clone(), +// |current_table_ref, +// models::PathElement { +// relationship, +// predicate, +// arguments, +// }| { +// // // get the relationship table +// // let relationship_name = &relationship; +// // let relationship = env.lookup_relationship(relationship_name)?; + +// // new alias for the target table +// // let target_table_alias: sql::ast::TableAlias = +// // state.make_boolean_expression_table_alias(relationship.target_collection.as_str()); + +// // let arguments = relationships::make_relationship_arguments( +// // relationships::MakeRelationshipArguments { +// // caller_arguments: arguments.clone(), +// // relationship_arguments: relationship.arguments.clone(), +// // }, +// // )?; + +// // // create a from clause and get a reference of inner query. +// // let (table, from_clause) = root::make_from_clause_and_reference( +// // &relationship.target_collection, +// // &arguments, +// // env, +// // state, +// // Some(target_table_alias.clone()), +// // )?; + +// // // build a SELECT querying this table with the relevant predicate. +// let mut select = sql::helpers::simple_select(vec![]); +// // select.from = Some(from_clause); + +// select.select_list = sql::ast::SelectList::SelectStar; + +// let new_root_and_current_tables = RootAndCurrentTables { +// root_table: root_and_current_tables.root_table.clone(), +// current_table: TableNameAndReference { +// reference: table.reference.clone(), +// name: table.name.clone(), +// }, +// }; +// // relationship-specfic filter +// let (rel_cond, rel_joins) = match predicate { +// None => (sql::helpers::true_expr(), vec![]), +// Some(predicate) => translate_expression_with_joins( +// env, +// state, +// &new_root_and_current_tables, +// predicate, +// )?, +// }; + +// // relationship where clause +// let cond = relationships::translate_column_mapping( +// env, +// ¤t_table_ref, +// &table.reference, +// rel_cond, +// relationship, +// )?; + +// select.where_ = sql::ast::Where(cond); + +// select.joins = rel_joins; + +// joins.push(sql::ast::Join::InnerJoin(sql::ast::InnerJoin { +// select: Box::new(select), +// alias: target_table_alias, +// })); + +// Ok(new_root_and_current_tables.current_table) +// }, +// )?; + +// let mut joins: VecDeque<_> = joins.into(); +// match joins.pop_front() { +// None => Ok((final_ref, vec![])), + +// // If we are fetching a nested column (we have joins), we wrap them in a select that fetches +// // columns from the last table in the chain. +// Some(first) => { +// let mut outer_select = sql::helpers::simple_select(vec![]); +// outer_select.select_list = sql::ast::SelectList::SelectStarFrom(final_ref.reference); +// let (select, alias) = first.get_select_and_alias(); +// outer_select.from = Some(sql::ast::From::Select { select, alias }); +// outer_select.joins = joins.into(); + +// let alias = state.make_boolean_expression_table_alias(final_ref.name.as_str()); +// let reference = sql::ast::TableReference::AliasedTable(alias.clone()); + +// Ok(( +// TableNameAndReference { +// reference, +// name: final_ref.name.clone(), +// }, +// // create a join from the select. +// // We use a full outer join so even if one of the sides does not contain rows, +// // We can still select values. +// // See a more elaborated explanation: https://github.com/hasura/ndc-postgres/pull/463#discussion_r1601884534 +// vec![sql::ast::Join::FullOuterJoin(sql::ast::FullOuterJoin { +// select: Box::new(outer_select), +// alias, +// })], +// )) +// } +// } // } /// translate a comparison target. @@ -491,7 +491,7 @@ fn translate_comparison_value( values::translate_json_value(env, state, json_value, typ)?, vec![], )), - models::ComparisonValue::Variable { name: _ } => todo!("Variables are not supported") + models::ComparisonValue::Variable { name: _ } => todo!("Variables are not supported"), } } @@ -510,7 +510,6 @@ pub fn translate_exists_in_collection( collection, arguments: _, } => { - // create a from clause and get a reference of inner query. let (table, from_clause) = root::make_from_clause_and_reference(&collection, None, env, state, None)?; @@ -588,7 +587,6 @@ fn get_comparison_target_type( path, field_path, } => { - let mut field_path = match field_path { None => VecDeque::new(), Some(field_path) => field_path.iter().collect(), diff --git a/crates/query-engine/translation/src/translation/query/mod.rs b/crates/query-engine/translation/src/translation/query/mod.rs index 0a8d256..9bcd3fd 100644 --- a/crates/query-engine/translation/src/translation/query/mod.rs +++ b/crates/query-engine/translation/src/translation/query/mod.rs @@ -29,15 +29,15 @@ pub fn translate( ); let collection_string = query_request.collection.as_str(); - let collection = if collection_string.contains(":") { - let split: Vec<&str> = collection_string.split(":").collect(); + let collection = if collection_string.contains(':') { + let split: Vec<&str> = collection_string.split(':').collect(); if split.len() != 2 { return Err(Error::InvalidCollectionName(collection_string.to_string())); }; let collection_name = models::CollectionName::new(split[0].into()); let gsi_name = split[1]; (collection_name, Some(sql::ast::Gsi(gsi_name.to_string()))) - // coll_name = + // coll_name = } else { (models::CollectionName::new(collection_string.into()), None) }; diff --git a/crates/query-engine/translation/src/translation/query/root.rs b/crates/query-engine/translation/src/translation/query/root.rs index 72b694c..ffb6eb2 100644 --- a/crates/query-engine/translation/src/translation/query/root.rs +++ b/crates/query-engine/translation/src/translation/query/root.rs @@ -34,21 +34,12 @@ pub fn translate_query( // translate_aggregate_select(env, state, make_from, join_predicate, query_request)?; // Create a structure describing the selection set - only rows, only aggregates, or both. - let select_set = match (&returns_field, row_select) { - // // Only rows or Neither (This is valid. Returns empty objects). - (_, rows) => (query_request.limit, returns_field, sql::helpers::SelectSet::Rows(rows)), // no fields selected. - // ( - // (ReturnsFields::NoFieldsWereRequested, rows), - // None - // ) => { - // (ReturnsFields::NoFieldsWereRequested, sql::helpers::SelectSet::Rows(rows)) - // } - // (ReturnsFields::NoFieldsWereRequested, None) => { - // return Err(Error::QueryError( - // "No fields or aggregates were requested in the query.".to_string(), - // )); - // } - }; + let (_, rows) = (&returns_field, row_select); + let select_set = ( + query_request.limit, + returns_field, + sql::helpers::SelectSet::Rows(rows), + ); Ok(select_set) } @@ -76,13 +67,9 @@ fn translate_rows_select( }; let mut fields_select = match returns_fields { - ReturnsFields::FieldsWereRequested => fields::translate_fields( - env, - state, - fields, - ¤t_table, - from_clause, - )?, + ReturnsFields::FieldsWereRequested => { + fields::translate_fields(env, state, fields, ¤t_table, from_clause)? + } ReturnsFields::NoFieldsWereRequested => { let select_1 = sql::ast::SelectList::Select1; @@ -229,9 +216,11 @@ fn make_reference_and_from_clause( make_from: &MakeFrom, ) -> Result<(TableNameAndReference, sql::ast::From), Error> { match make_from { - MakeFrom::Collection { name, gsi, arguments: _ } => { - make_from_clause_and_reference(name, gsi.clone(), env, state, None) - } + MakeFrom::Collection { + name, + gsi, + arguments: _, + } => make_from_clause_and_reference(name, gsi.clone(), env, state, None), MakeFrom::TableReference { name, reference } => { let table_alias = state.make_table_alias(name.to_string()); let from_clause = sql::ast::From::Table { diff --git a/crates/query-engine/translation/src/translation/query/sorting.rs b/crates/query-engine/translation/src/translation/query/sorting.rs index 484d883..945fab9 100644 --- a/crates/query-engine/translation/src/translation/query/sorting.rs +++ b/crates/query-engine/translation/src/translation/query/sorting.rs @@ -95,9 +95,7 @@ struct Column(models::FieldName); #[derive(Debug)] enum Aggregate { CountStarAggregate, - SingleColumnAggregate { - column: models::FieldName, - }, + SingleColumnAggregate { column: models::FieldName }, } impl OrderByElementGroup<'_> { diff --git a/crates/query-engine/translation/src/translation/query/values.rs b/crates/query-engine/translation/src/translation/query/values.rs index c01c7c0..868d953 100644 --- a/crates/query-engine/translation/src/translation/query/values.rs +++ b/crates/query-engine/translation/src/translation/query/values.rs @@ -26,8 +26,7 @@ pub fn translate_json_value( .ok_or(Error::UnableToDeserializeNumberAsF64(n.clone()))?; Ok(Expression::Value(Value::Float8(lit))) } - (serde_json::Value::String(str), _) => - Ok(Expression::Value(Value::String(str.clone()))), + (serde_json::Value::String(str), _) => Ok(Expression::Value(Value::String(str.clone()))), // Ok(Expression::Cast { // expression: Box::new(Expression::Value(Value::String(str.clone()))), // r#type: type_to_ast_scalar_type(env, r#type)?, @@ -76,9 +75,9 @@ fn type_to_ast_scalar_type_name( query_engine_metadata::metadata::Type::ScalarType(t) => { let scalar_type: &query_engine_metadata::metadata::ScalarType = env.lookup_scalar_type(t)?; - Ok(sql::ast::ScalarTypeName::Unqualified( - scalar_type.type_name.to_string(), - )) + Ok(sql::ast::ScalarTypeName::Unqualified( + scalar_type.type_name.to_string(), + )) // match scalar_type.schema_name.clone() { // None => Ok(sql::ast::ScalarTypeName::Unqualified( // scalar_type.type_name.to_string(),