Support join with table alias (#852)
This commit is contained in:
parent
c956805210
commit
bb9d532ab5
@ -3,8 +3,8 @@ use crate::{
|
||||
PrimaryKeyToColumn, RelationDef,
|
||||
};
|
||||
use sea_query::{
|
||||
Alias, Expr, Iden, IntoCondition, LockType, SeaRc, SelectExpr, SelectStatement, SimpleExpr,
|
||||
TableRef,
|
||||
Alias, Expr, Iden, IntoCondition, IntoIden, LockType, SeaRc, SelectExpr, SelectStatement,
|
||||
SimpleExpr, TableRef,
|
||||
};
|
||||
pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement};
|
||||
|
||||
@ -182,6 +182,32 @@ pub trait QuerySelect: Sized {
|
||||
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
|
||||
fn lock(mut self, lock_type: LockType) -> Self {
|
||||
self.query().lock(lock_type);
|
||||
@ -431,8 +457,15 @@ pub trait QueryFilter: Sized {
|
||||
}
|
||||
|
||||
pub(crate) fn join_condition(mut rel: RelationDef) -> Condition {
|
||||
let from_tbl = unpack_table_ref(&rel.from_tbl);
|
||||
let to_tbl = unpack_table_ref(&rel.to_tbl);
|
||||
// Use table alias (if any) to construct the join condition
|
||||
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 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),
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
||||
use pretty_assertions::assert_eq;
|
||||
use sea_query::{Expr, IntoCondition, JoinType};
|
||||
use sea_query::{Alias, Expr, IntoCondition, JoinType};
|
||||
|
||||
#[test]
|
||||
fn join_1() {
|
||||
@ -506,4 +506,64 @@ mod tests {
|
||||
.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