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    if matches!(col, Expr::Value(Value::Enum(_))) {
621        return col;
622    }
623    #[cfg(feature = "postgres-array")]
624    if matches!(
625        col,
626        Expr::Value(Value::Array(sea_query::ArrayType::Enum(_), _))
627    ) {
628        return col;
629    }
630
631    let type_name = match col_type {
632        ColumnType::Array(_) => format!("{enum_name}[]").into_iden(),
633        _ => enum_name,
634    };
635    col.as_enum(type_name)
636}
637
638pub(crate) fn cast_enum_as<F>(expr: Expr, col_def: &ColumnDef, f: F) -> Expr
639where
640    F: Fn(Expr, DynIden, &ColumnType) -> Expr,
641{
642    let col_type = col_def.get_column_type();
643
644    match col_type {
645        #[cfg(all(feature = "with-json", feature = "postgres-array"))]
646        ColumnType::Json | ColumnType::JsonBinary => {
647            use sea_query::ArrayType;
648            use serde_json::Value as Json;
649
650            match expr {
651                Expr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
652                    // flatten Array(Vec<Json>) into Json
653                    let json_vec: Vec<Json> = json_vec
654                        .into_iter()
655                        .filter_map(|val| match val {
656                            Value::Json(Some(json)) => Some(*json),
657                            _ => None,
658                        })
659                        .collect();
660                    Expr::Value(Value::Json(Some(Box::new(json_vec.into()))))
661                }
662                Expr::Value(Value::Array(ArrayType::Json, None)) => Expr::Value(Value::Json(None)),
663                _ => expr,
664            }
665        }
666        _ => match col_type.get_enum_name() {
667            Some(enum_name) => f(expr, enum_name.clone(), col_type),
668            None => expr,
669        },
670    }
671}
672
673#[cfg(test)]
674mod tests {
675    use crate::{
676        ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, tests_cfg::*,
677    };
678    use sea_query::Query;
679
680    #[test]
681    fn test_in_subquery_1() {
682        assert_eq!(
683            cake::Entity::find()
684                .filter(
685                    Condition::any().add(
686                        cake::Column::Id.in_subquery(
687                            Query::select()
688                                .expr(cake::Column::Id.max())
689                                .from(cake::Entity)
690                                .to_owned()
691                        )
692                    )
693                )
694                .build(DbBackend::MySql)
695                .to_string(),
696            [
697                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
698                "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
699            ]
700            .join(" ")
701        );
702    }
703
704    #[test]
705    fn test_in_subquery_2() {
706        assert_eq!(
707            cake::Entity::find()
708                .filter(
709                    Condition::any().add(
710                        cake::Column::Id.in_subquery(
711                            Query::select()
712                                .column(cake_filling::Column::CakeId)
713                                .from(cake_filling::Entity)
714                                .to_owned()
715                        )
716                    )
717                )
718                .build(DbBackend::MySql)
719                .to_string(),
720            [
721                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
722                "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
723            ]
724            .join(" ")
725        );
726    }
727
728    #[test]
729    #[cfg(feature = "macros")]
730    fn select_as_1() {
731        use crate::{ActiveModelTrait, ActiveValue, Update};
732
733        mod hello_expanded {
734            use crate as sea_orm;
735            use crate::entity::prelude::*;
736            use crate::sea_query::{Expr, ExprTrait};
737
738            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
739            pub struct Entity;
740
741            impl EntityName for Entity {
742                fn table_name(&self) -> &'static str {
743                    "hello"
744                }
745            }
746
747            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
748            pub struct Model {
749                pub id: i32,
750                #[sea_orm(enum_name = "One1")]
751                pub one: i32,
752                pub two: i32,
753                #[sea_orm(enum_name = "Three3")]
754                pub three: i32,
755            }
756
757            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
758            pub enum Column {
759                Id,
760                One1,
761                Two,
762                Three3,
763            }
764
765            impl ColumnTrait for Column {
766                type EntityName = Entity;
767
768                fn def(&self) -> ColumnDef {
769                    match self {
770                        Column::Id => ColumnType::Integer.def(),
771                        Column::One1 => ColumnType::Integer.def(),
772                        Column::Two => ColumnType::Integer.def(),
773                        Column::Three3 => ColumnType::Integer.def(),
774                    }
775                }
776
777                fn select_as(&self, expr: Expr) -> Expr {
778                    match self {
779                        Self::Two => expr.cast_as("integer"),
780                        _ => self.select_enum_as(expr),
781                    }
782                }
783            }
784
785            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
786            pub enum PrimaryKey {
787                Id,
788            }
789
790            impl PrimaryKeyTrait for PrimaryKey {
791                type ValueType = i32;
792
793                fn auto_increment() -> bool {
794                    true
795                }
796            }
797
798            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
799            pub enum Relation {}
800
801            impl ActiveModelBehavior for ActiveModel {}
802        }
803
804        #[allow(clippy::enum_variant_names)]
805        mod hello_compact {
806            use crate as sea_orm;
807            use crate::entity::prelude::*;
808
809            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
810            #[sea_orm(table_name = "hello")]
811            pub struct Model {
812                #[sea_orm(primary_key)]
813                pub id: i32,
814                #[sea_orm(enum_name = "One1")]
815                pub one: i32,
816                #[sea_orm(select_as = "integer")]
817                pub two: i32,
818                #[sea_orm(enum_name = "Three3")]
819                pub three: i32,
820            }
821
822            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
823            pub enum Relation {}
824
825            impl ActiveModelBehavior for ActiveModel {}
826        }
827
828        fn assert_it<E, A>(active_model: A)
829        where
830            E: EntityTrait,
831            A: ActiveModelTrait<Entity = E>,
832        {
833            assert_eq!(
834                E::find().build(DbBackend::Postgres).to_string(),
835                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
836            );
837            assert_eq!(
838                Update::one(active_model)
839                    .validate()
840                    .unwrap()
841                    .build(DbBackend::Postgres)
842                    .to_string(),
843                r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
844            );
845        }
846
847        assert_it(hello_expanded::ActiveModel {
848            id: ActiveValue::set(1),
849            one: ActiveValue::set(1),
850            two: ActiveValue::set(2),
851            three: ActiveValue::set(3),
852        });
853        assert_it(hello_compact::ActiveModel {
854            id: ActiveValue::set(1),
855            one: ActiveValue::set(1),
856            two: ActiveValue::set(2),
857            three: ActiveValue::set(3),
858        });
859    }
860
861    #[test]
862    #[cfg(feature = "macros")]
863    fn save_as_1() {
864        use crate::{ActiveModelTrait, ActiveValue, Update};
865
866        mod hello_expanded {
867            use crate as sea_orm;
868            use crate::entity::prelude::*;
869            use crate::sea_query::{Expr, ExprTrait};
870
871            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
872            pub struct Entity;
873
874            impl EntityName for Entity {
875                fn table_name(&self) -> &'static str {
876                    "hello"
877                }
878            }
879
880            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
881            pub struct Model {
882                pub id: i32,
883                #[sea_orm(enum_name = "One1")]
884                pub one: i32,
885                pub two: i32,
886                #[sea_orm(enum_name = "Three3")]
887                pub three: i32,
888            }
889
890            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
891            pub enum Column {
892                Id,
893                One1,
894                Two,
895                Three3,
896            }
897
898            impl ColumnTrait for Column {
899                type EntityName = Entity;
900
901                fn def(&self) -> ColumnDef {
902                    match self {
903                        Column::Id => ColumnType::Integer.def(),
904                        Column::One1 => ColumnType::Integer.def(),
905                        Column::Two => ColumnType::Integer.def(),
906                        Column::Three3 => ColumnType::Integer.def(),
907                    }
908                }
909
910                fn save_as(&self, val: Expr) -> Expr {
911                    match self {
912                        Self::Two => val.cast_as("text"),
913                        _ => self.save_enum_as(val),
914                    }
915                }
916            }
917
918            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
919            pub enum PrimaryKey {
920                Id,
921            }
922
923            impl PrimaryKeyTrait for PrimaryKey {
924                type ValueType = i32;
925
926                fn auto_increment() -> bool {
927                    true
928                }
929            }
930
931            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
932            pub enum Relation {}
933
934            impl ActiveModelBehavior for ActiveModel {}
935        }
936
937        #[allow(clippy::enum_variant_names)]
938        mod hello_compact {
939            use crate as sea_orm;
940            use crate::entity::prelude::*;
941
942            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
943            #[sea_orm(table_name = "hello")]
944            pub struct Model {
945                #[sea_orm(primary_key)]
946                pub id: i32,
947                #[sea_orm(enum_name = "One1")]
948                pub one: i32,
949                #[sea_orm(save_as = "text")]
950                pub two: i32,
951                #[sea_orm(enum_name = "Three3")]
952                pub three: i32,
953            }
954
955            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
956            pub enum Relation {}
957
958            impl ActiveModelBehavior for ActiveModel {}
959        }
960
961        fn assert_it<E, A>(active_model: A)
962        where
963            E: EntityTrait,
964            A: ActiveModelTrait<Entity = E>,
965        {
966            assert_eq!(
967                E::find().build(DbBackend::Postgres).to_string(),
968                r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
969            );
970            assert_eq!(
971                Update::one(active_model)
972                    .validate()
973                    .unwrap()
974                    .build(DbBackend::Postgres)
975                    .to_string(),
976                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
977            );
978        }
979
980        assert_it(hello_expanded::ActiveModel {
981            id: ActiveValue::set(1),
982            one: ActiveValue::set(1),
983            two: ActiveValue::set(2),
984            three: ActiveValue::set(3),
985        });
986        assert_it(hello_compact::ActiveModel {
987            id: ActiveValue::set(1),
988            one: ActiveValue::set(1),
989            two: ActiveValue::set(2),
990            three: ActiveValue::set(3),
991        });
992    }
993
994    #[test]
995    #[cfg(feature = "macros")]
996    fn select_as_and_value_1() {
997        use crate::{ActiveModelTrait, ActiveValue, Update};
998
999        mod hello_expanded {
1000            use crate as sea_orm;
1001            use crate::entity::prelude::*;
1002            use crate::sea_query::{Expr, ExprTrait};
1003
1004            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1005            pub struct Entity;
1006
1007            impl EntityName for Entity {
1008                fn table_name(&self) -> &'static str {
1009                    "hello"
1010                }
1011            }
1012
1013            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1014            pub struct Model {
1015                pub id: i32,
1016                #[sea_orm(enum_name = "One1")]
1017                pub one: i32,
1018                pub two: i32,
1019                #[sea_orm(enum_name = "Three3")]
1020                pub three: i32,
1021            }
1022
1023            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1024            pub enum Column {
1025                Id,
1026                One1,
1027                Two,
1028                Three3,
1029            }
1030
1031            impl ColumnTrait for Column {
1032                type EntityName = Entity;
1033
1034                fn def(&self) -> ColumnDef {
1035                    match self {
1036                        Column::Id => ColumnType::Integer.def(),
1037                        Column::One1 => ColumnType::Integer.def(),
1038                        Column::Two => ColumnType::Integer.def(),
1039                        Column::Three3 => ColumnType::Integer.def(),
1040                    }
1041                }
1042
1043                fn select_as(&self, expr: Expr) -> Expr {
1044                    match self {
1045                        Self::Two => expr.cast_as("integer"),
1046                        _ => self.select_enum_as(expr),
1047                    }
1048                }
1049
1050                fn save_as(&self, val: Expr) -> Expr {
1051                    match self {
1052                        Self::Two => val.cast_as("text"),
1053                        _ => self.save_enum_as(val),
1054                    }
1055                }
1056            }
1057
1058            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1059            pub enum PrimaryKey {
1060                Id,
1061            }
1062
1063            impl PrimaryKeyTrait for PrimaryKey {
1064                type ValueType = i32;
1065
1066                fn auto_increment() -> bool {
1067                    true
1068                }
1069            }
1070
1071            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1072            pub enum Relation {}
1073
1074            impl ActiveModelBehavior for ActiveModel {}
1075        }
1076
1077        #[allow(clippy::enum_variant_names)]
1078        mod hello_compact {
1079            use crate as sea_orm;
1080            use crate::entity::prelude::*;
1081
1082            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1083            #[sea_orm(table_name = "hello")]
1084            pub struct Model {
1085                #[sea_orm(primary_key)]
1086                pub id: i32,
1087                #[sea_orm(enum_name = "One1")]
1088                pub one: i32,
1089                #[sea_orm(select_as = "integer", save_as = "text")]
1090                pub two: i32,
1091                #[sea_orm(enum_name = "Three3")]
1092                pub three: i32,
1093            }
1094
1095            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1096            pub enum Relation {}
1097
1098            impl ActiveModelBehavior for ActiveModel {}
1099        }
1100
1101        fn assert_it<E, A>(active_model: A)
1102        where
1103            E: EntityTrait,
1104            A: ActiveModelTrait<Entity = E>,
1105        {
1106            assert_eq!(
1107                E::find().build(DbBackend::Postgres).to_string(),
1108                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
1109            );
1110            assert_eq!(
1111                Update::one(active_model)
1112                    .validate()
1113                    .unwrap()
1114                    .build(DbBackend::Postgres)
1115                    .to_string(),
1116                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1117            );
1118        }
1119
1120        assert_it(hello_expanded::ActiveModel {
1121            id: ActiveValue::set(1),
1122            one: ActiveValue::set(1),
1123            two: ActiveValue::set(2),
1124            three: ActiveValue::set(3),
1125        });
1126        assert_it(hello_compact::ActiveModel {
1127            id: ActiveValue::set(1),
1128            one: ActiveValue::set(1),
1129            two: ActiveValue::set(2),
1130            three: ActiveValue::set(3),
1131        });
1132    }
1133}