Join APIs
This commit is contained in:
parent
634b5aca7a
commit
1bec83ff64
@ -105,7 +105,7 @@ async fn count_fruits_by_cake(db: &Database) -> Result<(), QueryErr> {
|
|||||||
print!("count fruits by cake: ");
|
print!("count fruits by cake: ");
|
||||||
|
|
||||||
let select = cake::Entity::find()
|
let select = cake::Entity::find()
|
||||||
.left_join(cake::Relation::Fruit)
|
.left_join(fruit::Entity)
|
||||||
.select_only()
|
.select_only()
|
||||||
.column(cake::Column::Name)
|
.column(cake::Column::Name)
|
||||||
.column_as(fruit::Column::Id.count(), "num_of_fruits")
|
.column_as(fruit::Column::Id.count(), "num_of_fruits")
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{EntityTrait, Identity, IntoIdentity, Select};
|
use crate::{EntityTrait, Identity, IntoIdentity, Select};
|
||||||
use sea_query::{Iden, IntoIden};
|
use sea_query::{Iden, IntoIden, JoinType};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -24,7 +24,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn find_related() -> Select<R> {
|
fn find_related() -> Select<R> {
|
||||||
Select::<R>::new().prepare_reverse_join(Self::to())
|
Select::<R>::new().join_rev(JoinType::InnerJoin, Self::to())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
ColumnTrait, EntityTrait, Identity, Iterable, ModelTrait, PrimaryKeyOfModel, Related,
|
ColumnTrait, EntityTrait, Identity, Iterable, ModelTrait, PrimaryKeyOfModel, Related,
|
||||||
RelationDef, RelationTrait, Statement,
|
RelationDef, Statement,
|
||||||
};
|
};
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
@ -67,35 +67,6 @@ where
|
|||||||
self
|
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 {
|
pub fn select_only(mut self) -> Self {
|
||||||
self.query.clear_selects();
|
self.query.clear_selects();
|
||||||
self
|
self
|
||||||
@ -243,23 +214,71 @@ where
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn left_join(self, rel: E::Relation) -> Self {
|
/// Join via [`RelationDef`].
|
||||||
self.prepare_join(JoinType::LeftJoin, E::Relation::def(&rel))
|
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 {
|
/// Join via [`RelationDef`] but in reverse direction.
|
||||||
self.prepare_join(JoinType::RightJoin, E::Relation::def(&rel))
|
/// 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 {
|
/// Left Join with a Related Entity.
|
||||||
self.prepare_join(JoinType::InnerJoin, E::Relation::def(&rel))
|
pub fn left_join<R>(self, _: R) -> Self
|
||||||
|
where
|
||||||
|
R: EntityTrait,
|
||||||
|
E: Related<R>,
|
||||||
|
{
|
||||||
|
self.join(JoinType::LeftJoin, E::to())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reverse_join<R>(self) -> Self
|
/// Right Join with a Related Entity.
|
||||||
|
pub fn right_join<R>(self, _: R) -> Self
|
||||||
|
where
|
||||||
|
R: EntityTrait,
|
||||||
|
E: Related<R>,
|
||||||
|
{
|
||||||
|
self.join(JoinType::RightJoin, E::to())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inner Join with a Related Entity.
|
||||||
|
pub fn inner_join<R>(self, _: R) -> Self
|
||||||
|
where
|
||||||
|
R: EntityTrait,
|
||||||
|
E: Related<R>,
|
||||||
|
{
|
||||||
|
self.join(JoinType::InnerJoin, E::to())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Join with an Entity Related to me.
|
||||||
|
pub fn reverse_join<R>(self, _: R) -> Self
|
||||||
where
|
where
|
||||||
R: EntityTrait + Related<E>,
|
R: EntityTrait + Related<E>,
|
||||||
{
|
{
|
||||||
self.prepare_reverse_join(R::to())
|
self.join_rev(JoinType::InnerJoin, R::to())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a mutable ref to the query builder
|
/// Get a mutable ref to the query builder
|
||||||
@ -296,7 +315,7 @@ mod tests {
|
|||||||
fn join_1() {
|
fn join_1() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake::Entity::find()
|
cake::Entity::find()
|
||||||
.left_join(cake::Relation::Fruit)
|
.left_join(fruit::Entity)
|
||||||
.build(MysqlQueryBuilder)
|
.build(MysqlQueryBuilder)
|
||||||
.to_string(),
|
.to_string(),
|
||||||
[
|
[
|
||||||
@ -311,7 +330,7 @@ mod tests {
|
|||||||
fn join_2() {
|
fn join_2() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
cake::Entity::find()
|
cake::Entity::find()
|
||||||
.inner_join(cake::Relation::Fruit)
|
.inner_join(fruit::Entity)
|
||||||
.filter(fruit::Column::Name.contains("cherry"))
|
.filter(fruit::Column::Name.contains("cherry"))
|
||||||
.build(MysqlQueryBuilder)
|
.build(MysqlQueryBuilder)
|
||||||
.to_string(),
|
.to_string(),
|
||||||
@ -328,7 +347,7 @@ mod tests {
|
|||||||
fn join_3() {
|
fn join_3() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
fruit::Entity::find()
|
fruit::Entity::find()
|
||||||
.reverse_join::<cake::Entity>()
|
.reverse_join(cake::Entity)
|
||||||
.build(MysqlQueryBuilder)
|
.build(MysqlQueryBuilder)
|
||||||
.to_string(),
|
.to_string(),
|
||||||
[
|
[
|
||||||
|
Loading…
x
Reference in New Issue
Block a user