diff --git a/Cargo.toml b/Cargo.toml index a4a24e3..419a097 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,7 +54,7 @@ nonempty = "0.10" percent-encoding = "2" prometheus = "0.13" ref-cast = "1" -reqwest = "0.11" +reqwest = { version = "0.11", default-features = false } schemars = "0.8" serde = "1" serde_derive = "^1.0" diff --git a/crates/configuration/src/to_runtime_configuration.rs b/crates/configuration/src/to_runtime_configuration.rs index 9e918e6..b28df85 100644 --- a/crates/configuration/src/to_runtime_configuration.rs +++ b/crates/configuration/src/to_runtime_configuration.rs @@ -172,7 +172,6 @@ fn convert_nullable(nullable: &metadata::Nullable) -> query_engine_metadata::met fn convert_type(r#type: metadata::Type) -> query_engine_metadata::metadata::Type { match r#type { metadata::Type::ScalarType(t) => query_engine_metadata::metadata::Type::ScalarType(t), - metadata::Type::CompositeType(t) => query_engine_metadata::metadata::Type::CompositeType(t), metadata::Type::ArrayType(t) => { query_engine_metadata::metadata::Type::ArrayType(Box::new(convert_type(*t))) } diff --git a/crates/connectors/ndc-bigquery/Cargo.toml b/crates/connectors/ndc-bigquery/Cargo.toml index 0d7b870..8f970b3 100644 --- a/crates/connectors/ndc-bigquery/Cargo.toml +++ b/crates/connectors/ndc-bigquery/Cargo.toml @@ -47,6 +47,6 @@ axum-test-helper = { workspace = true } insta = { workspace = true, features = ["json"] } env_logger = { workspace = true } hyper = { workspace = true, features = ["tcp"] } -reqwest = { workspace = true, default-features = false, features = ["rustls-tls"] } +reqwest = { workspace = true, features = ["rustls-tls"] } similar-asserts = { workspace = true } url = { workspace = true } diff --git a/crates/connectors/ndc-bigquery/src/schema.rs b/crates/connectors/ndc-bigquery/src/schema.rs index ccdf374..72b7278 100644 --- a/crates/connectors/ndc-bigquery/src/schema.rs +++ b/crates/connectors/ndc-bigquery/src/schema.rs @@ -250,6 +250,5 @@ pub fn type_to_type(typ: &metadata::Type) -> models::Type { metadata::Type::ScalarType(scalar_type) => models::Type::Named { name: scalar_type.as_str().into(), }, - metadata::Type::CompositeType(t) => models::Type::Named { name: t.clone() }, } } diff --git a/crates/query-engine/metadata/src/metadata/database.rs b/crates/query-engine/metadata/src/metadata/database.rs index d29df38..fdc9982 100644 --- a/crates/query-engine/metadata/src/metadata/database.rs +++ b/crates/query-engine/metadata/src/metadata/database.rs @@ -16,7 +16,6 @@ pub struct ScalarTypeTypeName(pub String); #[serde(rename_all = "camelCase")] pub enum Type { ScalarType(models::ScalarTypeName), - CompositeType(models::TypeName), ArrayType(Box), } @@ -44,27 +43,6 @@ pub struct ScalarType { pub type_representation: Option, } -/// Map of all known composite types. -#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)] -#[serde(rename_all = "camelCase")] -pub struct CompositeTypes(pub BTreeMap); - -impl CompositeTypes { - pub fn empty() -> Self { - CompositeTypes(BTreeMap::new()) - } -} - -/// Information about a composite type. These are very similar to tables, but with the crucial -/// difference that composite types do not support constraints (such as NOT NULL). -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)] -pub struct CompositeType { - pub type_name: String, - pub schema_name: Option, - pub fields: BTreeMap, - pub description: Option, -} - /// The complete list of supported binary operators for scalar types. /// Not all of these are supported for every type. #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, JsonSchema)] diff --git a/crates/query-engine/sql/src/sql/ast.rs b/crates/query-engine/sql/src/sql/ast.rs index ca6120a..298e931 100644 --- a/crates/query-engine/sql/src/sql/ast.rs +++ b/crates/query-engine/sql/src/sql/ast.rs @@ -107,8 +107,6 @@ pub enum SelectList { SelectStar, SelectStarFrom(TableReference), Select1, - SelectStarComposite(Expression), - SelectListComposite(Box, Box), } /// A FROM clause diff --git a/crates/query-engine/sql/src/sql/convert.rs b/crates/query-engine/sql/src/sql/convert.rs index 47210d0..8ec469a 100644 --- a/crates/query-engine/sql/src/sql/convert.rs +++ b/crates/query-engine/sql/src/sql/convert.rs @@ -99,19 +99,9 @@ impl SelectList { table_reference.to_sql(sql); sql.append_syntax(".*"); } - SelectList::SelectStarComposite(expr) => { - sql.append_syntax("("); - expr.to_sql(sql); - sql.append_syntax(").*"); - } SelectList::Select1 => { sql.append_syntax("1"); } - SelectList::SelectListComposite(select_list1, select_list2) => { - select_list1.to_sql(sql); - sql.append_syntax(", "); - select_list2.to_sql(sql); - } } } } diff --git a/crates/query-engine/sql/src/sql/helpers.rs b/crates/query-engine/sql/src/sql/helpers.rs index 4fdba33..019179f 100644 --- a/crates/query-engine/sql/src/sql/helpers.rs +++ b/crates/query-engine/sql/src/sql/helpers.rs @@ -79,20 +79,6 @@ pub fn make_column_alias(name: String) -> ColumnAlias { // SELECTs // -/// Build a simple 'SELECT (exp).*' -pub fn select_composite(exp: Expression) -> Select { - Select { - with: empty_with(), - select_list: SelectList::SelectStarComposite(exp), - from: None, - joins: vec![], - where_: Where(empty_where()), - group_by: empty_group_by(), - order_by: empty_order_by(), - limit: empty_limit(), - } -} - /// Build a simple select with a select list and the rest are empty. pub fn simple_select(select_list: Vec<(ColumnAlias, Expression)>) -> Select { Select { diff --git a/crates/query-engine/sql/src/sql/rewrites/constant_folding.rs b/crates/query-engine/sql/src/sql/rewrites/constant_folding.rs index 1413f57..fded019 100644 --- a/crates/query-engine/sql/src/sql/rewrites/constant_folding.rs +++ b/crates/query-engine/sql/src/sql/rewrites/constant_folding.rs @@ -40,18 +40,9 @@ pub fn normalize_select(mut select: Select) -> Select { /// Normalize all expressions in a select list. pub fn normalize_select_list(select_list: SelectList) -> SelectList { match select_list { - SelectList::SelectListComposite(select_list1, select_list2) => { - SelectList::SelectListComposite( - Box::new(normalize_select_list(*select_list1)), - Box::new(normalize_select_list(*select_list2)), - ) - } SelectList::SelectStar => SelectList::SelectStar, SelectList::SelectStarFrom(table) => SelectList::SelectStarFrom(table), SelectList::Select1 => SelectList::Select1, - SelectList::SelectStarComposite(exp) => { - SelectList::SelectStarComposite(normalize_expr(exp)) - } SelectList::SelectList(vec) => SelectList::SelectList( vec.into_iter() .map(|(alias, expr)| (alias, normalize_expr(expr))) diff --git a/crates/query-engine/translation/src/translation/helpers.rs b/crates/query-engine/translation/src/translation/helpers.rs index c64a94c..da81058 100644 --- a/crates/query-engine/translation/src/translation/helpers.rs +++ b/crates/query-engine/translation/src/translation/helpers.rs @@ -90,20 +90,6 @@ pub enum CollectionInfo<'env> { }, } -#[derive(Debug)] -/// Metadata information about a composite type. This includes both tables (and views) and -/// dedicated composite types. -pub enum CompositeTypeInfo<'env> { - Table { - name: models::CollectionName, - info: &'env metadata::TableInfo, - }, - CompositeType { - name: models::TypeName, - info: &'env metadata::CompositeType, - }, -} - #[derive(Debug)] /// Metadata information about any object that can have fields pub enum FieldsInfo<'env> { @@ -115,22 +101,6 @@ pub enum FieldsInfo<'env> { name: &'env models::CollectionName, info: &'env metadata::NativeQueryInfo, }, - CompositeType { - name: models::TypeName, - info: &'env metadata::CompositeType, - }, -} - -impl<'a> From<&'a CompositeTypeInfo<'a>> for FieldsInfo<'a> { - fn from(value: &'a CompositeTypeInfo<'a>) -> Self { - match value { - CompositeTypeInfo::Table { name, info } => FieldsInfo::Table { name, info }, - CompositeTypeInfo::CompositeType { name, info } => FieldsInfo::CompositeType { - name: name.clone(), - info, - }, - } - } } impl<'a> From<&'a CollectionInfo<'a>> for FieldsInfo<'a> { @@ -233,41 +203,6 @@ impl<'request> Env<'request> { info.ok_or(Error::CollectionNotFound(type_name.as_str().into())) } - /// Lookup a metadata object which can be described by a Composite Type. This can be any of - /// Tables and Composite Types themselves. - /// - /// This does not include Native Queries, since the fields of a Native Query is an ad-hoc - /// construct of the NDC, and not a named type that Postgres knows about. - /// - /// Therefore, being a `CompositeTypeInfo` is a stronger property than being a `FieldsInfo`. - /// - /// This is used in the elaboration of nested fields that are not fully specified, and in the - /// translation of input values and variables of composite type. - pub fn lookup_composite_type( - &self, - type_name: &'request models::TypeName, - ) -> Result, Error> { - let info = - self.metadata - .tables - .0 - .get(type_name.as_str()) - .map(|t| CompositeTypeInfo::Table { - name: type_name.as_str().into(), - info: t, - }); - // .or_else(|| { - // self.metadata.composite_types.0.get(type_name).map(|t| { - // CompositeTypeInfo::CompositeType { - // name: t.type_name.as_str().into(), - // info: t, - // } - // }) - // }); - - info.ok_or(Error::CollectionNotFound(type_name.as_str().into())) - } - /// Lookup a collection's information in the metadata. pub fn lookup_collection( &self, @@ -411,16 +346,6 @@ impl FieldsInfo<'_> { .ok_or_else(|| { Error::ColumnNotFoundInCollection(column_name.clone(), name.as_str().into()) }), - FieldsInfo::CompositeType { name, info } => info - .fields - .get(column_name) - .map(|field_info| ColumnInfo { - name: sql::ast::ColumnName(field_info.field_name.clone()), - r#type: field_info.r#type.clone(), - }) - .ok_or_else(|| { - Error::ColumnNotFoundInCollection(column_name.clone(), name.as_str().into()) - }), } } } @@ -432,39 +357,6 @@ impl CollectionInfo<'_> { } } -impl CompositeTypeInfo<'_> { - pub fn type_name(&self) -> &str { - match self { - CompositeTypeInfo::Table { name, .. } => name.as_str(), - CompositeTypeInfo::CompositeType { name, .. } => name.as_str(), - } - } - - pub fn schema_name(&self) -> Option<&String> { - match self { - CompositeTypeInfo::Table { info, .. } => Some(&info.schema_name), - CompositeTypeInfo::CompositeType { info, .. } => info.schema_name.as_ref(), - } - } - - /// Fetch all the field names (external, internal) of a composite type. - pub fn fields(&self) -> Vec<(String, &String)> { - match self { - CompositeTypeInfo::CompositeType { name: _, info } => info - .fields - .iter() - .map(|(name, field)| (name.clone().into(), &field.field_name)) - .collect::>(), - - CompositeTypeInfo::Table { name: _, info } => info - .columns - .iter() - .map(|(name, column)| (name.clone().into(), &column.name)) - .collect::>(), - } - } -} - impl Default for State { fn default() -> State { State { diff --git a/crates/query-engine/translation/src/translation/query/fields.rs b/crates/query-engine/translation/src/translation/query/fields.rs index c6413fa..3f06d07 100644 --- a/crates/query-engine/translation/src/translation/query/fields.rs +++ b/crates/query-engine/translation/src/translation/query/fields.rs @@ -1,8 +1,5 @@ //! Handle 'rows' and 'aggregates' translation. -use std::collections::BTreeMap; - -use indexmap::indexmap; use indexmap::IndexMap; use ndc_models as models; @@ -11,31 +8,10 @@ use super::relationships; use crate::translation::error::Error; use crate::translation::error::UnsupportedCapabilities; use crate::translation::helpers::FieldsInfo; -use crate::translation::helpers::{ColumnInfo, Env, State, TableNameAndReference}; +use crate::translation::helpers::{Env, State, TableNameAndReference}; use query_engine_metadata::metadata::{Type, TypeRepresentation}; use query_engine_sql::sql; -/// This type collects the salient parts of joined-on subqueries that compute the result of a -/// nested field selection. -struct JoinNestedFieldInfo { - select: sql::ast::Select, - alias: sql::ast::TableAlias, -} - -/// Translate a list of nested field joins into lateral joins. -fn translate_nested_field_joins(joins: Vec) -> Vec { - joins - .into_iter() - .map(|JoinNestedFieldInfo { select, alias }| { - sql::ast::Join::LeftOuterJoin(sql::ast::LeftOuterJoin { - select: Box::new(select), - alias, - on: sql::ast::Expression::Value(sql::ast::Value::Bool(true)), // TODO(PY): get correct expression - }) - }) - .collect() -} - /// Translate the field-selection of a query to SQL. /// Because field selection may be nested this function is mutually recursive with /// 'translate_nested_field'. @@ -50,9 +26,6 @@ pub(crate) fn translate_fields( // find the table according to the metadata. let fields_info = env.lookup_fields_info(¤t_table.name)?; - // Each nested field is computed in one joined-on sub query. - let mut nested_field_joins: Vec = vec![]; - let columns: Vec<(sql::ast::ColumnAlias, sql::ast::Expression)> = fields .into_iter() .map(|(alias, field)| match field { @@ -62,37 +35,11 @@ pub(crate) fn translate_fields( arguments, } if arguments.is_empty() => unpack_and_wrap_fields( env, - state, current_table, - join_relationship_fields, &column, sql::helpers::make_column_alias(alias.to_string()), &fields_info, - &mut nested_field_joins, ), - models::Field::Column { - column, - fields: Some(nested_field), - arguments, - } if arguments.is_empty() => { - let column_info = fields_info.lookup_column(&column)?; - let (nested_field_join, nested_column_reference) = translate_nested_field( - env, - state, - current_table, - &column, - &column_info, - nested_field, - join_relationship_fields, - )?; - - nested_field_joins.push(nested_field_join); - - Ok(( - sql::helpers::make_column_alias(alias.to_string()), - sql::ast::Expression::ColumnReference(nested_column_reference), - )) - } models::Field::Column { column: _, fields: _, @@ -130,10 +77,6 @@ pub(crate) fn translate_fields( select.from = Some(from); - select - .joins - .extend(translate_nested_field_joins(nested_field_joins)); - // let select_final = match returns_field { // ReturnsFields::FieldsWereRequested => { // (select) @@ -159,220 +102,17 @@ pub(crate) fn translate_fields( Ok(select) } -/// Translate a nested field selection. -/// -/// Nested fields are different from relationships in that the value of a nested field is already -/// available on the current table as a column of composite type. -/// -/// A nested field selection translates to a JOIN clause in the form of: -/// -/// LEFT OUTER JOIN LATERAL ( -/// SELECT -/// AS "collected" -/// FROM -/// ( -/// < select of translate_fields(fields, nested_field_binding_alias, ... ) -/// which includes joins from recursive calls> -/// FROM -/// ( -/// SELECT -/// ().* -/// ) AS ON ('true') -/// ) AS -/// ) AS ON ('true') -/// -/// Alongside the column reference `."collected"` -/// -/// When the nested field is an object: -/// - is `row_to_json()` -/// - is `.` -/// -/// When the nested field is an array: -/// - is `json_agg(row_to_json())` -/// - is `unnest(.)` -/// -/// # Arguments -/// -/// * `current_table` - the table reference the column lives on -/// * `current_column` - the column to extract nested fields from -fn translate_nested_field( - env: &Env, - state: &mut State, - current_table: &TableNameAndReference, - current_column_name: &models::FieldName, - current_column: &ColumnInfo, - field: models::NestedField, - join_relationship_fields: &mut Vec, -) -> Result<(JoinNestedFieldInfo, sql::ast::ColumnReference), Error> { - let nested_field_column_collect_alias = - sql::helpers::make_column_alias("collected".to_string()); - let nested_fields_alias = state.make_table_alias("nested_fields".to_string()); - - // How we project and collect nested fields depend on whether the nested value is an object or - // an array. - let (collect_expression, field_binding_expression, nested_field_type_name, fields) = match field - { - models::NestedField::Object(models::NestedObject { fields }) => { - // SELECT row_to_json(nested_fields.*) - let collect_expression = sql::ast::Expression::RowToJson( - sql::ast::TableReference::AliasedTable(nested_fields_alias.clone()), - ); - - // In order to bring the nested fields into scope for sub selections - // we need to unpack them as selected columns of a bound relation. - // - // This becomes the SQL - // ``` - // SELECT - // ("%0_"."").* - // ``` - let field_binding_expression = - sql::ast::Expression::ColumnReference(sql::ast::ColumnReference::AliasedColumn { - table: current_table.reference.clone(), - column: sql::helpers::make_column_alias(current_column.name.0.clone()), - }); - - let nested_field_type_name = match ¤t_column.r#type { - Type::CompositeType(type_name) => Ok(type_name.clone()), - t => Err(Error::NestedFieldNotOfCompositeType { - field_name: current_column_name.clone(), - actual_type: t.clone(), - }), - }?; - Ok(( - collect_expression, - field_binding_expression, - nested_field_type_name, - fields, - )) - } - models::NestedField::Array(models::NestedArray { fields }) => { - match *fields { - models::NestedField::Array(models::NestedArray { .. }) => { - Err(Error::NestedArraysNotSupported { - field_name: current_column_name.clone(), - }) - } - models::NestedField::Object(models::NestedObject { fields }) => { - // SELECT json_agg(row_to_json(nested_fields.*)) - let collect_expression = sql::ast::Expression::FunctionCall { - function: sql::ast::Function::JsonAgg, - args: vec![sql::ast::Expression::RowToJson( - sql::ast::TableReference::AliasedTable(nested_fields_alias.clone()), - )], - }; - - // In order to bring the nested fields into scope for sub selections - // we need to unpack them as selected columns of a bound relation. - // - // This becomes the SQL - // ``` - // SELECT - // (unnest("%0_"."")).* - // ``` - let field_binding_expression = sql::ast::Expression::FunctionCall { - function: sql::ast::Function::Unnest, - args: vec![sql::ast::Expression::ColumnReference( - sql::ast::ColumnReference::AliasedColumn { - table: current_table.reference.clone(), - column: sql::helpers::make_column_alias( - current_column.name.0.clone(), - ), - }, - )], - }; - - let nested_field_type_name = match ¤t_column.r#type { - Type::ArrayType(element_type) => match **element_type { - Type::CompositeType(ref type_name) => Ok(type_name.clone()), - ref t => Err(Error::NestedFieldNotOfCompositeType { - field_name: current_column_name.clone(), - actual_type: t.clone(), - }), - }, - t => Err(Error::NestedFieldNotOfArrayType { - field_name: current_column_name.clone(), - actual_type: t.clone(), - }), - }?; - Ok(( - collect_expression, - field_binding_expression, - nested_field_type_name, - fields, - )) - } - } - } - }?; - - // The FROM-clause to use for the next layer of fields returned by `translate_fields` below, - // which brings each nested field into scope as separate columns in a sub query. - let nested_field_binding_alias = state.make_table_alias("nested_field_binding".to_string()); - let nested_field_from = sql::ast::From::Select { - select: Box::new(sql::helpers::select_composite(field_binding_expression)), - alias: nested_field_binding_alias.clone(), - }; - - // The recursive call to the next layer of fields - let nested_field_table_reference = TableNameAndReference { - name: nested_field_type_name.as_str().into(), - reference: sql::ast::TableReference::AliasedTable(nested_field_binding_alias), - }; - - let fields_select = translate_fields( - env, - state, - fields, - &nested_field_table_reference, - nested_field_from, - join_relationship_fields, - )?; - - // The top-level select statement which collects the fields at the next level of nesting into a - // single json object. - let mut collect_select = sql::helpers::simple_select(vec![( - nested_field_column_collect_alias.clone(), - collect_expression, - )]); - - collect_select.from = Some(sql::ast::From::Select { - select: Box::new(fields_select), - alias: nested_fields_alias, - }); - - // The JOIN clause plus alias that our caller will use to query and select the composite field - // json value this function produced. - let nested_field_table_collect_alias = - state.make_table_alias("nested_fields_collect".to_string()); - - let nested_field_join = JoinNestedFieldInfo { - select: collect_select, - alias: nested_field_table_collect_alias.clone(), - }; - - Ok(( - nested_field_join, - sql::ast::ColumnReference::AliasedColumn { - table: sql::ast::TableReference::AliasedTable(nested_field_table_collect_alias), - column: nested_field_column_collect_alias, - }, - )) -} - #[allow(clippy::too_many_arguments)] /// In order to return the expected type representation for each column, /// we need to wrap columns in type representation cast, and unpack composite types /// so we can wrap them. fn unpack_and_wrap_fields( env: &Env, - state: &mut State, current_table: &TableNameAndReference, - join_relationship_fields: &mut Vec, + column: &models::FieldName, alias: sql::ast::ColumnAlias, fields_info: &FieldsInfo<'_>, - nested_field_joins: &mut Vec, ) -> Result<(sql::ast::ColumnAlias, sql::ast::Expression), Error> { let column_info = fields_info.lookup_column(column)?; @@ -392,59 +132,10 @@ fn unpack_and_wrap_fields( wrap_in_type_representation(expression, column_type_representation), )) } - // Composite types are a more involved case because we cannot just "cast" - // a composite type, we need to unpack it and cast the individual fields. - // In this case, we unpack a single composite column selection to an explicit - // selection of all fields. - Type::CompositeType(ref composite_type) => { - // build a nested field selection of all fields. - let nested_field = unpack_composite_type(env, composite_type)?; - - // translate this as if it is a nested field selection. - let (nested_field_join, nested_column_reference) = translate_nested_field( - env, - state, - current_table, - column, - &column_info, - nested_field, - join_relationship_fields, - )?; - - nested_field_joins.push(nested_field_join); - - Ok(( - alias, - sql::ast::Expression::ColumnReference(nested_column_reference), - )) - } Type::ArrayType(ref type_boxed) => match **type_boxed { Type::ArrayType(_) => Err(Error::NestedArraysNotSupported { field_name: column.clone(), }), - Type::CompositeType(ref composite_type) => { - // build a nested field selection of all fields. - let nested_field = models::NestedField::Array(models::NestedArray { - fields: Box::new(unpack_composite_type(env, composite_type)?), - }); - - let (nested_field_join, nested_column_reference) = translate_nested_field( - env, - state, - current_table, - column, - &column_info, - nested_field, - join_relationship_fields, - )?; - - nested_field_joins.push(nested_field_join); - - Ok(( - alias, - sql::ast::Expression::ColumnReference(nested_column_reference), - )) - } Type::ScalarType(ref scalar_type) => { let inner_column_type_representation = env.lookup_type_representation(scalar_type); let (alias, expression) = sql::helpers::make_column( @@ -539,25 +230,3 @@ fn get_type_representation_cast_type( | TypeRepresentation::Enum(_) => None, } } - -/// Create an explicit NestedField that selects all fields (1 level) of a composite type. -fn unpack_composite_type( - env: &Env, - composite_type: &models::TypeName, -) -> Result { - Ok(models::NestedField::Object({ - let composite_type = env.lookup_composite_type(composite_type)?; - let mut fields = indexmap!(); - for (result_name, field_name) in composite_type.fields() { - fields.insert( - result_name.into(), - models::Field::Column { - column: field_name.as_str().into(), - fields: None, - arguments: BTreeMap::new(), - }, - ); - } - models::NestedObject { fields } - })) -} diff --git a/crates/query-engine/translation/src/translation/query/filtering.rs b/crates/query-engine/translation/src/translation/query/filtering.rs index d3224bc..4dd60c1 100644 --- a/crates/query-engine/translation/src/translation/query/filtering.rs +++ b/crates/query-engine/translation/src/translation/query/filtering.rs @@ -12,7 +12,7 @@ use super::values; use crate::translation::error::Error; use crate::translation::helpers::wrap_in_field_path; use crate::translation::helpers::{ - ColumnInfo, CompositeTypeInfo, Env, RootAndCurrentTables, State, TableNameAndReference, + ColumnInfo, Env, RootAndCurrentTables, State, TableNameAndReference, }; use query_engine_metadata::metadata::database; use query_engine_sql::sql; @@ -659,7 +659,7 @@ fn get_comparison_target_type( None => VecDeque::new(), Some(field_path) => field_path.iter().collect(), }; - get_column_scalar_type_name(env, &column.r#type, &mut field_path) + get_column_scalar_type_name(&column.r#type, &mut field_path) } models::ComparisonTarget::Column { name, @@ -676,7 +676,7 @@ fn get_comparison_target_type( .lookup_collection(&root_and_current_tables.current_table.name)? .lookup_column(name)?; - get_column_scalar_type_name(env, &column.r#type, &mut field_path) + get_column_scalar_type_name(&column.r#type, &mut field_path) } Some(last) => { let column = env @@ -686,7 +686,7 @@ fn get_comparison_target_type( )? .lookup_column(name)?; - get_column_scalar_type_name(env, &column.r#type, &mut field_path) + get_column_scalar_type_name(&column.r#type, &mut field_path) } } } @@ -696,7 +696,6 @@ fn get_comparison_target_type( /// Extract the scalar type name of a column down their nested field path. /// Will error if path do not lead to a scalar type. fn get_column_scalar_type_name( - env: &Env, typ: &database::Type, field_path: &mut VecDeque<&models::FieldName>, ) -> Result { @@ -713,36 +712,6 @@ fn get_column_scalar_type_name( database::Type::ArrayType(_) => Err(Error::NonScalarTypeUsedInOperator { r#type: typ.clone(), }), - database::Type::CompositeType(composite_type) => match field { - None => Err(Error::NonScalarTypeUsedInOperator { - r#type: database::Type::CompositeType(composite_type.clone()), - }), - // If a composite type has a field, try to extract its type. - Some(field) => { - let composite_type = env.lookup_composite_type(composite_type)?; - match composite_type { - CompositeTypeInfo::CompositeType { info, name } => { - let typ = &info - .fields - .get(field) - .ok_or(Error::ColumnNotFoundInCollection( - field.clone(), - name.as_str().into(), - ))? - .r#type; - get_column_scalar_type_name(env, typ, field_path) - } - CompositeTypeInfo::Table { info, name } => { - let typ = &info - .columns - .get(field) - .ok_or(Error::ColumnNotFoundInCollection((*field).clone(), name))? - .r#type; - get_column_scalar_type_name(env, typ, field_path) - } - } - } - }, } } diff --git a/crates/query-engine/translation/src/translation/query/relationships.rs b/crates/query-engine/translation/src/translation/query/relationships.rs index f465263..e0f97af 100644 --- a/crates/query-engine/translation/src/translation/query/relationships.rs +++ b/crates/query-engine/translation/src/translation/query/relationships.rs @@ -9,6 +9,8 @@ use crate::translation::error::Error; use crate::translation::helpers::{Env, State, TableNameAndReference}; use query_engine_sql::sql; +/// Information about a join we need to perform. +#[derive(Debug)] pub struct JoinFieldInfo { pub table_alias: sql::ast::TableAlias, pub column_alias: sql::ast::ColumnAlias, @@ -25,6 +27,8 @@ pub fn translate_joins( // We got these by processing the fields selection. join_fields: Vec, ) -> Result, Error> { + println!("join_fields: {:#?}", join_fields); + // traverse and build a join. join_fields .into_iter() diff --git a/crates/query-engine/translation/src/translation/query/values.rs b/crates/query-engine/translation/src/translation/query/values.rs index c44b358..e408286 100644 --- a/crates/query-engine/translation/src/translation/query/values.rs +++ b/crates/query-engine/translation/src/translation/query/values.rs @@ -35,11 +35,7 @@ pub fn translate_json_value( sql::ast::Expression::Value(sql::ast::Value::JsonValue(value.clone())); translate_projected_variable(env, state, r#type, value_expression) } - (serde_json::Value::Object(_obj), database::Type::CompositeType(_type_name)) => { - let value_expression = - sql::ast::Expression::Value(sql::ast::Value::JsonValue(value.clone())); - translate_projected_variable(env, state, r#type, value_expression) - } + // If the type is not congruent with the value constructor we simply pass the json value // raw and cast to the specified type. This allows users to consume any json values, // treating them either as actual json or as any type that has a cast from json defined. @@ -95,18 +91,6 @@ fn type_to_ast_scalar_type_name( } } } - query_engine_metadata::metadata::Type::CompositeType(t) => { - let type_info = env.lookup_composite_type(t)?; - let type_name = type_info.type_name().to_string(); - Ok(if let Some(schema_name) = type_info.schema_name() { - sql::ast::ScalarTypeName::Qualified { - type_name, - schema_name: sql::ast::SchemaName(schema_name.to_string()), - } - } else { - sql::ast::ScalarTypeName::Unqualified(type_name) - }) - } } } @@ -151,16 +135,6 @@ pub fn translate_projected_variable( exp: sql::ast::Expression, ) -> Result { let result = match r#type { - database::Type::CompositeType(_type_name) => sql::ast::Expression::FunctionCall { - function: sql::ast::Function::JsonbPopulateRecord, - args: vec![ - sql::ast::Expression::Cast { - expression: Box::new(sql::ast::Expression::Value(sql::ast::Value::Null)), - r#type: type_to_ast_scalar_type(env, r#type)?, - }, - exp, - ], - }, // We translate projection of array types into the following sql: // ``` // ( SELECT diff --git a/crates/query-engine/translation/tests/goldenfiles/select_no_fields/configuration.json b/crates/query-engine/translation/tests/goldenfiles/select_no_fields/configuration.json index 9a8a1e4..26a14f0 100644 --- a/crates/query-engine/translation/tests/goldenfiles/select_no_fields/configuration.json +++ b/crates/query-engine/translation/tests/goldenfiles/select_no_fields/configuration.json @@ -47,4 +47,3 @@ } } } - diff --git a/crates/query-engine/translation/tests/goldenfiles/select_where_string/configuration.json b/crates/query-engine/translation/tests/goldenfiles/select_where_string/configuration.json index 9cb5148..0940d20 100644 --- a/crates/query-engine/translation/tests/goldenfiles/select_where_string/configuration.json +++ b/crates/query-engine/translation/tests/goldenfiles/select_where_string/configuration.json @@ -70,4 +70,3 @@ } } } - diff --git a/crates/query-engine/translation/tests/goldenfiles/select_with_limit/configuration.json b/crates/query-engine/translation/tests/goldenfiles/select_with_limit/configuration.json index 9a8a1e4..26a14f0 100644 --- a/crates/query-engine/translation/tests/goldenfiles/select_with_limit/configuration.json +++ b/crates/query-engine/translation/tests/goldenfiles/select_with_limit/configuration.json @@ -47,4 +47,3 @@ } } } - diff --git a/crates/tests/tests-common/goldenfiles/select_by_pk.json b/crates/tests/tests-common/goldenfiles/select_by_pk.json index dc52696..5ab99c7 100644 --- a/crates/tests/tests-common/goldenfiles/select_by_pk.json +++ b/crates/tests/tests-common/goldenfiles/select_by_pk.json @@ -2,30 +2,30 @@ "collection": "albums", "arguments": {}, "query": { - "fields": { - "Title": { - "type": "column", - "column": "Title" - } - }, - "predicate": { - "type": "and", - "expressions": [ - { - "type": "binary_comparison_operator", - "column": { - "type": "column", - "name": "AlbumId", - "path": [] - }, - "operator": "_eq", - "value": { - "type": "scalar", - "value": 2 - } - } - ] + "fields": { + "Title": { + "type": "column", + "column": "Title" } + }, + "predicate": { + "type": "and", + "expressions": [ + { + "type": "binary_comparison_operator", + "column": { + "type": "column", + "name": "AlbumId", + "path": [] + }, + "operator": "_eq", + "value": { + "type": "scalar", + "value": 2 + } + } + ] + } }, "collection_relationships": {} -} \ No newline at end of file +} diff --git a/crates/tests/tests-common/goldenfiles/select_order_by_no_fields.json b/crates/tests/tests-common/goldenfiles/select_order_by_no_fields.json index 7f8ff3b..53fc1c6 100644 --- a/crates/tests/tests-common/goldenfiles/select_order_by_no_fields.json +++ b/crates/tests/tests-common/goldenfiles/select_order_by_no_fields.json @@ -1,23 +1,22 @@ { - "collection": "albums", - "query": { - "fields": {}, - "limit": 5, - "offset": 1, - "order_by": { - "elements": [ - { - "order_direction": "asc", - "target": { - "type": "column", - "name": "Title", - "path": [] - } + "collection": "albums", + "query": { + "fields": {}, + "limit": 5, + "offset": 1, + "order_by": { + "elements": [ + { + "order_direction": "asc", + "target": { + "type": "column", + "name": "Title", + "path": [] } - ] - } - }, - "arguments": {}, - "collection_relationships": {} - } - \ No newline at end of file + } + ] + } + }, + "arguments": {}, + "collection_relationships": {} +} diff --git a/crates/tests/tests-common/goldenfiles/select_where_and.json b/crates/tests/tests-common/goldenfiles/select_where_and.json index 92d7045..4c8f40d 100644 --- a/crates/tests/tests-common/goldenfiles/select_where_and.json +++ b/crates/tests/tests-common/goldenfiles/select_where_and.json @@ -68,4 +68,4 @@ }, "arguments": {}, "collection_relationships": {} -} \ No newline at end of file +} diff --git a/crates/tests/tests-common/goldenfiles/select_where_or.json b/crates/tests/tests-common/goldenfiles/select_where_or.json index 227cfdb..ce83868 100644 --- a/crates/tests/tests-common/goldenfiles/select_where_or.json +++ b/crates/tests/tests-common/goldenfiles/select_where_or.json @@ -68,4 +68,4 @@ }, "arguments": {}, "collection_relationships": {} -} \ No newline at end of file +}