use crate::{EntityTrait, Identity, IdentityOf, Iterable, QuerySelect, Select}; use core::marker::PhantomData; use sea_query::{JoinType, TableRef}; use std::fmt::Debug; #[derive(Clone, Debug)] pub enum RelationType { HasOne, HasMany, } pub type ForeignKeyAction = sea_query::ForeignKeyAction; pub trait RelationTrait: Iterable + Debug + 'static { fn def(&self) -> RelationDef; } pub trait Related where R: EntityTrait, { fn to() -> RelationDef; fn via() -> Option { None } fn find_related() -> Select { Select::::new().join_join_rev(JoinType::InnerJoin, Self::to(), Self::via()) } } #[derive(Debug)] pub struct RelationDef { pub rel_type: RelationType, pub from_tbl: TableRef, pub to_tbl: TableRef, pub from_col: Identity, pub to_col: Identity, pub is_owner: bool, pub on_delete: Option, pub on_update: Option, } #[derive(Debug)] pub struct RelationBuilder where E: EntityTrait, R: EntityTrait, { entities: PhantomData<(E, R)>, rel_type: RelationType, from_tbl: TableRef, to_tbl: TableRef, from_col: Option, to_col: Option, is_owner: bool, on_delete: Option, on_update: Option, } impl RelationDef { /// Reverse this relation (swap from and to) pub fn rev(self) -> Self { Self { rel_type: self.rel_type, from_tbl: self.to_tbl, to_tbl: self.from_tbl, from_col: self.to_col, to_col: self.from_col, is_owner: !self.is_owner, on_delete: self.on_delete, on_update: self.on_update, } } } impl RelationBuilder where E: EntityTrait, R: EntityTrait, { pub(crate) fn new(rel_type: RelationType, from: E, to: R, is_owner: bool) -> Self { Self { entities: PhantomData, rel_type, from_tbl: from.table_ref(), to_tbl: to.table_ref(), from_col: None, to_col: None, is_owner, on_delete: None, on_update: None, } } pub(crate) fn from_rel(rel_type: RelationType, rel: RelationDef, is_owner: bool) -> Self { Self { entities: PhantomData, rel_type, from_tbl: rel.from_tbl, to_tbl: rel.to_tbl, from_col: Some(rel.from_col), to_col: Some(rel.to_col), is_owner, on_delete: None, on_update: None, } } 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: T) -> Self where T: IdentityOf, { self.to_col = Some(identifier.identity_of()); self } pub fn on_delete(mut self, action: ForeignKeyAction) -> Self { self.on_delete = Some(action); self } pub fn on_update(mut self, action: ForeignKeyAction) -> Self { self.on_update = Some(action); self } } impl From> for RelationDef where E: EntityTrait, R: EntityTrait, { fn from(b: RelationBuilder) -> Self { RelationDef { rel_type: b.rel_type, from_tbl: b.from_tbl, to_tbl: b.to_tbl, from_col: b.from_col.unwrap(), to_col: b.to_col.unwrap(), is_owner: b.is_owner, on_delete: b.on_delete, on_update: b.on_update, } } }