Skip to content

Commit a0d4230

Browse files
committed
Refactor JoinExpression to support multiple conditions
1 parent cd57a1d commit a0d4230

File tree

14 files changed

+195
-209
lines changed

14 files changed

+195
-209
lines changed

libs/@local/graph/postgres-store/src/store/postgres/query/compile.rs

Lines changed: 69 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -356,22 +356,15 @@ impl<'p, 'q: 'p, R: PostgresRecord> SelectCompiler<'p, 'q, R> {
356356
}
357357

358358
fn add_condition(&mut self, condition: Condition, table: Option<&TableReference>) {
359-
let conditions = table
359+
table
360360
.and_then(|table| {
361-
self.statement.joins.iter_mut().find_map(|join| match join {
362-
// If a table is provided and we have a join on that table, we add the condition
363-
// to the
364-
JoinExpression::Old {
365-
from,
366-
additional_conditions,
367-
..
368-
} if *from.reference_table() == *table => Some(additional_conditions),
369-
JoinExpression::Old { .. } => None,
361+
// If a table is provided and we have a join on that table, we add the condition
362+
self.statement.joins.iter_mut().find_map(|join| {
363+
(*table == *join.from.reference_table()).then_some(&mut join.conditions)
370364
})
371365
})
372-
.unwrap_or(&mut self.statement.where_expression.conditions);
373-
374-
conditions.push(condition);
366+
.unwrap_or(&mut self.statement.where_expression.conditions)
367+
.push(condition);
375368
}
376369

377370
/// Adds a new path to the selection which can be used as cursor.
@@ -572,11 +565,7 @@ impl<'p, 'q: 'p, R: PostgresRecord> SelectCompiler<'p, 'q, R> {
572565
};
573566

574567
if let Some(last_join) = self.statement.joins.last_mut() {
575-
let JoinExpression::Old {
576-
from: last_join_from,
577-
..
578-
} = last_join;
579-
let last_reference_table = last_join_from.reference_table();
568+
let last_reference_table = last_join.from.reference_table();
580569
ensure!(
581570
last_reference_table.name == TableName::from(Table::DataTypeEmbeddings)
582571
|| last_reference_table.name
@@ -628,7 +617,7 @@ impl<'p, 'q: 'p, R: PostgresRecord> SelectCompiler<'p, 'q, R> {
628617
| Table::Reference(_) => unreachable!(),
629618
};
630619

631-
*last_join_from = JoinFrom::SelectStatement {
620+
last_join.from = JoinFrom::SelectStatement {
632621
statement: Box::new(SelectStatement {
633622
with: WithExpression::default(),
634623
distinct: vec![],
@@ -1097,76 +1086,85 @@ impl<'p, 'q: 'p, R: PostgresRecord> SelectCompiler<'p, 'q, R> {
10971086

10981087
let mut is_outer_join_chain = false;
10991088
for relation in path.relations() {
1100-
let foreign_key_join = relation.joins();
1101-
for foreign_key_reference in foreign_key_join {
1102-
let mut join_expression = JoinExpression::from_foreign_key(
1103-
foreign_key_reference,
1104-
current_table.alias.unwrap_or_default(),
1105-
Alias {
1106-
condition_index: self.artifacts.condition_index,
1107-
chain_depth: current_table.alias.unwrap_or_default().chain_depth + 1,
1108-
number: 0,
1109-
},
1110-
);
1111-
1112-
let JoinExpression::Old {
1113-
join: join_expression_type,
1114-
from: join_expression_from,
1115-
on: join_expression_on,
1116-
on_alias: join_expression_on_alias,
1117-
..
1118-
} = &mut join_expression;
1119-
let join_expression_table = join_expression_from.reference_table_mut();
1120-
1121-
if is_outer_join_chain {
1122-
*join_expression_type = JoinType::LeftOuter;
1123-
} else if *join_expression_type != JoinType::Inner {
1124-
is_outer_join_chain = true;
1089+
for foreign_key_reference in relation.joins() {
1090+
let join_type = if is_outer_join_chain {
1091+
JoinType::LeftOuter
11251092
} else {
1126-
// Join is Inner type, keep as-is
1127-
}
1093+
let join_type = foreign_key_reference.join_type();
1094+
if join_type != JoinType::Inner {
1095+
is_outer_join_chain = true;
1096+
}
1097+
join_type
1098+
};
1099+
1100+
let mut join_table = foreign_key_reference.table().aliased(Alias {
1101+
condition_index: self.artifacts.condition_index,
1102+
chain_depth: current_table.alias.unwrap_or_default().chain_depth + 1,
1103+
number: 0,
1104+
});
1105+
let mut conditions =
1106+
foreign_key_reference.conditions(current_table.alias, join_table.alias);
11281107

11291108
let mut found = false;
1109+
let mut max_number = 0;
1110+
11301111
for existing in &self.statement.joins {
1131-
let JoinExpression::Old {
1132-
from: existing_from,
1133-
on: existing_on,
1134-
on_alias: existing_on_alias,
1135-
..
1136-
} = existing;
1137-
let existing_table = existing_from.reference_table();
1138-
1139-
if existing_table == join_expression_table {
1112+
let existing_table = existing.from.reference_table();
1113+
1114+
// Check for exact match to reuse existing join
1115+
if *existing_table == join_table {
11401116
// We only need to check the join conditions, not the join type or
11411117
// additional conditions. This is enough to reuse an existing join
11421118
// statement.
1143-
if existing_on == join_expression_on
1144-
&& existing_on_alias == join_expression_on_alias
1145-
{
1146-
// We already have a join statement for this column, so we can reuse it.
1119+
if existing.conditions.starts_with(&conditions) {
1120+
// We already have a join statement for this column, so we can reuse
1121+
// it.
11471122
current_table = Cow::Borrowed(existing_table);
11481123
found = true;
11491124
break;
11501125
}
1151-
// We already have a join statement for this table, but it's on a different
1152-
// column. We need to create a new join statement later on with a new,
1153-
// unique alias.
1154-
join_expression_table.alias.get_or_insert_default().number += 1;
1126+
}
1127+
1128+
// Track maximum number for joins with same table name and alias prefix
1129+
if let Some(existing_alias) = existing_table.alias
1130+
&& join_table.name == existing_table.name
1131+
&& join_table
1132+
.alias
1133+
.map(|alias| (alias.condition_index, alias.chain_depth))
1134+
== existing_table
1135+
.alias
1136+
.map(|alias| (alias.condition_index, alias.chain_depth))
1137+
{
1138+
max_number = max_number.max(existing_alias.number + 1);
11551139
}
11561140
}
11571141

1142+
// If we didn't find an exact match but found alias conflicts, update the alias
11581143
if !found {
1159-
// We don't have a join statement for this column yet, so we need to create one.
1160-
current_table = Cow::Owned(join_expression_table.clone());
1161-
let current_alias = current_table.alias.unwrap_or_default();
1162-
self.statement.joins.push(join_expression);
1163-
1164-
for condition in relation.additional_conditions(&current_table) {
1165-
self.add_condition(condition, Some(&current_table));
1144+
if max_number > 0 {
1145+
join_table.alias.get_or_insert_default().number = max_number;
1146+
// Recalculate conditions with the updated alias
1147+
conditions =
1148+
foreign_key_reference.conditions(current_table.alias, join_table.alias);
11661149
}
11671150

1151+
// We don't have a join statement for this column yet, so we need to create one.
1152+
current_table = Cow::Owned(join_table.clone());
1153+
conditions.extend(relation.additional_conditions(&join_table));
1154+
self.statement.joins.push(JoinExpression {
1155+
join: join_type,
1156+
from: JoinFrom::Table {
1157+
table: TableReference {
1158+
alias: None,
1159+
..join_table.clone()
1160+
},
1161+
alias: Some(join_table),
1162+
},
1163+
conditions,
1164+
});
1165+
11681166
if let Some(hook) = self.table_hooks.get(&current_table.name) {
1169-
hook(self, current_alias);
1167+
hook(self, current_table.alias.unwrap_or_default());
11701168
}
11711169
}
11721170
}

libs/@local/graph/postgres-store/src/store/postgres/query/condition.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::store::postgres::query::{Expression, Transpile};
55
/// A [`Filter`], which can be transpiled.
66
///
77
/// [`Filter`]: hash_graph_store::filter::Filter
8-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8+
#[derive(Debug, Clone, PartialEq, Eq)]
99
pub enum Condition {
1010
All(Vec<Self>),
1111
Any(Vec<Self>),

libs/@local/graph/postgres-store/src/store/postgres/query/expression/conditional.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::store::postgres::query::{
99
Alias, Column, SelectStatement, Table, Transpile, WindowStatement, table::DatabaseColumn as _,
1010
};
1111

12-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12+
#[derive(Debug, Clone, PartialEq, Eq)]
1313
pub enum Function {
1414
Min(Box<Expression>),
1515
Max(Box<Expression>),
@@ -157,7 +157,7 @@ impl Transpile for PostgresType {
157157
}
158158

159159
/// A compiled expression in Postgres.
160-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
160+
#[derive(Debug, Clone, PartialEq, Eq)]
161161
pub enum Expression {
162162
Asterisk,
163163
ColumnReference(ColumnReference<'static>),

libs/@local/graph/postgres-store/src/store/postgres/query/expression/group_by_clause.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use core::fmt;
22

33
use crate::store::postgres::query::{Expression, Transpile};
44

5-
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
5+
#[derive(Debug, Clone, Default, PartialEq, Eq)]
66
pub struct GroupByExpression {
77
pub expressions: Vec<Expression>,
88
}

0 commit comments

Comments
 (0)