Skip to content

Commit a541ed9

Browse files
committed
Add find_by_relation method to QueryFilter and use it to eliminate unnecessary joins in ModelTrait
1 parent 5cc03a3 commit a541ed9

File tree

3 files changed

+43
-11
lines changed

3 files changed

+43
-11
lines changed

src/entity/model.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
find_linked, ActiveModelBehavior, ActiveModelTrait, ConnectionTrait, DbErr, DeleteResult,
3-
EntityTrait, IntoActiveModel, Linked, QueryFilter, QueryResult, QueryTrait, Related, Select,
4-
SelectModel, SelectorRaw, Statement,
3+
EntityTrait, IntoActiveModel, Linked, QueryFilter, QueryResult, QuerySelect, QueryTrait,
4+
Related, Select, SelectModel, SelectorRaw, Statement,
55
};
66
use async_trait::async_trait;
77
pub use sea_query::{Alias, CommonTableExpression, IntoTableRef, JoinType, UnionType, Value};
@@ -25,16 +25,33 @@ pub trait ModelTrait: Clone + Send + Debug {
2525
R: EntityTrait,
2626
Self::Entity: Related<R>,
2727
{
28-
<Self::Entity as Related<R>>::find_related().belongs_to(self)
28+
let mut select = Select::<R>::new();
29+
if let Some(via) = <Self::Entity as Related<R>>::via() {
30+
select = select.join_rev(JoinType::InnerJoin, via)
31+
}
32+
select.find_by_relation(<Self::Entity as Related<R>>::to(), self, None)
2933
}
3034

3135
/// Find linked Models
3236
fn find_linked<L>(&self, l: L) -> Select<L::ToEntity>
3337
where
3438
L: Linked<FromEntity = Self::Entity>,
3539
{
36-
let tbl_alias = &format!("r{}", l.link().len() - 1);
37-
l.find_linked().belongs_to_tbl_alias(self, tbl_alias)
40+
let mut link = l.link().into_iter().peekable();
41+
match link.next_if(|rel| rel.on_condition.is_none()) {
42+
Some(last) => {
43+
let tbl_alias = if link.len() == 0 {
44+
None
45+
} else {
46+
Some(format!("r{}", link.len() - 1))
47+
};
48+
find_linked(link.rev(), JoinType::InnerJoin).find_by_relation(last, self, tbl_alias)
49+
}
50+
None => {
51+
let tbl_alias = &format!("r{}", link.len() - 1);
52+
find_linked(link.rev(), JoinType::InnerJoin).belongs_to_tbl_alias(self, tbl_alias)
53+
}
54+
}
3855
}
3956

4057
/// Find linked Models, recursively

src/query/helper.rs

+18
Original file line numberDiff line numberDiff line change
@@ -861,6 +861,24 @@ pub trait QueryFilter: Sized {
861861
}
862862
self
863863
}
864+
865+
/// Perform a check to determine table belongs to a Model through a relation
866+
fn find_by_relation<M>(mut self, rel: RelationDef, model: &M, tbl_alias: Option<String>) -> Self
867+
where
868+
M: ModelTrait,
869+
{
870+
let tbl_alias = tbl_alias.unwrap_or_else(|| unpack_table_ref(&rel.to_tbl).to_string());
871+
for (from_col, to_col) in rel.from_col.into_iter().zip(rel.to_col.into_iter()) {
872+
let column = from_col
873+
.to_string()
874+
.parse()
875+
.ok()
876+
.expect("RelationDef should refer to valid column name");
877+
let expr = Expr::col((Alias::new(&tbl_alias), to_col)).eq(model.get(column));
878+
self = self.filter(expr);
879+
}
880+
self
881+
}
864882
}
865883

866884
pub(crate) fn join_condition(mut rel: RelationDef) -> Condition {

src/query/join.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,7 @@ mod tests {
199199
.to_string(),
200200
[
201201
"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`",
202-
"INNER JOIN `cake` ON `cake`.`id` = `fruit`.`cake_id`",
203-
"WHERE `cake`.`id` = 12",
202+
"WHERE `fruit`.`cake_id` = 12",
204203
]
205204
.join(" ")
206205
);
@@ -292,8 +291,7 @@ mod tests {
292291
r#"SELECT `filling`.`id`, `filling`.`name`, `filling`.`vendor_id`"#,
293292
r#"FROM `filling`"#,
294293
r#"INNER JOIN `cake_filling` AS `r0` ON `r0`.`filling_id` = `filling`.`id`"#,
295-
r#"INNER JOIN `cake` AS `r1` ON `r1`.`id` = `r0`.`cake_id`"#,
296-
r#"WHERE `r1`.`id` = 12"#,
294+
r#"WHERE `r0`.`cake_id` = 12"#,
297295
]
298296
.join(" ")
299297
);
@@ -316,8 +314,7 @@ mod tests {
316314
r#"FROM `vendor`"#,
317315
r#"INNER JOIN `filling` AS `r0` ON `r0`.`vendor_id` = `vendor`.`id`"#,
318316
r#"INNER JOIN `cake_filling` AS `r1` ON `r1`.`filling_id` = `r0`.`id`"#,
319-
r#"INNER JOIN `cake` AS `r2` ON `r2`.`id` = `r1`.`cake_id`"#,
320-
r#"WHERE `r2`.`id` = 18"#,
317+
r#"WHERE `r1`.`cake_id` = 18"#,
321318
]
322319
.join(" ")
323320
);

0 commit comments

Comments
 (0)