Support join with table alias (#852)
This commit is contained in:
parent
c956805210
commit
bb9d532ab5
@ -3,8 +3,8 @@ use crate::{
|
|||||||
PrimaryKeyToColumn, RelationDef,
|
PrimaryKeyToColumn, RelationDef,
|
||||||
};
|
};
|
||||||
use sea_query::{
|
use sea_query::{
|
||||||
Alias, Expr, Iden, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr,
|
Alias, Expr, Iden, IntoCondition, IntoIden, LockType, SeaRc, SelectExpr, SelectStatement,
|
||||||
TableRef,
|
SimpleExpr, TableRef,
|
||||||
};
|
};
|
||||||
pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement};
|
pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement};
|
||||||
|
|
||||||
@ -182,6 +182,32 @@ pub trait QuerySelect: Sized {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Join via [`RelationDef`] with table alias.
|
||||||
|
fn join_as<I>(mut self, join: JoinType, mut rel: RelationDef, alias: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIden,
|
||||||
|
{
|
||||||
|
let alias = alias.into_iden();
|
||||||
|
rel.to_tbl = rel.to_tbl.alias(SeaRc::clone(&alias));
|
||||||
|
self.query()
|
||||||
|
.join(join, rel.to_tbl.clone(), join_condition(rel));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Join via [`RelationDef`] with table alias but in reverse direction.
|
||||||
|
/// Assume when there exist a relation A to B.
|
||||||
|
/// You can reverse join B from A.
|
||||||
|
fn join_as_rev<I>(mut self, join: JoinType, mut rel: RelationDef, alias: I) -> Self
|
||||||
|
where
|
||||||
|
I: IntoIden,
|
||||||
|
{
|
||||||
|
let alias = alias.into_iden();
|
||||||
|
rel.from_tbl = rel.from_tbl.alias(SeaRc::clone(&alias));
|
||||||
|
self.query()
|
||||||
|
.join(join, rel.from_tbl.clone(), join_condition(rel));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Select lock
|
/// Select lock
|
||||||
fn lock(mut self, lock_type: LockType) -> Self {
|
fn lock(mut self, lock_type: LockType) -> Self {
|
||||||
self.query().lock(lock_type);
|
self.query().lock(lock_type);
|
||||||
@ -431,8 +457,15 @@ pub trait QueryFilter: Sized {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn join_condition(mut rel: RelationDef) -> Condition {
|
pub(crate) fn join_condition(mut rel: RelationDef) -> Condition {
|
||||||
let from_tbl = unpack_table_ref(&rel.from_tbl);
|
// Use table alias (if any) to construct the join condition
|
||||||
let to_tbl = unpack_table_ref(&rel.to_tbl);
|
let from_tbl = match unpack_table_alias(&rel.from_tbl) {
|
||||||
|
Some(alias) => alias,
|
||||||
|
None => unpack_table_ref(&rel.from_tbl),
|
||||||
|
};
|
||||||
|
let to_tbl = match unpack_table_alias(&rel.to_tbl) {
|
||||||
|
Some(alias) => alias,
|
||||||
|
None => unpack_table_ref(&rel.to_tbl),
|
||||||
|
};
|
||||||
let owner_keys = rel.from_col;
|
let owner_keys = rel.from_col;
|
||||||
let foreign_keys = rel.to_col;
|
let foreign_keys = rel.to_col;
|
||||||
|
|
||||||
@ -486,3 +519,16 @@ pub(crate) fn unpack_table_ref(table_ref: &TableRef) -> DynIden {
|
|||||||
| TableRef::ValuesList(_, tbl) => SeaRc::clone(tbl),
|
| TableRef::ValuesList(_, tbl) => SeaRc::clone(tbl),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn unpack_table_alias(table_ref: &TableRef) -> Option<DynIden> {
|
||||||
|
match table_ref {
|
||||||
|
TableRef::Table(_)
|
||||||
|
| TableRef::SchemaTable(_, _)
|
||||||
|
| TableRef::DatabaseSchemaTable(_, _, _)
|
||||||
|
| TableRef::SubQuery(_, _)
|
||||||
|
| TableRef::ValuesList(_, _) => None,
|
||||||
|
TableRef::TableAlias(_, alias)
|
||||||
|
| TableRef::SchemaTableAlias(_, _, alias)
|
||||||
|
| TableRef::DatabaseSchemaTableAlias(_, _, _, alias) => Some(SeaRc::clone(alias)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -124,7 +124,7 @@ mod tests {
|
|||||||
RelationTrait,
|
RelationTrait,
|
||||||
};
|
};
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use sea_query::{Expr, IntoCondition, JoinType};
|
use sea_query::{Alias, Expr, IntoCondition, JoinType};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn join_1() {
|
fn join_1() {
|
||||||
@ -506,4 +506,64 @@ mod tests {
|
|||||||
.join(" ")
|
.join(" ")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn join_20() {
|
||||||
|
assert_eq!(
|
||||||
|
cake::Entity::find()
|
||||||
|
.column_as(
|
||||||
|
Expr::tbl(Alias::new("fruit_alias"), fruit::Column::Name).into_simple_expr(),
|
||||||
|
"fruit_name"
|
||||||
|
)
|
||||||
|
.join_as(
|
||||||
|
JoinType::LeftJoin,
|
||||||
|
cake::Relation::Fruit
|
||||||
|
.def()
|
||||||
|
.on_condition(|_left, right| {
|
||||||
|
Expr::tbl(right, fruit::Column::Name)
|
||||||
|
.like("%tropical%")
|
||||||
|
.into_condition()
|
||||||
|
}),
|
||||||
|
Alias::new("fruit_alias")
|
||||||
|
)
|
||||||
|
.build(DbBackend::MySql)
|
||||||
|
.to_string(),
|
||||||
|
[
|
||||||
|
"SELECT `cake`.`id`, `cake`.`name`, `fruit_alias`.`name` AS `fruit_name` FROM `cake`",
|
||||||
|
"LEFT JOIN `fruit` AS `fruit_alias` ON `cake`.`id` = `fruit_alias`.`cake_id` AND `fruit_alias`.`name` LIKE '%tropical%'",
|
||||||
|
]
|
||||||
|
.join(" ")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn join_21() {
|
||||||
|
assert_eq!(
|
||||||
|
cake::Entity::find()
|
||||||
|
.column_as(
|
||||||
|
Expr::tbl(Alias::new("cake_filling_alias"), cake_filling::Column::CakeId).into_simple_expr(),
|
||||||
|
"cake_filling_cake_id"
|
||||||
|
)
|
||||||
|
.join(JoinType::LeftJoin, cake::Relation::TropicalFruit.def())
|
||||||
|
.join_as_rev(
|
||||||
|
JoinType::LeftJoin,
|
||||||
|
cake_filling::Relation::Cake
|
||||||
|
.def()
|
||||||
|
.on_condition(|left, _right| {
|
||||||
|
Expr::tbl(left, cake_filling::Column::CakeId)
|
||||||
|
.gt(10)
|
||||||
|
.into_condition()
|
||||||
|
}),
|
||||||
|
Alias::new("cake_filling_alias")
|
||||||
|
)
|
||||||
|
.build(DbBackend::MySql)
|
||||||
|
.to_string(),
|
||||||
|
[
|
||||||
|
"SELECT `cake`.`id`, `cake`.`name`, `cake_filling_alias`.`cake_id` AS `cake_filling_cake_id` FROM `cake`",
|
||||||
|
"LEFT JOIN `fruit` ON `cake`.`id` = `fruit`.`cake_id` AND `fruit`.`name` LIKE '%tropical%'",
|
||||||
|
"LEFT JOIN `cake_filling` AS `cake_filling_alias` ON `cake_filling_alias`.`cake_id` = `cake`.`id` AND `cake_filling_alias`.`cake_id` > 10",
|
||||||
|
]
|
||||||
|
.join(" ")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user