Support composite primary key of length up to 12 (#1508)
* feat: support composite primary key of length up to 12 * induction proof * docs * revert tests * testing cursor by 4+ columns
This commit is contained in:
parent
dd261f2a2f
commit
d45bb5b304
@ -2,15 +2,31 @@ use crate::{ColumnTrait, EntityTrait, IdenStatic};
|
|||||||
use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
|
use sea_query::{Alias, DynIden, Iden, IntoIden, SeaRc};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
/// Defines an operation for an Entity
|
/// List of column identifier
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Identity {
|
pub enum Identity {
|
||||||
/// Performs one operation
|
/// Column identifier consists of 1 column
|
||||||
Unary(DynIden),
|
Unary(DynIden),
|
||||||
/// Performs two operations
|
/// Column identifier consists of 2 columns
|
||||||
Binary(DynIden, DynIden),
|
Binary(DynIden, DynIden),
|
||||||
/// Performs three operations
|
/// Column identifier consists of 3 columns
|
||||||
Ternary(DynIden, DynIden, DynIden),
|
Ternary(DynIden, DynIden, DynIden),
|
||||||
|
/// Column identifier consists of more than 3 columns
|
||||||
|
Many(Vec<DynIden>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for Identity {
|
||||||
|
type Item = DynIden;
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
match self {
|
||||||
|
Identity::Unary(ident1) => vec![ident1].into_iter(),
|
||||||
|
Identity::Binary(ident1, ident2) => vec![ident1, ident2].into_iter(),
|
||||||
|
Identity::Ternary(ident1, ident2, ident3) => vec![ident1, ident2, ident3].into_iter(),
|
||||||
|
Identity::Many(vec) => vec.into_iter(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iden for Identity {
|
impl Iden for Identity {
|
||||||
@ -28,6 +44,11 @@ impl Iden for Identity {
|
|||||||
write!(s, "{}", iden2.to_string()).unwrap();
|
write!(s, "{}", iden2.to_string()).unwrap();
|
||||||
write!(s, "{}", iden3.to_string()).unwrap();
|
write!(s, "{}", iden3.to_string()).unwrap();
|
||||||
}
|
}
|
||||||
|
Identity::Many(vec) => {
|
||||||
|
for iden in vec.iter() {
|
||||||
|
write!(s, "{}", iden.to_string()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -47,6 +68,12 @@ where
|
|||||||
fn identity_of(self) -> Identity;
|
fn identity_of(self) -> Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IntoIdentity for Identity {
|
||||||
|
fn into_identity(self) -> Identity {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl IntoIdentity for String {
|
impl IntoIdentity for String {
|
||||||
fn into_identity(self) -> Identity {
|
fn into_identity(self) -> Identity {
|
||||||
self.as_str().into_identity()
|
self.as_str().into_identity()
|
||||||
@ -89,6 +116,36 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_into_identity {
|
||||||
|
( $($T:ident : $N:tt),+ $(,)? ) => {
|
||||||
|
impl< $($T),+ > IntoIdentity for ( $($T),+ )
|
||||||
|
where
|
||||||
|
$($T: IdenStatic),+
|
||||||
|
{
|
||||||
|
fn into_identity(self) -> Identity {
|
||||||
|
Identity::Many(vec![
|
||||||
|
$(self.$N.into_iden()),+
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rustfmt::skip]
|
||||||
|
mod impl_into_identity {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
|
||||||
|
impl_into_identity!(T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10, T11:11);
|
||||||
|
}
|
||||||
|
|
||||||
impl<E, C> IdentityOf<E> for C
|
impl<E, C> IdentityOf<E> for C
|
||||||
where
|
where
|
||||||
E: EntityTrait<Column = C>,
|
E: EntityTrait<Column = C>,
|
||||||
@ -99,7 +156,9 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, C> IdentityOf<E> for (C, C)
|
macro_rules! impl_identity_of {
|
||||||
|
( $($T:ident),+ $(,)? ) => {
|
||||||
|
impl<E, C> IdentityOf<E> for ( $($T),+ )
|
||||||
where
|
where
|
||||||
E: EntityTrait<Column = C>,
|
E: EntityTrait<Column = C>,
|
||||||
C: ColumnTrait,
|
C: ColumnTrait,
|
||||||
@ -108,13 +167,22 @@ where
|
|||||||
self.into_identity()
|
self.into_identity()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl<E, C> IdentityOf<E> for (C, C, C)
|
#[rustfmt::skip]
|
||||||
where
|
mod impl_identity_of {
|
||||||
E: EntityTrait<Column = C>,
|
use super::*;
|
||||||
C: ColumnTrait,
|
|
||||||
{
|
impl_identity_of!(C, C);
|
||||||
fn identity_of(self) -> Identity {
|
impl_identity_of!(C, C, C);
|
||||||
self.into_identity()
|
impl_identity_of!(C, C, C, C);
|
||||||
}
|
impl_identity_of!(C, C, C, C, C);
|
||||||
|
impl_identity_of!(C, C, C, C, C, C);
|
||||||
|
impl_identity_of!(C, C, C, C, C, C, C);
|
||||||
|
impl_identity_of!(C, C, C, C, C, C, C, C);
|
||||||
|
impl_identity_of!(C, C, C, C, C, C, C, C, C);
|
||||||
|
impl_identity_of!(C, C, C, C, C, C, C, C, C, C);
|
||||||
|
impl_identity_of!(C, C, C, C, C, C, C, C, C, C, C);
|
||||||
|
impl_identity_of!(C, C, C, C, C, C, C, C, C, C, C, C);
|
||||||
}
|
}
|
||||||
|
@ -65,3 +65,197 @@ pub trait PrimaryKeyToColumn {
|
|||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "macros")]
|
||||||
|
fn test_composite_primary_key() {
|
||||||
|
mod primary_key_of_1 {
|
||||||
|
use crate as sea_orm;
|
||||||
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "primary_key_of_1")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: i32,
|
||||||
|
pub owner: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod primary_key_of_2 {
|
||||||
|
use crate as sea_orm;
|
||||||
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "primary_key_of_2")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_1: i32,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_2: String,
|
||||||
|
pub owner: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod primary_key_of_3 {
|
||||||
|
use crate as sea_orm;
|
||||||
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "primary_key_of_3")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_1: i32,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_2: String,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_3: Uuid,
|
||||||
|
pub owner: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod primary_key_of_4 {
|
||||||
|
use crate as sea_orm;
|
||||||
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "primary_key_of_4")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_1: TimeDateTimeWithTimeZone,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_2: Uuid,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_3: Json,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_4: Decimal,
|
||||||
|
pub owner: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod primary_key_of_11 {
|
||||||
|
use crate as sea_orm;
|
||||||
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, EnumIter, DeriveActiveEnum)]
|
||||||
|
#[sea_orm(
|
||||||
|
rs_type = "String",
|
||||||
|
db_type = "String(Some(1))",
|
||||||
|
enum_name = "category"
|
||||||
|
)]
|
||||||
|
pub enum DeriveCategory {
|
||||||
|
#[sea_orm(string_value = "B")]
|
||||||
|
Big,
|
||||||
|
#[sea_orm(string_value = "S")]
|
||||||
|
Small,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "primary_key_of_11")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_1: Vec<u8>,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_2: DeriveCategory,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_3: Date,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_4: DateTime,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_5: Time,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_6: TimeTime,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_7: DateTime,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_8: TimeDateTime,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_9: DateTimeLocal,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_10: DateTimeUtc,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_11: DateTimeWithTimeZone,
|
||||||
|
pub owner: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod primary_key_of_12 {
|
||||||
|
use crate as sea_orm;
|
||||||
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "primary_key_of_12")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_1: String,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_2: i8,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_3: u8,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_4: i16,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_5: u16,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_6: i32,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_7: u32,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_8: i64,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_9: u64,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_10: f32,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_11: f64,
|
||||||
|
#[sea_orm(primary_key, auto_increment = false)]
|
||||||
|
pub id_12: bool,
|
||||||
|
pub owner: String,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -365,11 +365,8 @@ where
|
|||||||
|
|
||||||
macro_rules! set_foreign_key_stmt {
|
macro_rules! set_foreign_key_stmt {
|
||||||
( $relation: ident, $foreign_key: ident ) => {
|
( $relation: ident, $foreign_key: ident ) => {
|
||||||
let from_cols: Vec<String> = match $relation.from_col {
|
let from_cols: Vec<String> = $relation
|
||||||
Identity::Unary(o1) => vec![o1],
|
.from_col
|
||||||
Identity::Binary(o1, o2) => vec![o1, o2],
|
|
||||||
Identity::Ternary(o1, o2, o3) => vec![o1, o2, o3],
|
|
||||||
}
|
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|col| {
|
.map(|col| {
|
||||||
let col_name = col.to_string();
|
let col_name = col.to_string();
|
||||||
@ -377,19 +374,8 @@ macro_rules! set_foreign_key_stmt {
|
|||||||
col_name
|
col_name
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
match $relation.to_col {
|
for col in $relation.to_col.into_iter() {
|
||||||
Identity::Unary(o1) => {
|
$foreign_key.to_col(col);
|
||||||
$foreign_key.to_col(o1);
|
|
||||||
}
|
|
||||||
Identity::Binary(o1, o2) => {
|
|
||||||
$foreign_key.to_col(o1);
|
|
||||||
$foreign_key.to_col(o2);
|
|
||||||
}
|
|
||||||
Identity::Ternary(o1, o2, o3) => {
|
|
||||||
$foreign_key.to_col(o1);
|
|
||||||
$foreign_key.to_col(o2);
|
|
||||||
$foreign_key.to_col(o3);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if let Some(action) = $relation.on_delete {
|
if let Some(action) = $relation.on_delete {
|
||||||
$foreign_key.on_delete(action);
|
$foreign_key.on_delete(action);
|
||||||
|
@ -101,6 +101,56 @@ where
|
|||||||
.add(f(c2, v2)),
|
.add(f(c2, v2)),
|
||||||
)
|
)
|
||||||
.add(f(c1, v1)),
|
.add(f(c1, v1)),
|
||||||
|
(Identity::Many(col_vec), ValueTuple::Many(val_vec))
|
||||||
|
if col_vec.len() == val_vec.len() =>
|
||||||
|
{
|
||||||
|
// The length of `col_vec` and `val_vec` should be equal and is denoted by "n".
|
||||||
|
//
|
||||||
|
// The elements of `col_vec` and `val_vec` are denoted by:
|
||||||
|
// - `col_vec`: "col_1", "col_2", ..., "col_n-1", "col_n"
|
||||||
|
// - `val_vec`: "val_1", "val_2", ..., "val_n-1", "val_n"
|
||||||
|
//
|
||||||
|
// The general form of the where condition should have "n" number of inner-AND-condition chained by an outer-OR-condition.
|
||||||
|
// The "n"-th inner-AND-condition should have exactly "n" number of column value expressions,
|
||||||
|
// to construct the expression we take the first "n" number of column and value from the respected vector.
|
||||||
|
// - if it's not the last element, then we construct a "col_1 = val_1" equal expression
|
||||||
|
// - otherwise, for the last element, we should construct a "col_n > val_n" greater than or "col_n < val_n" less than expression.
|
||||||
|
// i.e.
|
||||||
|
// WHERE
|
||||||
|
// (col_1 = val_1 AND col_2 = val_2 AND ... AND col_n > val_n)
|
||||||
|
// OR (col_1 = val_1 AND col_2 = val_2 AND ... AND col_n-1 > val_n-1)
|
||||||
|
// OR (col_1 = val_1 AND col_2 = val_2 AND ... AND col_n-2 > val_n-2)
|
||||||
|
// OR ...
|
||||||
|
// OR (col_1 = val_1 AND col_2 > val_2)
|
||||||
|
// OR (col_1 > val_1)
|
||||||
|
|
||||||
|
// Counting from 1 to "n" (inclusive) but in reverse, i.e. n, n-1, ..., 2, 1
|
||||||
|
(1..=col_vec.len())
|
||||||
|
.rev()
|
||||||
|
.fold(Condition::any(), |cond_any, n| {
|
||||||
|
// Construct the inner-AND-condition
|
||||||
|
let inner_cond_all =
|
||||||
|
// Take the first "n" elements from the column and value vector respectively
|
||||||
|
col_vec.iter().zip(val_vec.iter()).enumerate().take(n).fold(
|
||||||
|
Condition::all(),
|
||||||
|
|inner_cond_all, (i, (col, val))| {
|
||||||
|
let val = val.clone();
|
||||||
|
// Construct a equal expression,
|
||||||
|
// except for the last one being greater than or less than expression
|
||||||
|
let expr = if i != (n - 1) {
|
||||||
|
Expr::col((SeaRc::clone(&self.table), SeaRc::clone(col)))
|
||||||
|
.eq(val)
|
||||||
|
} else {
|
||||||
|
f(col, val)
|
||||||
|
};
|
||||||
|
// Chain it with AND operator
|
||||||
|
inner_cond_all.add(expr)
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// Chain inner-AND-condition with OR operator
|
||||||
|
cond_any.add(inner_cond_all)
|
||||||
|
})
|
||||||
|
}
|
||||||
_ => panic!("column arity mismatch"),
|
_ => panic!("column arity mismatch"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -145,6 +195,11 @@ where
|
|||||||
f(query, c2);
|
f(query, c2);
|
||||||
f(query, c3);
|
f(query, c3);
|
||||||
}
|
}
|
||||||
|
Identity::Many(vec) => {
|
||||||
|
for col in vec.iter() {
|
||||||
|
f(query, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,4 +720,160 @@ mod tests {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod composite_entity {
|
||||||
|
use crate as sea_orm;
|
||||||
|
use crate::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "t")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_1: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_2: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_3: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_4: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_5: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_6: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_7: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_8: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_9: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_10: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_11: String,
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub col_12: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[smol_potat::test]
|
||||||
|
async fn cursor_by_many() -> Result<(), DbErr> {
|
||||||
|
use composite_entity::*;
|
||||||
|
|
||||||
|
let base_sql = [
|
||||||
|
r#"SELECT "t"."col_1", "t"."col_2", "t"."col_3", "t"."col_4", "t"."col_5", "t"."col_6", "t"."col_7", "t"."col_8", "t"."col_9", "t"."col_10", "t"."col_11", "t"."col_12""#,
|
||||||
|
r#"FROM "t" WHERE"#,
|
||||||
|
].join(" ");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
DbBackend::Postgres.build(&
|
||||||
|
Entity::find()
|
||||||
|
.cursor_by((Column::Col1, Column::Col2, Column::Col3, Column::Col4))
|
||||||
|
.after(("val_1", "val_2", "val_3", "val_4"))
|
||||||
|
.query
|
||||||
|
).to_string(),
|
||||||
|
format!("{base_sql} {}", [
|
||||||
|
r#"("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" > 'val_4')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" > 'val_3')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" > 'val_2')"#,
|
||||||
|
r#"OR "t"."col_1" > 'val_1'"#,
|
||||||
|
].join(" "))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
DbBackend::Postgres.build(&
|
||||||
|
Entity::find()
|
||||||
|
.cursor_by((Column::Col1, Column::Col2, Column::Col3, Column::Col4, Column::Col5))
|
||||||
|
.after(("val_1", "val_2", "val_3", "val_4", "val_5"))
|
||||||
|
.query
|
||||||
|
).to_string(),
|
||||||
|
format!("{base_sql} {}", [
|
||||||
|
r#"("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" > 'val_5')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" > 'val_4')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" > 'val_3')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" > 'val_2')"#,
|
||||||
|
r#"OR "t"."col_1" > 'val_1'"#,
|
||||||
|
].join(" "))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
DbBackend::Postgres.build(&
|
||||||
|
Entity::find()
|
||||||
|
.cursor_by((Column::Col1, Column::Col2, Column::Col3, Column::Col4, Column::Col5, Column::Col6))
|
||||||
|
.after(("val_1", "val_2", "val_3", "val_4", "val_5", "val_6"))
|
||||||
|
.query
|
||||||
|
).to_string(),
|
||||||
|
format!("{base_sql} {}", [
|
||||||
|
r#"("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" > 'val_6')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" > 'val_5')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" > 'val_4')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" > 'val_3')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" > 'val_2')"#,
|
||||||
|
r#"OR "t"."col_1" > 'val_1'"#,
|
||||||
|
].join(" "))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
DbBackend::Postgres.build(&
|
||||||
|
Entity::find()
|
||||||
|
.cursor_by((Column::Col1, Column::Col2, Column::Col3, Column::Col4, Column::Col5, Column::Col6, Column::Col7))
|
||||||
|
.before(("val_1", "val_2", "val_3", "val_4", "val_5", "val_6", "val_7"))
|
||||||
|
.query
|
||||||
|
).to_string(),
|
||||||
|
format!("{base_sql} {}", [
|
||||||
|
r#"("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" = 'val_6' AND "t"."col_7" < 'val_7')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" < 'val_6')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" < 'val_5')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" < 'val_4')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" < 'val_3')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" < 'val_2')"#,
|
||||||
|
r#"OR "t"."col_1" < 'val_1'"#,
|
||||||
|
].join(" "))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
DbBackend::Postgres.build(&
|
||||||
|
Entity::find()
|
||||||
|
.cursor_by((Column::Col1, Column::Col2, Column::Col3, Column::Col4, Column::Col5, Column::Col6, Column::Col7, Column::Col8))
|
||||||
|
.before(("val_1", "val_2", "val_3", "val_4", "val_5", "val_6", "val_7", "val_8"))
|
||||||
|
.query
|
||||||
|
).to_string(),
|
||||||
|
format!("{base_sql} {}", [
|
||||||
|
r#"("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" = 'val_6' AND "t"."col_7" = 'val_7' AND "t"."col_8" < 'val_8')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" = 'val_6' AND "t"."col_7" < 'val_7')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" < 'val_6')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" < 'val_5')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" < 'val_4')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" < 'val_3')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" < 'val_2')"#,
|
||||||
|
r#"OR "t"."col_1" < 'val_1'"#,
|
||||||
|
].join(" "))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
DbBackend::Postgres.build(&
|
||||||
|
Entity::find()
|
||||||
|
.cursor_by((Column::Col1, Column::Col2, Column::Col3, Column::Col4, Column::Col5, Column::Col6, Column::Col7, Column::Col8, Column::Col9))
|
||||||
|
.before(("val_1", "val_2", "val_3", "val_4", "val_5", "val_6", "val_7", "val_8", "val_9"))
|
||||||
|
.query
|
||||||
|
).to_string(),
|
||||||
|
format!("{base_sql} {}", [
|
||||||
|
r#"("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" = 'val_6' AND "t"."col_7" = 'val_7' AND "t"."col_8" = 'val_8' AND "t"."col_9" < 'val_9')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" = 'val_6' AND "t"."col_7" = 'val_7' AND "t"."col_8" < 'val_8')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" = 'val_6' AND "t"."col_7" < 'val_7')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" = 'val_5' AND "t"."col_6" < 'val_6')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" = 'val_4' AND "t"."col_5" < 'val_5')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" = 'val_3' AND "t"."col_4" < 'val_4')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" = 'val_2' AND "t"."col_3" < 'val_3')"#,
|
||||||
|
r#"OR ("t"."col_1" = 'val_1' AND "t"."col_2" < 'val_2')"#,
|
||||||
|
r#"OR "t"."col_1" < 'val_1'"#,
|
||||||
|
].join(" "))
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -908,136 +908,43 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A, B> TryGetableMany for (A, B)
|
macro_rules! impl_try_get_many {
|
||||||
|
( $LEN:expr, $($T:ident : $N:expr),+ $(,)? ) => {
|
||||||
|
impl< $($T),+ > TryGetableMany for ( $($T),+ )
|
||||||
where
|
where
|
||||||
A: TryGetable,
|
$($T: TryGetable),+
|
||||||
B: TryGetable,
|
|
||||||
{
|
{
|
||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
|
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
|
||||||
try_get_many_with_slice_len_of(2, cols)?;
|
try_get_many_with_slice_len_of($LEN, cols)?;
|
||||||
Ok((
|
Ok((
|
||||||
A::try_get(res, pre, &cols[0])?,
|
$($T::try_get(res, pre, &cols[$N])?),+
|
||||||
B::try_get(res, pre, &cols[1])?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
|
||||||
Ok((A::try_get_by_index(res, 0)?, B::try_get_by_index(res, 1)?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, C> TryGetableMany for (A, B, C)
|
|
||||||
where
|
|
||||||
A: TryGetable,
|
|
||||||
B: TryGetable,
|
|
||||||
C: TryGetable,
|
|
||||||
{
|
|
||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
|
|
||||||
try_get_many_with_slice_len_of(3, cols)?;
|
|
||||||
Ok((
|
|
||||||
A::try_get(res, pre, &cols[0])?,
|
|
||||||
B::try_get(res, pre, &cols[1])?,
|
|
||||||
C::try_get(res, pre, &cols[2])?,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
||||||
Ok((
|
Ok((
|
||||||
A::try_get_by_index(res, 0)?,
|
$($T::try_get_by_index(res, $N)?),+
|
||||||
B::try_get_by_index(res, 1)?,
|
|
||||||
C::try_get_by_index(res, 2)?,
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
impl<A, B, C, D> TryGetableMany for (A, B, C, D)
|
#[rustfmt::skip]
|
||||||
where
|
mod impl_try_get_many {
|
||||||
A: TryGetable,
|
use super::*;
|
||||||
B: TryGetable,
|
|
||||||
C: TryGetable,
|
|
||||||
D: TryGetable,
|
|
||||||
{
|
|
||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
|
|
||||||
try_get_many_with_slice_len_of(4, cols)?;
|
|
||||||
Ok((
|
|
||||||
A::try_get(res, pre, &cols[0])?,
|
|
||||||
B::try_get(res, pre, &cols[1])?,
|
|
||||||
C::try_get(res, pre, &cols[2])?,
|
|
||||||
D::try_get(res, pre, &cols[3])?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
impl_try_get_many!( 2, T0:0, T1:1);
|
||||||
Ok((
|
impl_try_get_many!( 3, T0:0, T1:1, T2:2);
|
||||||
A::try_get_by_index(res, 0)?,
|
impl_try_get_many!( 4, T0:0, T1:1, T2:2, T3:3);
|
||||||
B::try_get_by_index(res, 1)?,
|
impl_try_get_many!( 5, T0:0, T1:1, T2:2, T3:3, T4:4);
|
||||||
C::try_get_by_index(res, 2)?,
|
impl_try_get_many!( 6, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5);
|
||||||
D::try_get_by_index(res, 3)?,
|
impl_try_get_many!( 7, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6);
|
||||||
))
|
impl_try_get_many!( 8, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7);
|
||||||
}
|
impl_try_get_many!( 9, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8);
|
||||||
}
|
impl_try_get_many!(10, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9);
|
||||||
|
impl_try_get_many!(11, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10);
|
||||||
impl<A, B, C, D, E> TryGetableMany for (A, B, C, D, E)
|
impl_try_get_many!(12, T0:0, T1:1, T2:2, T3:3, T4:4, T5:5, T6:6, T7:7, T8:8, T9:9, T10:10, T11:11);
|
||||||
where
|
|
||||||
A: TryGetable,
|
|
||||||
B: TryGetable,
|
|
||||||
C: TryGetable,
|
|
||||||
D: TryGetable,
|
|
||||||
E: TryGetable,
|
|
||||||
{
|
|
||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
|
|
||||||
try_get_many_with_slice_len_of(5, cols)?;
|
|
||||||
Ok((
|
|
||||||
A::try_get(res, pre, &cols[0])?,
|
|
||||||
B::try_get(res, pre, &cols[1])?,
|
|
||||||
C::try_get(res, pre, &cols[2])?,
|
|
||||||
D::try_get(res, pre, &cols[3])?,
|
|
||||||
E::try_get(res, pre, &cols[4])?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
|
||||||
Ok((
|
|
||||||
A::try_get_by_index(res, 0)?,
|
|
||||||
B::try_get_by_index(res, 1)?,
|
|
||||||
C::try_get_by_index(res, 2)?,
|
|
||||||
D::try_get_by_index(res, 3)?,
|
|
||||||
E::try_get_by_index(res, 4)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<A, B, C, D, E, F> TryGetableMany for (A, B, C, D, E, F)
|
|
||||||
where
|
|
||||||
A: TryGetable,
|
|
||||||
B: TryGetable,
|
|
||||||
C: TryGetable,
|
|
||||||
D: TryGetable,
|
|
||||||
E: TryGetable,
|
|
||||||
F: TryGetable,
|
|
||||||
{
|
|
||||||
fn try_get_many(res: &QueryResult, pre: &str, cols: &[String]) -> Result<Self, TryGetError> {
|
|
||||||
try_get_many_with_slice_len_of(6, cols)?;
|
|
||||||
Ok((
|
|
||||||
A::try_get(res, pre, &cols[0])?,
|
|
||||||
B::try_get(res, pre, &cols[1])?,
|
|
||||||
C::try_get(res, pre, &cols[2])?,
|
|
||||||
D::try_get(res, pre, &cols[3])?,
|
|
||||||
E::try_get(res, pre, &cols[4])?,
|
|
||||||
F::try_get(res, pre, &cols[5])?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_get_many_by_index(res: &QueryResult) -> Result<Self, TryGetError> {
|
|
||||||
Ok((
|
|
||||||
A::try_get_by_index(res, 0)?,
|
|
||||||
B::try_get_by_index(res, 1)?,
|
|
||||||
C::try_get_by_index(res, 2)?,
|
|
||||||
D::try_get_by_index(res, 3)?,
|
|
||||||
E::try_get_by_index(res, 4)?,
|
|
||||||
F::try_get_by_index(res, 5)?,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
|
fn try_get_many_with_slice_len_of(len: usize, cols: &[String]) -> Result<(), TryGetError> {
|
||||||
@ -1132,12 +1039,22 @@ macro_rules! try_from_u64_err {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl TryFromU64 for tuples with generic types
|
#[rustfmt::skip]
|
||||||
try_from_u64_err!(A, B);
|
mod try_from_u64_err {
|
||||||
try_from_u64_err!(A, B, C);
|
use super::*;
|
||||||
try_from_u64_err!(A, B, C, D);
|
|
||||||
try_from_u64_err!(A, B, C, D, E);
|
try_from_u64_err!(T0, T1);
|
||||||
try_from_u64_err!(A, B, C, D, E, F);
|
try_from_u64_err!(T0, T1, T2);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4, T5);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
|
||||||
|
try_from_u64_err!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! try_from_u64_numeric {
|
macro_rules! try_from_u64_numeric {
|
||||||
( $type: ty ) => {
|
( $type: ty ) => {
|
||||||
|
@ -4,7 +4,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use sea_query::{
|
use sea_query::{
|
||||||
Alias, ConditionType, Expr, Iden, IntoCondition, IntoIden, LockType, SeaRc, SelectExpr,
|
Alias, ConditionType, Expr, Iden, IntoCondition, IntoIden, LockType, SeaRc, SelectExpr,
|
||||||
SelectStatement, SimpleExpr, TableRef,
|
SelectStatement, TableRef,
|
||||||
};
|
};
|
||||||
pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement};
|
pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement};
|
||||||
|
|
||||||
@ -713,24 +713,15 @@ pub(crate) fn join_tbl_on_condition(
|
|||||||
to_tbl: SeaRc<dyn Iden>,
|
to_tbl: SeaRc<dyn Iden>,
|
||||||
owner_keys: Identity,
|
owner_keys: Identity,
|
||||||
foreign_keys: Identity,
|
foreign_keys: Identity,
|
||||||
) -> SimpleExpr {
|
) -> Condition {
|
||||||
match (owner_keys, foreign_keys) {
|
let mut cond = Condition::all();
|
||||||
(Identity::Unary(o1), Identity::Unary(f1)) => {
|
for (owner_key, foreign_key) in owner_keys.into_iter().zip(foreign_keys.into_iter()) {
|
||||||
Expr::col((SeaRc::clone(&from_tbl), o1)).equals((SeaRc::clone(&to_tbl), f1))
|
cond = cond.add(
|
||||||
}
|
Expr::col((SeaRc::clone(&from_tbl), owner_key))
|
||||||
(Identity::Binary(o1, o2), Identity::Binary(f1, f2)) => {
|
.equals((SeaRc::clone(&to_tbl), foreign_key)),
|
||||||
Expr::col((SeaRc::clone(&from_tbl), o1))
|
);
|
||||||
.equals((SeaRc::clone(&to_tbl), f1))
|
|
||||||
.and(Expr::col((SeaRc::clone(&from_tbl), o2)).equals((SeaRc::clone(&to_tbl), f2)))
|
|
||||||
}
|
|
||||||
(Identity::Ternary(o1, o2, o3), Identity::Ternary(f1, f2, f3)) => {
|
|
||||||
Expr::col((SeaRc::clone(&from_tbl), o1))
|
|
||||||
.equals((SeaRc::clone(&to_tbl), f1))
|
|
||||||
.and(Expr::col((SeaRc::clone(&from_tbl), o2)).equals((SeaRc::clone(&to_tbl), f2)))
|
|
||||||
.and(Expr::col((SeaRc::clone(&from_tbl), o3)).equals((SeaRc::clone(&to_tbl), f3)))
|
|
||||||
}
|
|
||||||
_ => panic!("Owner key and foreign key mismatch"),
|
|
||||||
}
|
}
|
||||||
|
cond
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn unpack_table_ref(table_ref: &TableRef) -> DynIden {
|
pub(crate) fn unpack_table_ref(table_ref: &TableRef) -> DynIden {
|
||||||
|
@ -250,8 +250,8 @@ mod tests {
|
|||||||
r#"SELECT "cake_filling_price"."cake_id", "cake_filling_price"."filling_id", "cake_filling_price"."price""#,
|
r#"SELECT "cake_filling_price"."cake_id", "cake_filling_price"."filling_id", "cake_filling_price"."price""#,
|
||||||
r#"FROM "public"."cake_filling_price""#,
|
r#"FROM "public"."cake_filling_price""#,
|
||||||
r#"INNER JOIN "cake_filling" ON"#,
|
r#"INNER JOIN "cake_filling" ON"#,
|
||||||
r#"("cake_filling"."cake_id" = "cake_filling_price"."cake_id") AND"#,
|
r#""cake_filling"."cake_id" = "cake_filling_price"."cake_id" AND"#,
|
||||||
r#"("cake_filling"."filling_id" = "cake_filling_price"."filling_id")"#,
|
r#""cake_filling"."filling_id" = "cake_filling_price"."filling_id""#,
|
||||||
]
|
]
|
||||||
.join(" ")
|
.join(" ")
|
||||||
);
|
);
|
||||||
@ -269,8 +269,8 @@ mod tests {
|
|||||||
r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id""#,
|
r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id""#,
|
||||||
r#"FROM "cake_filling""#,
|
r#"FROM "cake_filling""#,
|
||||||
r#"INNER JOIN "public"."cake_filling_price" ON"#,
|
r#"INNER JOIN "public"."cake_filling_price" ON"#,
|
||||||
r#"("cake_filling_price"."cake_id" = "cake_filling"."cake_id") AND"#,
|
r#""cake_filling_price"."cake_id" = "cake_filling"."cake_id" AND"#,
|
||||||
r#"("cake_filling_price"."filling_id" = "cake_filling"."filling_id")"#,
|
r#""cake_filling_price"."filling_id" = "cake_filling"."filling_id""#,
|
||||||
]
|
]
|
||||||
.join(" ")
|
.join(" ")
|
||||||
);
|
);
|
||||||
|
@ -383,6 +383,18 @@ where
|
|||||||
model.get(column_c),
|
model.get(column_c),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Identity::Many(cols) => {
|
||||||
|
let values = cols.iter().map(|col| {
|
||||||
|
let col_name = col.to_string();
|
||||||
|
let column = <<<Model as ModelTrait>::Entity as EntityTrait>::Column as FromStr>::from_str(
|
||||||
|
&col_name,
|
||||||
|
)
|
||||||
|
.unwrap_or_else(|_| panic!("Failed at mapping '{}' to column", col_name));
|
||||||
|
model.get(column)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
ValueTuple::Many(values)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,6 +421,12 @@ fn prepare_condition(table: &TableRef, col: &Identity, keys: &[ValueTuple]) -> C
|
|||||||
])
|
])
|
||||||
.in_tuples(keys),
|
.in_tuples(keys),
|
||||||
),
|
),
|
||||||
|
Identity::Many(cols) => {
|
||||||
|
let columns = cols
|
||||||
|
.iter()
|
||||||
|
.map(|col| SimpleExpr::Column(table_column(table, col)));
|
||||||
|
Condition::all().add(Expr::tuple(columns).in_tuples(keys))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user