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