diff --git a/crates/query-engine/translation/src/translation/error.rs b/crates/query-engine/translation/src/translation/error.rs index 29f2307b..54554d04 100644 --- a/crates/query-engine/translation/src/translation/error.rs +++ b/crates/query-engine/translation/src/translation/error.rs @@ -54,6 +54,10 @@ pub enum Error { field_name: models::FieldName, actual_type: Type, }, + ScopeOutOfRange { + requested: usize, + size: usize, + }, } /// Capabilities we don't currently support. @@ -169,9 +173,6 @@ impl std::fmt::Display for Error { write!(f, "{string}") } Error::UnexpectedStructure(structure) => write!(f, "Unexpected {structure}."), - Error::InternalError(thing) => { - write!(f, "Internal error: {thing}.") - } Error::NonScalarTypeUsedInOperator { r#type } => { write!(f, "Non-scalar-type used in operator: {type:?}") } @@ -199,6 +200,15 @@ impl std::fmt::Display for Error { "Nested field '{field_name}' not of array type. Actual type: {actual_type:?}" ) } + Error::ScopeOutOfRange { requested, size } => { + write!( + f, + "Scope out of range. Got '{requested}' but the scope size is '{size}'." + ) + } + Error::InternalError(thing) => { + write!(f, "Internal error: {thing}.") + } } } } diff --git a/crates/query-engine/translation/src/translation/helpers.rs b/crates/query-engine/translation/src/translation/helpers.rs index f71aaf8c..a8ea997c 100644 --- a/crates/query-engine/translation/src/translation/helpers.rs +++ b/crates/query-engine/translation/src/translation/helpers.rs @@ -51,11 +51,40 @@ pub struct NativeQueryInfo { /// an alias we generate), and what is their name in the metadata (so we can get /// their information such as which columns are available for that table). #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RootAndCurrentTables { - /// The root (top-most) table in the query. - pub root_table: TableSourceAndReference, +pub struct CurrentTableAndScope { /// The current table we are processing. pub current_table: TableSourceAndReference, + /// Named scope of tables ordered from farthest to closest to where we are. + scope: Vec, +} + +impl CurrentTableAndScope { + pub fn new(current_table: TableSourceAndReference) -> Self { + CurrentTableAndScope { + current_table, + scope: vec![], + } + } + pub fn get(&self, i: usize) -> Result<&TableSourceAndReference, Error> { + if i == 0 { + Ok(&self.current_table) + } else { + self.scope + .get(self.scope.len() - i) + .ok_or(Error::ScopeOutOfRange { + requested: i, + size: self.scope.len() + 1, + }) + } + } + pub fn push(&self, table: TableSourceAndReference) -> Self { + let mut scope = self.scope.clone(); + scope.push(self.current_table.clone()); + CurrentTableAndScope { + current_table: table, + scope, + } + } } /// For a table in the query, We'd like to track what is its reference in the query diff --git a/crates/query-engine/translation/src/translation/mutation/v2/delete.rs b/crates/query-engine/translation/src/translation/mutation/v2/delete.rs index b3f98d0a..27a4d506 100644 --- a/crates/query-engine/translation/src/translation/mutation/v2/delete.rs +++ b/crates/query-engine/translation/src/translation/mutation/v2/delete.rs @@ -156,10 +156,7 @@ pub fn translate( let predicate_expression = filtering::translate( env, state, - &helpers::RootAndCurrentTables { - root_table: table_name_and_reference.clone(), - current_table: table_name_and_reference, - }, + &helpers::CurrentTableAndScope::new(table_name_and_reference), &predicate, )?; diff --git a/crates/query-engine/translation/src/translation/mutation/v2/insert.rs b/crates/query-engine/translation/src/translation/mutation/v2/insert.rs index e1c8684c..5a585b33 100644 --- a/crates/query-engine/translation/src/translation/mutation/v2/insert.rs +++ b/crates/query-engine/translation/src/translation/mutation/v2/insert.rs @@ -242,10 +242,7 @@ pub fn translate( let predicate_expression = filtering::translate( env, state, - &helpers::RootAndCurrentTables { - root_table: table_name_and_reference.clone(), - current_table: table_name_and_reference, - }, + &helpers::CurrentTableAndScope::new(table_name_and_reference), &predicate, )?; diff --git a/crates/query-engine/translation/src/translation/mutation/v2/update.rs b/crates/query-engine/translation/src/translation/mutation/v2/update.rs index 8384ddec..0e7193c7 100644 --- a/crates/query-engine/translation/src/translation/mutation/v2/update.rs +++ b/crates/query-engine/translation/src/translation/mutation/v2/update.rs @@ -157,10 +157,7 @@ pub fn translate( }) .collect::, Error>>()?; - let root_and_current_tables = helpers::RootAndCurrentTables { - root_table: table_name_and_reference.clone(), - current_table: table_name_and_reference, - }; + let tables = helpers::CurrentTableAndScope::new(table_name_and_reference); // Build the `pre_constraint` argument boolean expression. let pre_predicate_json = @@ -179,7 +176,7 @@ pub fn translate( })?; let pre_predicate_expression = - filtering::translate(env, state, &root_and_current_tables, &pre_predicate)?; + filtering::translate(env, state, &tables, &pre_predicate)?; // Build the `post_constraint` argument boolean expression. let post_predicate_json = arguments.get(&mutation.post_check.argument_name).ok_or( @@ -195,7 +192,7 @@ pub fn translate( })?; let post_predicate_expression = - filtering::translate(env, state, &root_and_current_tables, &post_predicate)?; + filtering::translate(env, state, &tables, &post_predicate)?; let check_constraint_alias = sql::helpers::make_column_alias(sql::helpers::CHECK_CONSTRAINT_FIELD.to_string()); diff --git a/crates/query-engine/translation/src/translation/query/filtering.rs b/crates/query-engine/translation/src/translation/query/filtering.rs index 1b88c9d5..274c977f 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 super::variables; use crate::translation::error::{Error, UnsupportedCapabilities}; use crate::translation::helpers::{ - wrap_in_field_path, ColumnInfo, CompositeTypeInfo, Env, FieldPath, RootAndCurrentTables, State, + wrap_in_field_path, ColumnInfo, CompositeTypeInfo, CurrentTableAndScope, Env, FieldPath, State, TableSource, TableSourceAndReference, }; use query_engine_metadata::metadata::database; @@ -23,12 +23,12 @@ use std::collections::VecDeque; pub fn translate( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, predicate: &models::Expression, ) -> Result { // Fetch the filter expression and the relevant joins. let (filter_expression, joins) = - translate_expression_with_joins(env, state, root_and_current_tables, predicate)?; + translate_expression_with_joins(env, state, tables, predicate)?; let mut joins = VecDeque::from(joins); let filter = match joins.pop_front() { @@ -53,7 +53,7 @@ pub fn translate( pub fn translate_expression_with_joins( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, predicate: &models::Expression, ) -> Result<(sql::ast::Expression, Vec), Error> { match predicate { @@ -61,9 +61,7 @@ pub fn translate_expression_with_joins( let mut acc_joins = vec![]; let and_exprs = expressions .iter() - .map(|expr| { - translate_expression_with_joins(env, state, root_and_current_tables, expr) - }) + .map(|expr| translate_expression_with_joins(env, state, tables, expr)) .try_fold( sql::ast::Expression::Value(sql::ast::Value::Bool(true)), |acc, expr| { @@ -81,9 +79,7 @@ pub fn translate_expression_with_joins( let mut acc_joins = vec![]; let or_exprs = expressions .iter() - .map(|expr| { - translate_expression_with_joins(env, state, root_and_current_tables, expr) - }) + .map(|expr| translate_expression_with_joins(env, state, tables, expr)) .try_fold( sql::ast::Expression::Value(sql::ast::Value::Bool(false)), |acc, expr| { @@ -98,8 +94,7 @@ pub fn translate_expression_with_joins( Ok((or_exprs, acc_joins)) } models::Expression::Not { expression } => { - let (expr, joins) = - translate_expression_with_joins(env, state, root_and_current_tables, expression)?; + let (expr, joins) = translate_expression_with_joins(env, state, tables, expression)?; Ok((sql::ast::Expression::Not(Box::new(expr)), joins)) } models::Expression::BinaryComparisonOperator { @@ -107,12 +102,11 @@ pub fn translate_expression_with_joins( operator, value, } => { - let left_typ = get_comparison_target_type(env, root_and_current_tables, column)?; + let left_typ = get_comparison_target_type(env, tables, column)?; let op = env.lookup_comparison_operator(&left_typ, operator)?; if op.operator_kind == metadata::OperatorKind::In { let mut joins = vec![]; - let (left, left_joins) = - translate_comparison_target(env, state, root_and_current_tables, column)?; + let (left, left_joins) = translate_comparison_target(env, state, tables, column)?; joins.extend(left_joins); match value { @@ -133,7 +127,7 @@ pub fn translate_expression_with_joins( let (right, right_joins) = translate_comparison_target( env, state, - root_and_current_tables, + tables, &models::ComparisonTarget::Column { name: name.clone(), field_path: field_path.clone(), @@ -164,7 +158,7 @@ pub fn translate_expression_with_joins( let (right, right_joins) = translate_comparison_value( env, state, - root_and_current_tables, + tables, &models::ComparisonValue::Scalar { value: value.clone(), }, @@ -191,13 +185,8 @@ pub fn translate_expression_with_joins( let array_type = database::Type::ArrayType(Box::new( database::Type::ScalarType(left_typ), )); - let (right, right_joins) = translate_comparison_value( - env, - state, - root_and_current_tables, - value, - &array_type, - )?; + let (right, right_joins) = + translate_comparison_value(env, state, tables, value, &array_type)?; joins.extend(right_joins); let right = Box::new(make_unnest_subquery(state, right)); @@ -214,14 +203,13 @@ pub fn translate_expression_with_joins( } } else { let mut joins = vec![]; - let (left, left_joins) = - translate_comparison_target(env, state, root_and_current_tables, column)?; + let (left, left_joins) = translate_comparison_target(env, state, tables, column)?; joins.extend(left_joins); let (right, right_joins) = translate_comparison_value( env, state, - root_and_current_tables, + tables, value, &database::Type::ScalarType(op.argument_type.clone()), )?; @@ -257,7 +245,7 @@ pub fn translate_expression_with_joins( translate_exists_in_collection( env, state, - root_and_current_tables, + tables, in_collection.clone(), predicate, )?, @@ -266,8 +254,7 @@ pub fn translate_expression_with_joins( }, models::Expression::UnaryComparisonOperator { column, operator } => match operator { models::UnaryComparisonOperator::IsNull => { - let (value, joins) = - translate_comparison_target(env, state, root_and_current_tables, column)?; + let (value, joins) = translate_comparison_target(env, state, tables, column)?; Ok(( sql::ast::Expression::UnaryOperation { @@ -323,11 +310,11 @@ pub fn translate_expression_with_joins( fn translate_comparison_pathelements( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, path: &[models::PathElement], ) -> Result<(TableSourceAndReference, Vec), Error> { let mut joins = vec![]; - let RootAndCurrentTables { current_table, .. } = root_and_current_tables; + let CurrentTableAndScope { current_table, .. } = tables; let final_ref = path.iter().try_fold( current_table.clone(), @@ -367,22 +354,17 @@ fn translate_comparison_pathelements( 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: TableSourceAndReference { - reference: table.reference.clone(), - source: table.source.clone(), - }, - }; + let new_tables = tables.push(TableSourceAndReference { + reference: table.reference.clone(), + source: table.source.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, - )?, + Some(predicate) => { + translate_expression_with_joins(env, state, &new_tables, predicate)? + } }; // relationship where clause @@ -405,7 +387,7 @@ fn translate_comparison_pathelements( }, )); - Ok(new_root_and_current_tables.current_table) + Ok(new_tables.current_table) }, )?; @@ -450,14 +432,14 @@ fn translate_comparison_pathelements( fn translate_comparison_target( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, column: &models::ComparisonTarget, ) -> Result<(sql::ast::Expression, Vec), Error> { match column { models::ComparisonTarget::Aggregate { .. } => todo!(), models::ComparisonTarget::Column { name, field_path } => { let (table_ref, joins) = - translate_comparison_pathelements(env, state, root_and_current_tables, &vec![])?; + translate_comparison_pathelements(env, state, tables, &vec![])?; // get the unrelated table information from the metadata. let collection_info = env.lookup_fields_info(&table_ref.source)?; @@ -481,7 +463,7 @@ fn translate_comparison_target( fn translate_comparison_value( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, value: &models::ComparisonValue, typ: &database::Type, ) -> Result<(sql::ast::Expression, Vec), Error> { @@ -503,7 +485,7 @@ fn translate_comparison_value( translate_comparison_target( env, state, - root_and_current_tables, + tables, &models::ComparisonTarget::Column { name: name.clone(), field_path: field_path.clone(), @@ -526,7 +508,7 @@ fn translate_comparison_value( pub fn translate_exists_in_collection( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, in_collection: models::ExistsInCollection, predicate: &models::Expression, ) -> Result { @@ -558,20 +540,13 @@ pub fn translate_exists_in_collection( let mut select = sql::helpers::simple_select(select_cols); select.from = Some(from_clause); - let new_root_and_current_tables = RootAndCurrentTables { - root_table: root_and_current_tables.root_table.clone(), - current_table: TableSourceAndReference { - reference: table.reference, - source: table.source, - }, - }; + let new_tables = tables.push(TableSourceAndReference { + reference: table.reference.clone(), + source: table.source.clone(), + }); - let (expr, expr_joins) = translate_expression_with_joins( - env, - state, - &new_root_and_current_tables, - predicate, - )?; + let (expr, expr_joins) = + translate_expression_with_joins(env, state, &new_tables, predicate)?; select.where_ = sql::ast::Where(expr); select.joins = expr_joins; @@ -619,26 +594,19 @@ pub fn translate_exists_in_collection( let mut select = sql::helpers::simple_select(select_cols); select.from = Some(from_clause); - let new_root_and_current_tables = RootAndCurrentTables { - root_table: root_and_current_tables.root_table.clone(), - current_table: TableSourceAndReference { - reference: table.reference.clone(), - source: table.source, - }, - }; + let new_tables = tables.push(TableSourceAndReference { + reference: table.reference.clone(), + source: table.source.clone(), + }); // exists condition - let (exists_cond, exists_joins) = translate_expression_with_joins( - env, - state, - &new_root_and_current_tables, - predicate, - )?; + let (exists_cond, exists_joins) = + translate_expression_with_joins(env, state, &new_tables, predicate)?; // relationship where clause let cond = relationships::translate_column_mapping( env, - &root_and_current_tables.current_table, + &tables.current_table, &table.reference, exists_cond, relationship, @@ -664,7 +632,7 @@ pub fn translate_exists_in_collection( UnsupportedCapabilities::FieldArguments, ))?; } - let table = &root_and_current_tables.current_table; + let table = &tables.current_table; // Get the table information from the metadata. let collection_fields_info = env.lookup_fields_info(&table.source)?; @@ -730,21 +698,14 @@ pub fn translate_exists_in_collection( // Define a new root and current table structure pointing the current table // at the nested field. - let new_root_and_current_tables = RootAndCurrentTables { - root_table: root_and_current_tables.root_table.clone(), - current_table: TableSourceAndReference { - reference: sql::ast::TableReference::AliasedTable(alias), - source, - }, - }; + let new_tables = tables.push(TableSourceAndReference { + reference: sql::ast::TableReference::AliasedTable(alias), + source, + }); // Translate the predicate inside the exists. - let (exists_cond, exists_joins) = translate_expression_with_joins( - env, - state, - &new_root_and_current_tables, - predicate, - )?; + let (exists_cond, exists_joins) = + translate_expression_with_joins(env, state, &new_tables, predicate)?; // Construct the `where exists` expression. Ok(sql::helpers::where_exists_select( @@ -759,7 +720,7 @@ pub fn translate_exists_in_collection( /// Extract the scalar type of a comparison target fn get_comparison_target_type( env: &Env, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, column: &models::ComparisonTarget, ) -> Result { match column { @@ -769,7 +730,7 @@ fn get_comparison_target_type( Some(field_path) => field_path.iter().collect(), }; let column = env - .lookup_fields_info(&root_and_current_tables.current_table.source)? + .lookup_fields_info(&tables.current_table.source)? .lookup_column(name)?; get_column_scalar_type_name(env, &column.r#type, &mut field_path) diff --git a/crates/query-engine/translation/src/translation/query/root.rs b/crates/query-engine/translation/src/translation/query/root.rs index 925bc201..9f64b0c1 100644 --- a/crates/query-engine/translation/src/translation/query/root.rs +++ b/crates/query-engine/translation/src/translation/query/root.rs @@ -14,7 +14,7 @@ use super::sorting; use crate::translation::error::Error; use crate::translation::helpers::TableSource; use crate::translation::helpers::{ - CollectionInfo, Env, RootAndCurrentTables, State, TableSourceAndReference, + CollectionInfo, CurrentTableAndScope, Env, State, TableSourceAndReference, }; use query_engine_sql::sql; @@ -174,21 +174,17 @@ pub fn translate_query_part( select: &mut sql::ast::Select, ) -> Result<(), Error> { // the root table and the current table are the same at this point - let root_and_current_tables = RootAndCurrentTables { - root_table: current_table.clone(), - current_table: current_table.clone(), - }; + let tables = CurrentTableAndScope::new(current_table.clone()); // translate order_by - let (order_by, order_by_joins) = - sorting::translate(env, state, &root_and_current_tables, &query.order_by)?; + let (order_by, order_by_joins) = sorting::translate(env, state, &tables, &query.order_by)?; select.joins.extend(order_by_joins); // translate where let filter = match &query.predicate { None => Ok(sql::helpers::true_expr()), - Some(predicate) => filtering::translate(env, state, &root_and_current_tables, predicate), + Some(predicate) => filtering::translate(env, state, &tables, predicate), }?; // Apply a join predicate if we want one. diff --git a/crates/query-engine/translation/src/translation/query/sorting.rs b/crates/query-engine/translation/src/translation/query/sorting.rs index 1e6f05d9..062260b5 100644 --- a/crates/query-engine/translation/src/translation/query/sorting.rs +++ b/crates/query-engine/translation/src/translation/query/sorting.rs @@ -10,7 +10,7 @@ use super::relationships; use super::root; use crate::translation::error::Error; use crate::translation::helpers::{ - wrap_in_field_path, Env, FieldPath, FieldsInfo, RootAndCurrentTables, State, TableSource, + wrap_in_field_path, CurrentTableAndScope, Env, FieldPath, FieldsInfo, State, TableSource, TableSourceAndReference, }; use query_engine_sql::sql; @@ -22,7 +22,7 @@ use query_engine_sql::sql; pub fn translate( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, order_by: &Option, ) -> Result<(sql::ast::OrderBy, Vec), Error> { let mut joins: Vec = vec![]; @@ -37,13 +37,7 @@ pub fn translate( let order_by_parts = element_groups .iter() .map(|element_group| { - translate_order_by_target_group( - env, - state, - root_and_current_tables, - element_group, - &mut joins, - ) + translate_order_by_target_group(env, state, tables, element_group, &mut joins) }) .collect::>, Error>>()?; // flatten the result columns and sort by their indices in the order by list. @@ -278,16 +272,12 @@ fn group_elements(elements: &[models::OrderByElement]) -> Vec, ) -> Result, Error> { - let column_or_relationship_select = build_select_and_joins_for_order_by_group( - env, - state, - root_and_current_tables, - element_group, - )?; + let column_or_relationship_select = + build_select_and_joins_for_order_by_group(env, state, tables, element_group)?; match column_or_relationship_select { // The column is from the source table, we just need to query it directly. @@ -313,13 +303,8 @@ fn translate_order_by_target_group( // The column is from a relationship table, we need to join with this select query. ColumnsOrSelect::Select { columns, select } => { // Give it a nice unique alias. - let table_alias = state.make_order_by_table_alias( - root_and_current_tables - .current_table - .source - .name_for_alias() - .as_str(), - ); + let table_alias = state + .make_order_by_table_alias(tables.current_table.source.name_for_alias().as_str()); // Build a join and push it to the accumulated joins. let new_join = sql::ast::LeftOuterJoinLateral { @@ -392,7 +377,7 @@ enum ColumnsOrSelect { fn build_select_and_joins_for_order_by_group( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, element_group: &OrderByElementGroup, ) -> Result { // We want to build a select query where "Track" is the root table, and "Artist"."Name" @@ -426,26 +411,21 @@ fn build_select_and_joins_for_order_by_group( } OrderByElementGroup::Columns { .. } => { // If the path is empty, we don't need to build a query, just return the columns. - let table = - env.lookup_fields_info(&root_and_current_tables.current_table.source)?; - let columns = translate_targets( - &table, - &root_and_current_tables.current_table, - element_group, - )? - .into_iter() - .map(|column| { - ( - column.index, - column.direction, - column.field_path, - sql::ast::ColumnReference::AliasedColumn { - table: root_and_current_tables.current_table.reference.clone(), - column: column.alias, - }, - ) - }) - .collect(); + let table = env.lookup_fields_info(&tables.current_table.source)?; + let columns = translate_targets(&table, &tables.current_table, element_group)? + .into_iter() + .map(|column| { + ( + column.index, + column.direction, + column.field_path, + sql::ast::ColumnReference::AliasedColumn { + table: tables.current_table.reference.clone(), + column: column.alias, + }, + ) + }) + .collect(); Ok(ColumnsOrSelect::Columns(columns)) } } @@ -459,7 +439,7 @@ fn build_select_and_joins_for_order_by_group( // from the next join, we need to select these. let (last_table, cols) = path.iter().enumerate().try_fold( ( - root_and_current_tables.current_table.clone(), + tables.current_table.clone(), // this is a dummy value that will be ignored, since we only care about returning // the columns from the last table. PathElementSelectColumns::RelationshipColumns(vec![]), @@ -467,7 +447,7 @@ fn build_select_and_joins_for_order_by_group( |(last_table, _), (index, path_element)| { process_path_element_for_order_by_targets( (env, state), - root_and_current_tables, + tables, element_group, &mut joins, (last_table, (index, path_element)), @@ -601,7 +581,7 @@ struct OrderByRelationshipColumn { /// from the next join, we need to select these. fn process_path_element_for_order_by_targets( (env, state): (&Env, &mut State), - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, element_group: &OrderByElementGroup, // to get the information about this path element we need to select from the relevant table // and join with the previous table. We add a new join to this list of joins. @@ -674,13 +654,11 @@ fn process_path_element_for_order_by_targets( }?; // build a select query from this table where join condition and predicate. + let new_tables = tables.push(last_table); let select = select_for_path_element( env, state, - &RootAndCurrentTables { - root_table: root_and_current_tables.root_table.clone(), - current_table: last_table, - }, + &new_tables, relationship, &path_element.predicate, sql::ast::SelectList::SelectList(select_cols.aliases_and_expressions()), @@ -847,7 +825,7 @@ fn from_clause_for_path_element( fn select_for_path_element( env: &Env, state: &mut State, - root_and_current_tables: &RootAndCurrentTables, + tables: &CurrentTableAndScope, relationship: &models::Relationship, predicate: &Option>, select_list: sql::ast::SelectList, @@ -862,16 +840,13 @@ fn select_for_path_element( None => Ok(select), Some(predicate) => { // generate a condition for the predicate. - let predicate_tables = RootAndCurrentTables { - root_table: root_and_current_tables.root_table.clone(), - current_table: join_table, - }; + let predicate_tables = tables.push(join_table); let predicate_expr = filtering::translate(env, state, &predicate_tables, predicate)?; // generate a condition for this join. let join_condition = relationships::translate_column_mapping( env, - &root_and_current_tables.current_table, + &tables.current_table, &predicate_tables.current_table.reference, sql::helpers::empty_where(), relationship,