diff --git a/examples/sqlx-mysql/src/main.rs b/examples/sqlx-mysql/src/main.rs index d08aeea3..458e1d8a 100644 --- a/examples/sqlx-mysql/src/main.rs +++ b/examples/sqlx-mysql/src/main.rs @@ -105,7 +105,7 @@ async fn count_fruits_by_cake(db: &Database) -> Result<(), QueryErr> { print!("count fruits by cake: "); let select = cake::Entity::find() - .left_join(cake::Relation::Fruit) + .left_join(fruit::Entity) .select_only() .column(cake::Column::Name) .column_as(fruit::Column::Id.count(), "num_of_fruits") diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 15629f80..a1529c2c 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -1,5 +1,5 @@ use crate::{EntityTrait, Identity, IntoIdentity, Select}; -use sea_query::{Iden, IntoIden}; +use sea_query::{Iden, IntoIden, JoinType}; use std::fmt::Debug; use std::rc::Rc; @@ -24,7 +24,7 @@ where } fn find_related() -> Select { - Select::::new().prepare_reverse_join(Self::to()) + Select::::new().join_rev(JoinType::InnerJoin, Self::to()) } } diff --git a/src/query/select.rs b/src/query/select.rs index 9293f954..3814dc23 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -1,6 +1,6 @@ use crate::{ ColumnTrait, EntityTrait, Identity, Iterable, ModelTrait, PrimaryKeyOfModel, Related, - RelationDef, RelationTrait, Statement, + RelationDef, Statement, }; use core::fmt::Debug; use core::marker::PhantomData; @@ -67,35 +67,6 @@ where self } - fn prepare_join(mut self, join: JoinType, rel: RelationDef) -> Self { - let own_tbl = E::default().into_iden(); - let to_tbl = rel.to_tbl.clone(); - let owner_keys = rel.from_col; - let foreign_keys = rel.to_col; - let condition = match (owner_keys, foreign_keys) { - (Identity::Unary(o1), Identity::Unary(f1)) => { - Expr::tbl(Rc::clone(&own_tbl), o1).equals(Rc::clone(&to_tbl), f1) - } // _ => panic!("Owner key and foreign key mismatch"), - }; - self.query.join(join, Rc::clone(&to_tbl), condition); - self - } - - pub(crate) fn prepare_reverse_join(mut self, rel: RelationDef) -> Self { - let from_tbl = rel.from_tbl.clone(); - let to_tbl = rel.to_tbl.clone(); - let owner_keys = rel.from_col; - let foreign_keys = rel.to_col; - let condition = match (owner_keys, foreign_keys) { - (Identity::Unary(o1), Identity::Unary(f1)) => { - Expr::tbl(Rc::clone(&from_tbl), o1).equals(Rc::clone(&to_tbl), f1) - } // _ => panic!("Owner key and foreign key mismatch"), - }; - self.query - .join(JoinType::InnerJoin, Rc::clone(&from_tbl), condition); - self - } - pub fn select_only(mut self) -> Self { self.query.clear_selects(); self @@ -243,23 +214,71 @@ where self } - pub fn left_join(self, rel: E::Relation) -> Self { - self.prepare_join(JoinType::LeftJoin, E::Relation::def(&rel)) + /// Join via [`RelationDef`]. + pub fn join(mut self, join: JoinType, rel: RelationDef) -> Self { + let own_tbl = E::default().into_iden(); + let to_tbl = rel.to_tbl.clone(); + let owner_keys = rel.from_col; + let foreign_keys = rel.to_col; + let condition = match (owner_keys, foreign_keys) { + (Identity::Unary(o1), Identity::Unary(f1)) => { + Expr::tbl(Rc::clone(&own_tbl), o1).equals(Rc::clone(&to_tbl), f1) + } // _ => panic!("Owner key and foreign key mismatch"), + }; + self.query.join(join, Rc::clone(&to_tbl), condition); + self } - pub fn right_join(self, rel: E::Relation) -> Self { - self.prepare_join(JoinType::RightJoin, E::Relation::def(&rel)) + /// Join via [`RelationDef`] but in reverse direction. + /// Assume when there exist a relation A -> B. + /// You can reverse join B <- A. + pub fn join_rev(mut self, join: JoinType, rel: RelationDef) -> Self { + let from_tbl = rel.from_tbl.clone(); + let to_tbl = rel.to_tbl.clone(); + let owner_keys = rel.from_col; + let foreign_keys = rel.to_col; + let condition = match (owner_keys, foreign_keys) { + (Identity::Unary(o1), Identity::Unary(f1)) => { + Expr::tbl(Rc::clone(&from_tbl), o1).equals(Rc::clone(&to_tbl), f1) + } // _ => panic!("Owner key and foreign key mismatch"), + }; + self.query.join(join, Rc::clone(&from_tbl), condition); + self } - pub fn inner_join(self, rel: E::Relation) -> Self { - self.prepare_join(JoinType::InnerJoin, E::Relation::def(&rel)) + /// Left Join with a Related Entity. + pub fn left_join(self, _: R) -> Self + where + R: EntityTrait, + E: Related, + { + self.join(JoinType::LeftJoin, E::to()) } - pub fn reverse_join(self) -> Self + /// Right Join with a Related Entity. + pub fn right_join(self, _: R) -> Self + where + R: EntityTrait, + E: Related, + { + self.join(JoinType::RightJoin, E::to()) + } + + /// Inner Join with a Related Entity. + pub fn inner_join(self, _: R) -> Self + where + R: EntityTrait, + E: Related, + { + self.join(JoinType::InnerJoin, E::to()) + } + + /// Join with an Entity Related to me. + pub fn reverse_join(self, _: R) -> Self where R: EntityTrait + Related, { - self.prepare_reverse_join(R::to()) + self.join_rev(JoinType::InnerJoin, R::to()) } /// Get a mutable ref to the query builder @@ -296,7 +315,7 @@ mod tests { fn join_1() { assert_eq!( cake::Entity::find() - .left_join(cake::Relation::Fruit) + .left_join(fruit::Entity) .build(MysqlQueryBuilder) .to_string(), [ @@ -311,7 +330,7 @@ mod tests { fn join_2() { assert_eq!( cake::Entity::find() - .inner_join(cake::Relation::Fruit) + .inner_join(fruit::Entity) .filter(fruit::Column::Name.contains("cherry")) .build(MysqlQueryBuilder) .to_string(), @@ -328,7 +347,7 @@ mod tests { fn join_3() { assert_eq!( fruit::Entity::find() - .reverse_join::() + .reverse_join(cake::Entity) .build(MysqlQueryBuilder) .to_string(), [