From ee504e7d9f8490a9759b6a3dcf121fd82011d602 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 21 Sep 2021 12:01:07 +0800 Subject: [PATCH] `find_linked` join with table alias --- src/entity/link.rs | 22 ++++++++++++++++++---- src/entity/model.rs | 3 ++- src/query/helper.rs | 28 +++++++++++++++++++++++++--- src/query/join.rs | 7 ++++--- 4 files changed, 49 insertions(+), 11 deletions(-) diff --git a/src/entity/link.rs b/src/entity/link.rs index 97c9af1b..d0c262d7 100644 --- a/src/entity/link.rs +++ b/src/entity/link.rs @@ -1,5 +1,7 @@ -use crate::{EntityTrait, QuerySelect, RelationDef, Select}; -use sea_query::JoinType; +use crate::{ + join_tbl_on_condition, unpack_table_ref, EntityTrait, QuerySelect, RelationDef, Select, +}; +use sea_query::{Alias, IntoIden, JoinType, SeaRc}; pub type LinkDef = RelationDef; @@ -12,8 +14,20 @@ pub trait Linked { fn find_linked(&self) -> Select { let mut select = Select::new(); - for rel in self.link().into_iter().rev() { - select = select.join_rev(JoinType::InnerJoin, rel); + for (i, rel) in self.link().into_iter().rev().enumerate() { + let from_tbl = Alias::new(&format!("r{}", i)).into_iden(); + let to_tbl = if i > 0 { + Alias::new(&format!("r{}", i - 1)).into_iden() + } else { + unpack_table_ref(&rel.to_tbl) + }; + + select.query().join_as( + JoinType::InnerJoin, + unpack_table_ref(&rel.from_tbl), + SeaRc::clone(&from_tbl), + join_tbl_on_condition(from_tbl, to_tbl, rel.from_col, rel.to_col), + ); } select } diff --git a/src/entity/model.rs b/src/entity/model.rs index c6129ad7..ce4a3a4c 100644 --- a/src/entity/model.rs +++ b/src/entity/model.rs @@ -24,7 +24,8 @@ pub trait ModelTrait: Clone + Send + Debug { where L: Linked, { - l.find_linked().belongs_to(self) + let tbl_alias = &format!("r{}", l.link().len() - 1); + l.find_linked().belongs_to_tbl_alias(self, tbl_alias) } } diff --git a/src/query/helper.rs b/src/query/helper.rs index d93595f1..e6df3637 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -2,10 +2,11 @@ use crate::{ ColumnTrait, EntityTrait, Identity, IntoIdentity, IntoSimpleExpr, Iterable, ModelTrait, PrimaryKeyToColumn, RelationDef, }; -pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement}; use sea_query::{ - Expr, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr, TableRef, + Alias, Expr, Iden, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr, + TableRef, }; +pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement}; // LINT: when the column does not appear in tables selected from // LINT: when there is a group by clause, but some columns don't have aggregate functions @@ -287,14 +288,35 @@ pub trait QueryFilter: Sized { } self } + + fn belongs_to_tbl_alias(mut self, model: &M, tbl_alias: &str) -> Self + where + M: ModelTrait, + { + for key in ::PrimaryKey::iter() { + let col = key.into_column(); + let expr = Expr::tbl(Alias::new(tbl_alias), col).eq(model.get(col)); + self = self.filter(expr); + } + self + } } -fn join_condition(rel: RelationDef) -> SimpleExpr { +pub(crate) fn join_condition(rel: RelationDef) -> SimpleExpr { let from_tbl = unpack_table_ref(&rel.from_tbl); let to_tbl = unpack_table_ref(&rel.to_tbl); let owner_keys = rel.from_col; let foreign_keys = rel.to_col; + join_tbl_on_condition(from_tbl, to_tbl, owner_keys, foreign_keys) +} + +pub(crate) fn join_tbl_on_condition( + from_tbl: SeaRc, + to_tbl: SeaRc, + owner_keys: Identity, + foreign_keys: Identity, +) -> SimpleExpr { match (owner_keys, foreign_keys) { (Identity::Unary(o1), Identity::Unary(f1)) => { Expr::tbl(SeaRc::clone(&from_tbl), o1).equals(SeaRc::clone(&to_tbl), f1) diff --git a/src/query/join.rs b/src/query/join.rs index 19dc3160..e71b7027 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -76,6 +76,7 @@ where mod tests { use crate::tests_cfg::{cake, cake_filling, cake_filling_price, filling, fruit}; use crate::{ColumnTrait, DbBackend, EntityTrait, ModelTrait, QueryFilter, QueryTrait}; + use pretty_assertions::assert_eq; #[test] fn join_1() { @@ -249,9 +250,9 @@ mod tests { [ r#"SELECT `filling`.`id`, `filling`.`name`"#, r#"FROM `filling`"#, - r#"INNER JOIN `cake_filling` ON `cake_filling`.`filling_id` = `filling`.`id`"#, - r#"INNER JOIN `cake` ON `cake`.`id` = `cake_filling`.`cake_id`"#, - r#"WHERE `cake`.`id` = 12"#, + r#"INNER JOIN `cake_filling` AS `r0` ON `r0`.`filling_id` = `filling`.`id`"#, + r#"INNER JOIN `cake` AS `r1` ON `r1`.`id` = `r0`.`cake_id`"#, + r#"WHERE `r1`.`id` = 12"#, ] .join(" ") );