diff --git a/src/entity/identity.rs b/src/entity/identity.rs index af68978c..d1cc3170 100644 --- a/src/entity/identity.rs +++ b/src/entity/identity.rs @@ -1,17 +1,24 @@ -use crate::IdenStatic; +use crate::{ColumnTrait, EntityTrait, IdenStatic}; use sea_query::{DynIden, IntoIden}; #[derive(Debug, Clone)] pub enum Identity { Unary(DynIden), Binary(DynIden, DynIden), - // Ternary(DynIden, DynIden, DynIden), + Ternary(DynIden, DynIden, DynIden), } pub trait IntoIdentity { fn into_identity(self) -> Identity; } +pub trait IdentityOf +where + E: EntityTrait, +{ + fn identity_of(self) -> Identity; +} + impl IntoIdentity for T where T: IdenStatic, @@ -30,3 +37,44 @@ where Identity::Binary(self.0.into_iden(), self.1.into_iden()) } } + +impl IntoIdentity for (T, C, R) +where + T: IdenStatic, + C: IdenStatic, + R: IdenStatic, +{ + fn into_identity(self) -> Identity { + Identity::Ternary(self.0.into_iden(), self.1.into_iden(), self.2.into_iden()) + } +} + +impl IdentityOf for C +where + E: EntityTrait, + C: ColumnTrait, +{ + fn identity_of(self) -> Identity { + self.into_identity() + } +} + +impl IdentityOf for (C, C) +where + E: EntityTrait, + C: ColumnTrait, +{ + fn identity_of(self) -> Identity { + self.into_identity() + } +} + +impl IdentityOf for (C, C, C) +where + E: EntityTrait, + C: ColumnTrait, +{ + fn identity_of(self) -> Identity { + self.into_identity() + } +} diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 7c9213d3..7d2059e2 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -1,4 +1,4 @@ -use crate::{EntityTrait, Identity, IntoIdentity, Iterable, QuerySelect, Select}; +use crate::{EntityTrait, Identity, IdentityOf, Iterable, QuerySelect, Select}; use core::marker::PhantomData; use sea_query::{DynIden, IntoIden, JoinType}; use std::fmt::Debug; @@ -89,13 +89,19 @@ where } } - pub fn from(mut self, identifier: E::Column) -> Self { - self.from_col = Some(identifier.into_identity()); + pub fn from(mut self, identifier: T) -> Self + where + T: IdentityOf, + { + self.from_col = Some(identifier.identity_of()); self } - pub fn to(mut self, identifier: R::Column) -> Self { - self.to_col = Some(identifier.into_identity()); + pub fn to(mut self, identifier: T) -> Self + where + T: IdentityOf, + { + self.to_col = Some(identifier.identity_of()); self } } diff --git a/src/query/helper.rs b/src/query/helper.rs index 78eaa4e7..9691e1ab 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -283,6 +283,12 @@ fn join_condition(rel: RelationDef) -> SimpleExpr { .equals(SeaRc::clone(&to_tbl), f1) .and(Expr::tbl(SeaRc::clone(&from_tbl), o2).equals(SeaRc::clone(&to_tbl), f2)) } + (Identity::Ternary(o1, o2, o3), Identity::Ternary(f1, f2, f3)) => { + Expr::tbl(SeaRc::clone(&from_tbl), o1) + .equals(SeaRc::clone(&to_tbl), f1) + .and(Expr::tbl(SeaRc::clone(&from_tbl), o2).equals(SeaRc::clone(&to_tbl), f2)) + .and(Expr::tbl(SeaRc::clone(&from_tbl), o3).equals(SeaRc::clone(&to_tbl), f3)) + } _ => panic!("Owner key and foreign key mismatch"), } } diff --git a/src/query/join.rs b/src/query/join.rs index 61c6c1b9..d6e00301 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -61,7 +61,7 @@ where #[cfg(test)] mod tests { - use crate::tests_cfg::{cake, filling, fruit}; + use crate::tests_cfg::{cake, cake_filling, cake_filling_price, filling, fruit}; use crate::{ColumnTrait, DbBackend, EntityTrait, ModelTrait, QueryFilter, QueryTrait}; #[test] @@ -182,4 +182,23 @@ mod tests { .join(" ") ); } + + #[test] + fn join_8() { + use crate::{Related, Select}; + + let find_cake_filling_price: Select = + cake_filling::Entity::find_related(); + assert_eq!( + find_cake_filling_price.build(DbBackend::MySql).to_string(), + [ + "SELECT `cake_filling_price`.`cake_id`, `cake_filling_price`.`filling_id`, `cake_filling_price`.`price`", + "FROM `cake_filling_price`", + "INNER JOIN `cake_filling` ON", + "(`cake_filling`.`cake_id` = `cake_filling_price`.`cake_id`) AND", + "(`cake_filling`.`filling_id` = `cake_filling_price`.`filling_id`)", + ] + .join(" ") + ); + } } diff --git a/src/tests_cfg/cake_filling.rs b/src/tests_cfg/cake_filling.rs index 6b5c20aa..b1151ee4 100644 --- a/src/tests_cfg/cake_filling.rs +++ b/src/tests_cfg/cake_filling.rs @@ -66,4 +66,10 @@ impl RelationTrait for Relation { } } +impl Related for Entity { + fn to() -> RelationDef { + super::cake_filling_price::Relation::CakeFilling.def().rev() + } +} + impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/cake_filling_price.rs b/src/tests_cfg/cake_filling_price.rs new file mode 100644 index 00000000..eae07871 --- /dev/null +++ b/src/tests_cfg/cake_filling_price.rs @@ -0,0 +1,76 @@ +use crate as sea_orm; +use crate::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "cake_filling_price" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub cake_id: i32, + pub filling_id: i32, + pub price: Decimal, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + CakeId, + FillingId, + Price, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + CakeId, + FillingId, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + false + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + CakeFilling, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::CakeId => ColumnType::Integer.def(), + Self::FillingId => ColumnType::Integer.def(), + Self::Price => ColumnType::Decimal(None).def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::CakeFilling => Entity::belongs_to(super::cake_filling::Entity) + .from((Column::CakeId, Column::FillingId)) + .to(( + super::cake_filling::Column::CakeId, + super::cake_filling::Column::FillingId, + )) + .into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CakeFilling.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/mod.rs b/src/tests_cfg/mod.rs index ca9b8a68..afb9e115 100644 --- a/src/tests_cfg/mod.rs +++ b/src/tests_cfg/mod.rs @@ -2,10 +2,12 @@ pub mod cake; pub mod cake_filling; +pub mod cake_filling_price; pub mod filling; pub mod fruit; pub use cake::Entity as Cake; pub use cake_filling::Entity as CakeFilling; +pub use cake_filling_price::Entity as CakeFillingPrice; pub use filling::Entity as Filling; pub use fruit::Entity as Fruit;