Skip to main content

sea_orm/entity/
column.rs

1use crate::{
2    ColumnDef, ColumnType, DbBackend, EntityName, Iden, IdenStatic, IntoSimpleExpr, Iterable,
3};
4use sea_query::{
5    BinOper, DynIden, Expr, ExprTrait, IntoIden, IntoLikeExpr, SeaRc, SelectStatement, Value,
6};
7use std::{borrow::Cow, str::FromStr};
8
9mod types;
10pub use types::*;
11
12pub(crate) mod macros {
13    macro_rules! bind_oper {
14        ($vis:vis $op:ident, $bin_op:ident) => {
15            #[allow(missing_docs)]
16            $vis fn $op<V>(&self, v: V) -> Expr
17            where
18                V: Into<Value>,
19            {
20                let expr = self.save_as(Expr::val(v));
21                Expr::col(self.as_column_ref()).binary(BinOper::$bin_op, expr)
22            }
23        };
24    }
25
26    macro_rules! bind_func_no_params {
27        ($vis:vis $func:ident) => {
28            /// See also SeaQuery's method with same name.
29            $vis fn $func(&self) -> Expr {
30                Expr::col(self.as_column_ref()).$func()
31            }
32        };
33    }
34
35    macro_rules! bind_vec_func {
36        ($vis:vis $func:ident) => {
37            #[allow(missing_docs)]
38            #[allow(clippy::wrong_self_convention)]
39            $vis fn $func<V, I>(&self, v: I) -> Expr
40            where
41                V: Into<Value>,
42                I: IntoIterator<Item = V>,
43            {
44                let v_with_enum_cast = v.into_iter().map(|v| self.save_as(Expr::val(v)));
45                Expr::col(self.as_column_ref()).$func(v_with_enum_cast)
46            }
47        };
48    }
49
50    macro_rules! bind_subquery_func {
51        ($vis:vis $func:ident) => {
52            #[allow(clippy::wrong_self_convention)]
53            #[allow(missing_docs)]
54            $vis fn $func(&self, s: SelectStatement) -> Expr {
55                Expr::col(self.as_column_ref()).$func(s)
56            }
57        };
58    }
59
60    macro_rules! bind_array_oper {
61        ($vis:vis $op:ident, $oper:ident) => {
62            #[cfg(feature = "postgres-array")]
63            /// Array operator. Postgres only.
64            $vis fn $op<V, I>(&self, v: I) -> Expr
65            where
66                V: Into<Value> + sea_query::ValueType + sea_query::postgres_array::NotU8,
67                I: IntoIterator<Item = V>,
68            {
69                use sea_query::extension::postgres::PgBinOper;
70
71                let vec: Vec<_> = v.into_iter().collect();
72                Expr::col(self.as_column_ref()).binary(PgBinOper::$oper, self.save_as(Expr::val(vec)))
73            }
74        };
75    }
76
77    pub(crate) use bind_array_oper;
78    pub(crate) use bind_func_no_params;
79    pub(crate) use bind_oper;
80    pub(crate) use bind_subquery_func;
81    pub(crate) use bind_vec_func;
82}
83
84use macros::*;
85
86/// API for working with a `Column`. Mostly a wrapper of the identically named methods in [`sea_query::Expr`]
87pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
88    #[allow(missing_docs)]
89    type EntityName: EntityName;
90
91    /// Get the column definition with SQL attributes
92    fn def(&self) -> ColumnDef;
93
94    /// Get the enum type name if this is a enum column
95    fn enum_type_name(&self) -> Option<&'static str> {
96        None
97    }
98
99    /// Get the name of the entity the column belongs to
100    fn entity_name(&self) -> DynIden {
101        SeaRc::new(Self::EntityName::default())
102    }
103
104    /// Get the table.column reference
105    fn as_column_ref(&self) -> (DynIden, DynIden) {
106        (self.entity_name(), SeaRc::new(*self))
107    }
108
109    /// Perform equality against a Value. `None` will be converted to `IS NULL`.
110    /// ```
111    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::fruit};
112    ///
113    /// assert_eq!(
114    ///     fruit::Entity::find()
115    ///         .filter(fruit::COLUMN.cake_id.eq(2))
116    ///         .build(DbBackend::MySql)
117    ///         .to_string(),
118    ///     "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`cake_id` = 2"
119    /// );
120    /// assert_eq!(
121    ///     fruit::Entity::find()
122    ///         .filter(fruit::COLUMN.cake_id.eq(Option::<i32>::None))
123    ///         .build(DbBackend::MySql)
124    ///         .to_string(),
125    ///     "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`cake_id` IS NULL"
126    /// );
127    /// ```
128    fn eq<V>(&self, v: V) -> Expr
129    where
130        V: Into<Value>,
131    {
132        let v = v.into();
133        if v == v.as_null() {
134            Expr::col(self.as_column_ref()).is_null()
135        } else {
136            let expr = self.save_as(Expr::val(v));
137            Expr::col(self.as_column_ref()).eq(expr)
138        }
139    }
140
141    /// Perform inequality against a Value. `None` will be converted to `IS NOT NULL`.
142    /// ```
143    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::fruit};
144    ///
145    /// assert_eq!(
146    ///     fruit::Entity::find()
147    ///         .filter(fruit::COLUMN.cake_id.ne(2))
148    ///         .build(DbBackend::MySql)
149    ///         .to_string(),
150    ///     "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`cake_id` <> 2"
151    /// );
152    /// assert_eq!(
153    ///     fruit::Entity::find()
154    ///         .filter(fruit::COLUMN.cake_id.ne(Option::<i32>::None))
155    ///         .build(DbBackend::MySql)
156    ///         .to_string(),
157    ///     "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit` WHERE `fruit`.`cake_id` IS NOT NULL"
158    /// );
159    /// ```
160    fn ne<V>(&self, v: V) -> Expr
161    where
162        V: Into<Value>,
163    {
164        let v = v.into();
165        if v == v.as_null() {
166            Expr::col(self.as_column_ref()).is_not_null()
167        } else {
168            let expr = self.save_as(Expr::val(v));
169            Expr::col(self.as_column_ref()).ne(expr)
170        }
171    }
172
173    bind_oper!(gt, GreaterThan);
174    bind_oper!(gte, GreaterThanOrEqual);
175    bind_oper!(lt, SmallerThan);
176    bind_oper!(lte, SmallerThanOrEqual);
177
178    /// ```
179    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
180    ///
181    /// assert_eq!(
182    ///     cake::Entity::find()
183    ///         .filter(cake::Column::Id.between(2, 3))
184    ///         .build(DbBackend::MySql)
185    ///         .to_string(),
186    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` BETWEEN 2 AND 3"
187    /// );
188    /// ```
189    fn between<V>(&self, a: V, b: V) -> Expr
190    where
191        V: Into<Value>,
192    {
193        Expr::col(self.as_column_ref()).between(a, b)
194    }
195
196    /// ```
197    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
198    ///
199    /// assert_eq!(
200    ///     cake::Entity::find()
201    ///         .filter(cake::Column::Id.not_between(2, 3))
202    ///         .build(DbBackend::MySql)
203    ///         .to_string(),
204    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` NOT BETWEEN 2 AND 3"
205    /// );
206    /// ```
207    fn not_between<V>(&self, a: V, b: V) -> Expr
208    where
209        V: Into<Value>,
210    {
211        Expr::col(self.as_column_ref()).not_between(a, b)
212    }
213
214    /// ```
215    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
216    ///
217    /// assert_eq!(
218    ///     cake::Entity::find()
219    ///         .filter(cake::Column::Name.like("cheese"))
220    ///         .build(DbBackend::MySql)
221    ///         .to_string(),
222    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'"
223    /// );
224    /// ```
225    fn like<T>(&self, s: T) -> Expr
226    where
227        T: IntoLikeExpr,
228    {
229        Expr::col(self.as_column_ref()).like(s)
230    }
231
232    /// ```
233    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
234    ///
235    /// assert_eq!(
236    ///     cake::Entity::find()
237    ///         .filter(cake::Column::Name.not_like("cheese"))
238    ///         .build(DbBackend::MySql)
239    ///         .to_string(),
240    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'"
241    /// );
242    /// ```
243    fn not_like<T>(&self, s: T) -> Expr
244    where
245        T: IntoLikeExpr,
246    {
247        Expr::col(self.as_column_ref()).not_like(s)
248    }
249
250    /// Postgres Only.
251    /// ```
252    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
253    ///
254    /// assert_eq!(
255    ///     cake::Entity::find()
256    ///         .filter(cake::Column::Name.ilike("cheese"))
257    ///         .build(DbBackend::Postgres)
258    ///         .to_string(),
259    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."name" ILIKE 'cheese'"#
260    /// );
261    /// ```
262    fn ilike<T>(&self, s: T) -> Expr
263    where
264        T: IntoLikeExpr,
265    {
266        use sea_query::extension::postgres::PgExpr;
267
268        Expr::col(self.as_column_ref()).ilike(s)
269    }
270
271    /// Postgres Only.
272    /// ```
273    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
274    ///
275    /// assert_eq!(
276    ///     cake::Entity::find()
277    ///         .filter(cake::Column::Name.not_ilike("cheese"))
278    ///         .build(DbBackend::Postgres)
279    ///         .to_string(),
280    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."name" NOT ILIKE 'cheese'"#
281    /// );
282    /// ```
283    fn not_ilike<T>(&self, s: T) -> Expr
284    where
285        T: IntoLikeExpr,
286    {
287        use sea_query::extension::postgres::PgExpr;
288
289        Expr::col(self.as_column_ref()).not_ilike(s)
290    }
291
292    /// This is a simplified shorthand for a more general `like` method.
293    /// Use `like` if you need something more complex, like specifying an escape character.
294    ///
295    /// ## Examples
296    ///
297    /// ```
298    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
299    ///
300    /// assert_eq!(
301    ///     cake::Entity::find()
302    ///         .filter(cake::Column::Name.starts_with("cheese"))
303    ///         .build(DbBackend::MySql)
304    ///         .to_string(),
305    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'"
306    /// );
307    /// ```
308    fn starts_with<T>(&self, s: T) -> Expr
309    where
310        T: Into<String>,
311    {
312        let pattern = format!("{}%", s.into());
313        Expr::col(self.as_column_ref()).like(pattern)
314    }
315
316    /// This is a simplified shorthand for a more general `like` method.
317    /// Use `like` if you need something more complex, like specifying an escape character.
318    ///
319    /// ## Examples
320    ///
321    /// ```
322    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
323    ///
324    /// assert_eq!(
325    ///     cake::Entity::find()
326    ///         .filter(cake::Column::Name.ends_with("cheese"))
327    ///         .build(DbBackend::MySql)
328    ///         .to_string(),
329    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'"
330    /// );
331    /// ```
332    fn ends_with<T>(&self, s: T) -> Expr
333    where
334        T: Into<String>,
335    {
336        let pattern = format!("%{}", s.into());
337        Expr::col(self.as_column_ref()).like(pattern)
338    }
339
340    /// This is a simplified shorthand for a more general `like` method.
341    /// Use `like` if you need something more complex, like specifying an escape character.
342    ///
343    /// ## Examples
344    ///
345    /// ```
346    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
347    ///
348    /// assert_eq!(
349    ///     cake::Entity::find()
350    ///         .filter(cake::Column::Name.contains("cheese"))
351    ///         .build(DbBackend::MySql)
352    ///         .to_string(),
353    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
354    /// );
355    /// ```
356    fn contains<T>(&self, s: T) -> Expr
357    where
358        T: Into<String>,
359    {
360        let pattern = format!("%{}%", s.into());
361        Expr::col(self.as_column_ref()).like(pattern)
362    }
363
364    bind_func_no_params!(max);
365    bind_func_no_params!(min);
366    bind_func_no_params!(sum);
367    bind_func_no_params!(avg);
368    bind_func_no_params!(count);
369    bind_func_no_params!(is_null);
370    bind_func_no_params!(is_not_null);
371
372    /// Provide fallback value if the column is null (null coalescing)
373    fn if_null<V>(&self, v: V) -> Expr
374    where
375        V: Into<Value>,
376    {
377        Expr::col(self.as_column_ref()).if_null(v)
378    }
379
380    bind_vec_func!(is_in);
381    bind_vec_func!(is_not_in);
382
383    /// Postgres only.
384    /// ```
385    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
386    ///
387    /// // Compare with MySQL
388    /// assert_eq!(
389    ///     cake::Entity::find()
390    ///         .filter(cake::Column::Id.is_in(std::iter::empty::<i32>()))
391    ///         .build(DbBackend::MySql)
392    ///         .to_string(),
393    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE 1 = 2"
394    /// );
395    /// assert_eq!(
396    ///     cake::Entity::find()
397    ///         .filter(cake::Column::Id.is_in(vec![4, 5]))
398    ///         .build(DbBackend::MySql)
399    ///         .to_string(),
400    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` IN (4, 5)"
401    /// );
402    /// // Postgres Array
403    /// assert_eq!(
404    ///     cake::Entity::find()
405    ///         .filter(cake::Column::Id.eq_any(std::iter::empty::<i32>()))
406    ///         .build(DbBackend::Postgres)
407    ///         .to_string(),
408    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE 1 = 2"#
409    /// );
410    /// assert_eq!(
411    ///     cake::Entity::find()
412    ///         .filter(cake::Column::Id.eq_any(vec![4, 5]))
413    ///         .build(DbBackend::Postgres)
414    ///         .to_string(),
415    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = ANY(ARRAY [4,5])"#
416    /// );
417    /// assert_eq!(
418    ///     cake::Entity::find()
419    ///         .filter(cake::Column::Name.eq_any(&["Apple".to_owned(), "Chocolate".to_owned()]))
420    ///         .build(DbBackend::Postgres)
421    ///         .to_string(),
422    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."name" = ANY(ARRAY ['Apple','Chocolate'])"#
423    /// );
424    /// ```
425    #[cfg(feature = "postgres-array")]
426    fn eq_any<V, I>(&self, v: I) -> Expr
427    where
428        V: Into<Value> + sea_query::postgres_array::NotU8,
429        I: IntoIterator<Item = V>,
430    {
431        use sea_query::extension::postgres::PgFunc;
432
433        let values: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
434
435        if let Some(first) = values.first() {
436            Expr::col(self.as_column_ref()).eq(PgFunc::any(Value::Array(
437                first.array_type(),
438                Some(Box::new(values)),
439            )))
440        } else {
441            Expr::col(self.as_column_ref()).is_in(std::iter::empty::<V>())
442        }
443    }
444
445    /// Postgres only. Opposite of `eq_any` (equivalent to `is_not_in`).
446    /// ```
447    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
448    ///
449    /// assert_eq!(
450    ///     cake::Entity::find()
451    ///         .filter(cake::Column::Id.ne_all(std::iter::empty::<i32>()))
452    ///         .build(DbBackend::Postgres)
453    ///         .to_string(),
454    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE 1 = 1"#
455    /// );
456    /// assert_eq!(
457    ///     cake::Entity::find()
458    ///         .filter(cake::Column::Id.ne_all(vec![4, 5]))
459    ///         .build(DbBackend::Postgres)
460    ///         .to_string(),
461    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" <> ALL(ARRAY [4,5])"#
462    /// );
463    /// ```
464    #[cfg(feature = "postgres-array")]
465    fn ne_all<V, I>(&self, v: I) -> Expr
466    where
467        V: Into<Value> + sea_query::postgres_array::NotU8,
468        I: IntoIterator<Item = V>,
469    {
470        use sea_query::extension::postgres::PgFunc;
471
472        let values: Vec<Value> = v.into_iter().map(|v| v.into()).collect();
473
474        if let Some(first) = values.first() {
475            Expr::col(self.as_column_ref()).ne(PgFunc::all(Value::Array(
476                first.array_type(),
477                Some(Box::new(values)),
478            )))
479        } else {
480            Expr::col(self.as_column_ref()).is_not_in(std::iter::empty::<V>())
481        }
482    }
483
484    bind_subquery_func!(in_subquery);
485    bind_subquery_func!(not_in_subquery);
486
487    bind_array_oper!(array_contains, Contains);
488    bind_array_oper!(array_contained, Contained);
489    bind_array_oper!(array_overlap, Overlap);
490
491    /// Construct a [`Expr::Column`] wrapped in [`Expr`].
492    fn into_expr(self) -> Expr {
493        self.into_simple_expr()
494    }
495
496    /// Construct a returning [`Expr`].
497    #[allow(clippy::match_single_binding)]
498    fn into_returning_expr(self, db_backend: DbBackend) -> Expr {
499        match db_backend {
500            _ => Expr::col(self),
501        }
502    }
503
504    /// Cast column expression used in select statement.
505    /// It only cast database enum as text if it's an enum column.
506    fn select_as(&self, expr: Expr) -> Expr {
507        self.select_enum_as(expr)
508    }
509
510    /// Cast enum column as text; do nothing if `self` is not an enum.
511    fn select_enum_as(&self, expr: Expr) -> Expr {
512        cast_enum_as(expr, &self.def(), select_enum_as)
513    }
514
515    /// Cast value of a column into the correct type for database storage.
516    /// By default, it only cast text as enum type if it's an enum column.
517    fn save_as(&self, val: Expr) -> Expr {
518        self.save_enum_as(val)
519    }
520
521    /// Cast value of an enum column as enum type; do nothing if `self` is not an enum.
522    fn save_enum_as(&self, val: Expr) -> Expr {
523        cast_enum_as(val, &self.def(), save_enum_as)
524    }
525
526    /// Get the JSON key for deserialization.
527    #[cfg(feature = "with-json")]
528    fn json_key(&self) -> &'static str {
529        self.as_str()
530    }
531}
532
533/// SeaORM's utility methods that act on [ColumnType]
534pub trait ColumnTypeTrait {
535    /// Instantiate a new [ColumnDef]
536    fn def(self) -> ColumnDef;
537
538    /// Get the name of the enum if this is a enum column
539    fn get_enum_name(&self) -> Option<&DynIden>;
540}
541
542impl ColumnTypeTrait for ColumnType {
543    fn def(self) -> ColumnDef {
544        ColumnDef {
545            col_type: self,
546            null: false,
547            unique: false,
548            indexed: false,
549            default: None,
550            comment: None,
551            unique_key: None,
552            renamed_from: None,
553            extra: None,
554            seaography: Default::default(),
555        }
556    }
557
558    fn get_enum_name(&self) -> Option<&DynIden> {
559        enum_name(self)
560    }
561}
562
563impl ColumnTypeTrait for ColumnDef {
564    fn def(self) -> ColumnDef {
565        self
566    }
567
568    fn get_enum_name(&self) -> Option<&DynIden> {
569        enum_name(&self.col_type)
570    }
571}
572
573fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
574    match col_type {
575        ColumnType::Enum { name, .. } => Some(name),
576        ColumnType::Array(col_type) => enum_name(col_type),
577        _ => None,
578    }
579}
580
581struct Text;
582struct TextArray;
583
584impl Iden for Text {
585    fn quoted(&self) -> Cow<'static, str> {
586        Cow::Borrowed("text")
587    }
588
589    fn unquoted(&self) -> &str {
590        match self.quoted() {
591            Cow::Borrowed(s) => s,
592            _ => unreachable!(),
593        }
594    }
595}
596
597impl Iden for TextArray {
598    fn quoted(&self) -> Cow<'static, str> {
599        // This is Postgres only and it has a special handling for quoting this
600        Cow::Borrowed("text[]")
601    }
602
603    fn unquoted(&self) -> &str {
604        match self.quoted() {
605            Cow::Borrowed(s) => s,
606            _ => unreachable!(),
607        }
608    }
609}
610
611pub(crate) fn select_enum_as(col: Expr, _: DynIden, col_type: &ColumnType) -> Expr {
612    let type_name = match col_type {
613        ColumnType::Array(_) => TextArray.into_iden(),
614        _ => Text.into_iden(),
615    };
616    col.as_enum(type_name)
617}
618
619pub(crate) fn save_enum_as(col: Expr, enum_name: DynIden, col_type: &ColumnType) -> Expr {
620    let type_name = match col_type {
621        ColumnType::Array(_) => format!("{enum_name}[]").into_iden(),
622        _ => enum_name,
623    };
624    col.as_enum(type_name)
625}
626
627pub(crate) fn cast_enum_as<F>(expr: Expr, col_def: &ColumnDef, f: F) -> Expr
628where
629    F: Fn(Expr, DynIden, &ColumnType) -> Expr,
630{
631    let col_type = col_def.get_column_type();
632
633    match col_type {
634        #[cfg(all(feature = "with-json", feature = "postgres-array"))]
635        ColumnType::Json | ColumnType::JsonBinary => {
636            use sea_query::ArrayType;
637            use serde_json::Value as Json;
638
639            match expr {
640                Expr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
641                    // flatten Array(Vec<Json>) into Json
642                    let json_vec: Vec<Json> = json_vec
643                        .into_iter()
644                        .filter_map(|val| match val {
645                            Value::Json(Some(json)) => Some(*json),
646                            _ => None,
647                        })
648                        .collect();
649                    Expr::Value(Value::Json(Some(Box::new(json_vec.into()))))
650                }
651                Expr::Value(Value::Array(ArrayType::Json, None)) => Expr::Value(Value::Json(None)),
652                _ => expr,
653            }
654        }
655        _ => match col_type.get_enum_name() {
656            Some(enum_name) => f(expr, enum_name.clone(), col_type),
657            None => expr,
658        },
659    }
660}
661
662#[cfg(test)]
663mod tests {
664    use crate::{
665        ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, tests_cfg::*,
666    };
667    use sea_query::Query;
668
669    #[test]
670    fn test_in_subquery_1() {
671        assert_eq!(
672            cake::Entity::find()
673                .filter(
674                    Condition::any().add(
675                        cake::Column::Id.in_subquery(
676                            Query::select()
677                                .expr(cake::Column::Id.max())
678                                .from(cake::Entity)
679                                .to_owned()
680                        )
681                    )
682                )
683                .build(DbBackend::MySql)
684                .to_string(),
685            [
686                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
687                "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
688            ]
689            .join(" ")
690        );
691    }
692
693    #[test]
694    fn test_in_subquery_2() {
695        assert_eq!(
696            cake::Entity::find()
697                .filter(
698                    Condition::any().add(
699                        cake::Column::Id.in_subquery(
700                            Query::select()
701                                .column(cake_filling::Column::CakeId)
702                                .from(cake_filling::Entity)
703                                .to_owned()
704                        )
705                    )
706                )
707                .build(DbBackend::MySql)
708                .to_string(),
709            [
710                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
711                "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
712            ]
713            .join(" ")
714        );
715    }
716
717    #[test]
718    #[cfg(feature = "macros")]
719    fn select_as_1() {
720        use crate::{ActiveModelTrait, ActiveValue, Update};
721
722        mod hello_expanded {
723            use crate as sea_orm;
724            use crate::entity::prelude::*;
725            use crate::sea_query::{Expr, ExprTrait};
726
727            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
728            pub struct Entity;
729
730            impl EntityName for Entity {
731                fn table_name(&self) -> &'static str {
732                    "hello"
733                }
734            }
735
736            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
737            pub struct Model {
738                pub id: i32,
739                #[sea_orm(enum_name = "One1")]
740                pub one: i32,
741                pub two: i32,
742                #[sea_orm(enum_name = "Three3")]
743                pub three: i32,
744            }
745
746            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
747            pub enum Column {
748                Id,
749                One1,
750                Two,
751                Three3,
752            }
753
754            impl ColumnTrait for Column {
755                type EntityName = Entity;
756
757                fn def(&self) -> ColumnDef {
758                    match self {
759                        Column::Id => ColumnType::Integer.def(),
760                        Column::One1 => ColumnType::Integer.def(),
761                        Column::Two => ColumnType::Integer.def(),
762                        Column::Three3 => ColumnType::Integer.def(),
763                    }
764                }
765
766                fn select_as(&self, expr: Expr) -> Expr {
767                    match self {
768                        Self::Two => expr.cast_as("integer"),
769                        _ => self.select_enum_as(expr),
770                    }
771                }
772            }
773
774            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
775            pub enum PrimaryKey {
776                Id,
777            }
778
779            impl PrimaryKeyTrait for PrimaryKey {
780                type ValueType = i32;
781
782                fn auto_increment() -> bool {
783                    true
784                }
785            }
786
787            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
788            pub enum Relation {}
789
790            impl ActiveModelBehavior for ActiveModel {}
791        }
792
793        #[allow(clippy::enum_variant_names)]
794        mod hello_compact {
795            use crate as sea_orm;
796            use crate::entity::prelude::*;
797
798            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
799            #[sea_orm(table_name = "hello")]
800            pub struct Model {
801                #[sea_orm(primary_key)]
802                pub id: i32,
803                #[sea_orm(enum_name = "One1")]
804                pub one: i32,
805                #[sea_orm(select_as = "integer")]
806                pub two: i32,
807                #[sea_orm(enum_name = "Three3")]
808                pub three: i32,
809            }
810
811            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
812            pub enum Relation {}
813
814            impl ActiveModelBehavior for ActiveModel {}
815        }
816
817        fn assert_it<E, A>(active_model: A)
818        where
819            E: EntityTrait,
820            A: ActiveModelTrait<Entity = E>,
821        {
822            assert_eq!(
823                E::find().build(DbBackend::Postgres).to_string(),
824                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
825            );
826            assert_eq!(
827                Update::one(active_model)
828                    .validate()
829                    .unwrap()
830                    .build(DbBackend::Postgres)
831                    .to_string(),
832                r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
833            );
834        }
835
836        assert_it(hello_expanded::ActiveModel {
837            id: ActiveValue::set(1),
838            one: ActiveValue::set(1),
839            two: ActiveValue::set(2),
840            three: ActiveValue::set(3),
841        });
842        assert_it(hello_compact::ActiveModel {
843            id: ActiveValue::set(1),
844            one: ActiveValue::set(1),
845            two: ActiveValue::set(2),
846            three: ActiveValue::set(3),
847        });
848    }
849
850    #[test]
851    #[cfg(feature = "macros")]
852    fn save_as_1() {
853        use crate::{ActiveModelTrait, ActiveValue, Update};
854
855        mod hello_expanded {
856            use crate as sea_orm;
857            use crate::entity::prelude::*;
858            use crate::sea_query::{Expr, ExprTrait};
859
860            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
861            pub struct Entity;
862
863            impl EntityName for Entity {
864                fn table_name(&self) -> &'static str {
865                    "hello"
866                }
867            }
868
869            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
870            pub struct Model {
871                pub id: i32,
872                #[sea_orm(enum_name = "One1")]
873                pub one: i32,
874                pub two: i32,
875                #[sea_orm(enum_name = "Three3")]
876                pub three: i32,
877            }
878
879            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
880            pub enum Column {
881                Id,
882                One1,
883                Two,
884                Three3,
885            }
886
887            impl ColumnTrait for Column {
888                type EntityName = Entity;
889
890                fn def(&self) -> ColumnDef {
891                    match self {
892                        Column::Id => ColumnType::Integer.def(),
893                        Column::One1 => ColumnType::Integer.def(),
894                        Column::Two => ColumnType::Integer.def(),
895                        Column::Three3 => ColumnType::Integer.def(),
896                    }
897                }
898
899                fn save_as(&self, val: Expr) -> Expr {
900                    match self {
901                        Self::Two => val.cast_as("text"),
902                        _ => self.save_enum_as(val),
903                    }
904                }
905            }
906
907            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
908            pub enum PrimaryKey {
909                Id,
910            }
911
912            impl PrimaryKeyTrait for PrimaryKey {
913                type ValueType = i32;
914
915                fn auto_increment() -> bool {
916                    true
917                }
918            }
919
920            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
921            pub enum Relation {}
922
923            impl ActiveModelBehavior for ActiveModel {}
924        }
925
926        #[allow(clippy::enum_variant_names)]
927        mod hello_compact {
928            use crate as sea_orm;
929            use crate::entity::prelude::*;
930
931            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
932            #[sea_orm(table_name = "hello")]
933            pub struct Model {
934                #[sea_orm(primary_key)]
935                pub id: i32,
936                #[sea_orm(enum_name = "One1")]
937                pub one: i32,
938                #[sea_orm(save_as = "text")]
939                pub two: i32,
940                #[sea_orm(enum_name = "Three3")]
941                pub three: i32,
942            }
943
944            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
945            pub enum Relation {}
946
947            impl ActiveModelBehavior for ActiveModel {}
948        }
949
950        fn assert_it<E, A>(active_model: A)
951        where
952            E: EntityTrait,
953            A: ActiveModelTrait<Entity = E>,
954        {
955            assert_eq!(
956                E::find().build(DbBackend::Postgres).to_string(),
957                r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
958            );
959            assert_eq!(
960                Update::one(active_model)
961                    .validate()
962                    .unwrap()
963                    .build(DbBackend::Postgres)
964                    .to_string(),
965                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
966            );
967        }
968
969        assert_it(hello_expanded::ActiveModel {
970            id: ActiveValue::set(1),
971            one: ActiveValue::set(1),
972            two: ActiveValue::set(2),
973            three: ActiveValue::set(3),
974        });
975        assert_it(hello_compact::ActiveModel {
976            id: ActiveValue::set(1),
977            one: ActiveValue::set(1),
978            two: ActiveValue::set(2),
979            three: ActiveValue::set(3),
980        });
981    }
982
983    #[test]
984    #[cfg(feature = "macros")]
985    fn select_as_and_value_1() {
986        use crate::{ActiveModelTrait, ActiveValue, Update};
987
988        mod hello_expanded {
989            use crate as sea_orm;
990            use crate::entity::prelude::*;
991            use crate::sea_query::{Expr, ExprTrait};
992
993            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
994            pub struct Entity;
995
996            impl EntityName for Entity {
997                fn table_name(&self) -> &'static str {
998                    "hello"
999                }
1000            }
1001
1002            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1003            pub struct Model {
1004                pub id: i32,
1005                #[sea_orm(enum_name = "One1")]
1006                pub one: i32,
1007                pub two: i32,
1008                #[sea_orm(enum_name = "Three3")]
1009                pub three: i32,
1010            }
1011
1012            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1013            pub enum Column {
1014                Id,
1015                One1,
1016                Two,
1017                Three3,
1018            }
1019
1020            impl ColumnTrait for Column {
1021                type EntityName = Entity;
1022
1023                fn def(&self) -> ColumnDef {
1024                    match self {
1025                        Column::Id => ColumnType::Integer.def(),
1026                        Column::One1 => ColumnType::Integer.def(),
1027                        Column::Two => ColumnType::Integer.def(),
1028                        Column::Three3 => ColumnType::Integer.def(),
1029                    }
1030                }
1031
1032                fn select_as(&self, expr: Expr) -> Expr {
1033                    match self {
1034                        Self::Two => expr.cast_as("integer"),
1035                        _ => self.select_enum_as(expr),
1036                    }
1037                }
1038
1039                fn save_as(&self, val: Expr) -> Expr {
1040                    match self {
1041                        Self::Two => val.cast_as("text"),
1042                        _ => self.save_enum_as(val),
1043                    }
1044                }
1045            }
1046
1047            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1048            pub enum PrimaryKey {
1049                Id,
1050            }
1051
1052            impl PrimaryKeyTrait for PrimaryKey {
1053                type ValueType = i32;
1054
1055                fn auto_increment() -> bool {
1056                    true
1057                }
1058            }
1059
1060            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1061            pub enum Relation {}
1062
1063            impl ActiveModelBehavior for ActiveModel {}
1064        }
1065
1066        #[allow(clippy::enum_variant_names)]
1067        mod hello_compact {
1068            use crate as sea_orm;
1069            use crate::entity::prelude::*;
1070
1071            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1072            #[sea_orm(table_name = "hello")]
1073            pub struct Model {
1074                #[sea_orm(primary_key)]
1075                pub id: i32,
1076                #[sea_orm(enum_name = "One1")]
1077                pub one: i32,
1078                #[sea_orm(select_as = "integer", save_as = "text")]
1079                pub two: i32,
1080                #[sea_orm(enum_name = "Three3")]
1081                pub three: i32,
1082            }
1083
1084            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1085            pub enum Relation {}
1086
1087            impl ActiveModelBehavior for ActiveModel {}
1088        }
1089
1090        fn assert_it<E, A>(active_model: A)
1091        where
1092            E: EntityTrait,
1093            A: ActiveModelTrait<Entity = E>,
1094        {
1095            assert_eq!(
1096                E::find().build(DbBackend::Postgres).to_string(),
1097                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
1098            );
1099            assert_eq!(
1100                Update::one(active_model)
1101                    .validate()
1102                    .unwrap()
1103                    .build(DbBackend::Postgres)
1104                    .to_string(),
1105                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1106            );
1107        }
1108
1109        assert_it(hello_expanded::ActiveModel {
1110            id: ActiveValue::set(1),
1111            one: ActiveValue::set(1),
1112            two: ActiveValue::set(2),
1113            three: ActiveValue::set(3),
1114        });
1115        assert_it(hello_compact::ActiveModel {
1116            id: ActiveValue::set(1),
1117            one: ActiveValue::set(1),
1118            two: ActiveValue::set(2),
1119            three: ActiveValue::set(3),
1120        });
1121    }
1122}