sea_orm/entity/
column.rs

1use crate::{
2    ColumnDef, ColumnType, DbBackend, EntityName, Iden, IdenStatic, IntoSimpleExpr, Iterable,
3};
4use sea_query::{
5    Alias, BinOper, DynIden, Expr, ExprTrait, IntoIden, IntoLikeExpr, SeaRc, SelectStatement,
6    SimpleExpr, Value,
7};
8use std::{borrow::Cow, str::FromStr};
9
10macro_rules! bind_oper {
11    ( $op: ident, $bin_op: ident ) => {
12        #[allow(missing_docs)]
13        fn $op<V>(&self, v: V) -> SimpleExpr
14        where
15            V: Into<Value>,
16        {
17            let expr = self.save_as(Expr::val(v));
18            Expr::col((self.entity_name(), *self)).binary(BinOper::$bin_op, expr)
19        }
20    };
21}
22
23macro_rules! bind_func_no_params {
24    ( $func: ident ) => {
25        /// See also SeaQuery's method with same name.
26        fn $func(&self) -> SimpleExpr {
27            Expr::col((self.entity_name(), *self)).$func()
28        }
29    };
30}
31
32macro_rules! bind_vec_func {
33    ( $func: ident ) => {
34        #[allow(missing_docs)]
35        #[allow(clippy::wrong_self_convention)]
36        fn $func<V, I>(&self, v: I) -> SimpleExpr
37        where
38            V: Into<Value>,
39            I: IntoIterator<Item = V>,
40        {
41            let v_with_enum_cast = v.into_iter().map(|v| self.save_as(Expr::val(v)));
42            Expr::col((self.entity_name(), *self)).$func(v_with_enum_cast)
43        }
44    };
45}
46
47macro_rules! bind_subquery_func {
48    ( $func: ident ) => {
49        #[allow(clippy::wrong_self_convention)]
50        #[allow(missing_docs)]
51        fn $func(&self, s: SelectStatement) -> SimpleExpr {
52            Expr::col((self.entity_name(), *self)).$func(s)
53        }
54    };
55}
56
57// LINT: when the operand value does not match column type
58/// API for working with a `Column`. Mostly a wrapper of the identically named methods in [`sea_query::Expr`]
59pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
60    #[allow(missing_docs)]
61    type EntityName: EntityName;
62
63    /// Define a column for an Entity
64    fn def(&self) -> ColumnDef;
65
66    /// Get the enum name of the column type
67    fn enum_type_name(&self) -> Option<&'static str> {
68        None
69    }
70
71    /// Get the name of the entity the column belongs to
72    fn entity_name(&self) -> DynIden {
73        SeaRc::new(Self::EntityName::default())
74    }
75
76    /// get the name of the entity the column belongs to
77    fn as_column_ref(&self) -> (DynIden, DynIden) {
78        (self.entity_name(), SeaRc::new(*self))
79    }
80
81    bind_oper!(eq, Equal);
82    bind_oper!(ne, NotEqual);
83    bind_oper!(gt, GreaterThan);
84    bind_oper!(gte, GreaterThanOrEqual);
85    bind_oper!(lt, SmallerThan);
86    bind_oper!(lte, SmallerThanOrEqual);
87
88    /// ```
89    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
90    ///
91    /// assert_eq!(
92    ///     cake::Entity::find()
93    ///         .filter(cake::Column::Id.between(2, 3))
94    ///         .build(DbBackend::MySql)
95    ///         .to_string(),
96    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` BETWEEN 2 AND 3"
97    /// );
98    /// ```
99    fn between<V>(&self, a: V, b: V) -> SimpleExpr
100    where
101        V: Into<Value>,
102    {
103        Expr::col((self.entity_name(), *self)).between(a, b)
104    }
105
106    /// ```
107    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
108    ///
109    /// assert_eq!(
110    ///     cake::Entity::find()
111    ///         .filter(cake::Column::Id.not_between(2, 3))
112    ///         .build(DbBackend::MySql)
113    ///         .to_string(),
114    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` NOT BETWEEN 2 AND 3"
115    /// );
116    /// ```
117    fn not_between<V>(&self, a: V, b: V) -> SimpleExpr
118    where
119        V: Into<Value>,
120    {
121        Expr::col((self.entity_name(), *self)).not_between(a, b)
122    }
123
124    /// ```
125    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
126    ///
127    /// assert_eq!(
128    ///     cake::Entity::find()
129    ///         .filter(cake::Column::Name.like("cheese"))
130    ///         .build(DbBackend::MySql)
131    ///         .to_string(),
132    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'"
133    /// );
134    /// ```
135    fn like<T>(&self, s: T) -> SimpleExpr
136    where
137        T: IntoLikeExpr,
138    {
139        Expr::col((self.entity_name(), *self)).like(s)
140    }
141
142    /// ```
143    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
144    ///
145    /// assert_eq!(
146    ///     cake::Entity::find()
147    ///         .filter(cake::Column::Name.not_like("cheese"))
148    ///         .build(DbBackend::MySql)
149    ///         .to_string(),
150    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'"
151    /// );
152    /// ```
153    fn not_like<T>(&self, s: T) -> SimpleExpr
154    where
155        T: IntoLikeExpr,
156    {
157        Expr::col((self.entity_name(), *self)).not_like(s)
158    }
159
160    /// This is a simplified shorthand for a more general `like` method.
161    /// Use `like` if you need something more complex, like specifying an escape character.
162    ///
163    /// ## Examples
164    ///
165    /// ```
166    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
167    ///
168    /// assert_eq!(
169    ///     cake::Entity::find()
170    ///         .filter(cake::Column::Name.starts_with("cheese"))
171    ///         .build(DbBackend::MySql)
172    ///         .to_string(),
173    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'"
174    /// );
175    /// ```
176    fn starts_with<T>(&self, s: T) -> SimpleExpr
177    where
178        T: Into<String>,
179    {
180        let pattern = format!("{}%", s.into());
181        Expr::col((self.entity_name(), *self)).like(pattern)
182    }
183
184    /// This is a simplified shorthand for a more general `like` method.
185    /// Use `like` if you need something more complex, like specifying an escape character.
186    ///
187    /// ## Examples
188    ///
189    /// ```
190    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
191    ///
192    /// assert_eq!(
193    ///     cake::Entity::find()
194    ///         .filter(cake::Column::Name.ends_with("cheese"))
195    ///         .build(DbBackend::MySql)
196    ///         .to_string(),
197    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'"
198    /// );
199    /// ```
200    fn ends_with<T>(&self, s: T) -> SimpleExpr
201    where
202        T: Into<String>,
203    {
204        let pattern = format!("%{}", s.into());
205        Expr::col((self.entity_name(), *self)).like(pattern)
206    }
207
208    /// This is a simplified shorthand for a more general `like` method.
209    /// Use `like` if you need something more complex, like specifying an escape character.
210    ///
211    /// ## Examples
212    ///
213    /// ```
214    /// use sea_orm::{DbBackend, entity::*, query::*, tests_cfg::cake};
215    ///
216    /// assert_eq!(
217    ///     cake::Entity::find()
218    ///         .filter(cake::Column::Name.contains("cheese"))
219    ///         .build(DbBackend::MySql)
220    ///         .to_string(),
221    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
222    /// );
223    /// ```
224    fn contains<T>(&self, s: T) -> SimpleExpr
225    where
226        T: Into<String>,
227    {
228        let pattern = format!("%{}%", s.into());
229        Expr::col((self.entity_name(), *self)).like(pattern)
230    }
231
232    bind_func_no_params!(max);
233    bind_func_no_params!(min);
234    bind_func_no_params!(sum);
235    bind_func_no_params!(count);
236    bind_func_no_params!(is_null);
237    bind_func_no_params!(is_not_null);
238
239    /// Perform an operation if the column is null
240    fn if_null<V>(&self, v: V) -> SimpleExpr
241    where
242        V: Into<Value>,
243    {
244        Expr::col((self.entity_name(), *self)).if_null(v)
245    }
246
247    bind_vec_func!(is_in);
248    bind_vec_func!(is_not_in);
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::Id.eq_any(vec![4, 5]))
257    ///         .build(DbBackend::Postgres)
258    ///         .to_string(),
259    ///     r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = ANY(ARRAY [4,5])"#
260    /// );
261    /// ```
262    #[cfg(feature = "postgres-array")]
263    fn eq_any<V, I>(&self, v: I) -> SimpleExpr
264    where
265        V: Into<Value> + sea_query::ValueType + sea_query::with_array::NotU8,
266        I: IntoIterator<Item = V>,
267    {
268        use sea_query::extension::postgres::PgFunc;
269
270        let vec: Vec<_> = v.into_iter().collect();
271        Expr::col((self.entity_name(), *self)).eq(PgFunc::any(vec))
272    }
273
274    bind_subquery_func!(in_subquery);
275    bind_subquery_func!(not_in_subquery);
276
277    /// Construct a [`SimpleExpr::Column`] wrapped in [`Expr`].
278    fn into_expr(self) -> Expr {
279        self.into_simple_expr()
280    }
281
282    /// Construct a returning [`Expr`].
283    #[allow(clippy::match_single_binding)]
284    fn into_returning_expr(self, db_backend: DbBackend) -> Expr {
285        match db_backend {
286            _ => Expr::col(self),
287        }
288    }
289
290    /// Cast column expression used in select statement.
291    /// It only cast database enum as text if it's an enum column.
292    fn select_as(&self, expr: Expr) -> SimpleExpr {
293        self.select_enum_as(expr)
294    }
295
296    /// Cast enum column as text; do nothing if `self` is not an enum.
297    fn select_enum_as(&self, expr: Expr) -> SimpleExpr {
298        cast_enum_as(expr, self, |col, _, col_type| {
299            let type_name = match col_type {
300                ColumnType::Array(_) => TextArray.into_iden(),
301                _ => Text.into_iden(),
302            };
303            col.as_enum(type_name)
304        })
305    }
306
307    /// Cast value of a column into the correct type for database storage.
308    /// It only cast text as enum type if it's an enum column.
309    fn save_as(&self, val: Expr) -> SimpleExpr {
310        self.save_enum_as(val)
311    }
312
313    /// Cast value of an enum column as enum type; do nothing if `self` is not an enum.
314    /// Will also transform `Array(Vec<Json>)` into `Json(Vec<Json>)` if the column type is `Json`.
315    fn save_enum_as(&self, val: Expr) -> SimpleExpr {
316        cast_enum_as(val, self, |col, enum_name, col_type| {
317            let type_name = match col_type {
318                ColumnType::Array(_) => Alias::new(format!("{enum_name}[]")).into_iden(),
319                _ => enum_name,
320            };
321            col.as_enum(type_name)
322        })
323    }
324}
325
326/// SeaORM's utility methods that act on [ColumnType]
327pub trait ColumnTypeTrait {
328    /// Instantiate a new [ColumnDef]
329    fn def(self) -> ColumnDef;
330
331    /// Get the name of the enum if this is a enum column
332    fn get_enum_name(&self) -> Option<&DynIden>;
333}
334
335impl ColumnTypeTrait for ColumnType {
336    fn def(self) -> ColumnDef {
337        ColumnDef {
338            col_type: self,
339            null: false,
340            unique: false,
341            indexed: false,
342            default: None,
343            comment: None,
344            unique_key: None,
345            seaography: Default::default(),
346        }
347    }
348
349    fn get_enum_name(&self) -> Option<&DynIden> {
350        enum_name(self)
351    }
352}
353
354impl ColumnTypeTrait for ColumnDef {
355    fn def(self) -> ColumnDef {
356        self
357    }
358
359    fn get_enum_name(&self) -> Option<&DynIden> {
360        enum_name(&self.col_type)
361    }
362}
363
364fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
365    match col_type {
366        ColumnType::Enum { name, .. } => Some(name),
367        ColumnType::Array(col_type) => enum_name(col_type),
368        _ => None,
369    }
370}
371
372struct Text;
373struct TextArray;
374
375impl Iden for Text {
376    fn quoted(&self) -> Cow<'static, str> {
377        Cow::Borrowed("text")
378    }
379
380    fn unquoted(&self) -> &str {
381        match self.quoted() {
382            Cow::Borrowed(s) => s,
383            _ => unreachable!(),
384        }
385    }
386}
387
388impl Iden for TextArray {
389    fn quoted(&self) -> Cow<'static, str> {
390        // This is Postgres only and it has a special handling for quoting this
391        Cow::Borrowed("text[]")
392    }
393
394    fn unquoted(&self) -> &str {
395        match self.quoted() {
396            Cow::Borrowed(s) => s,
397            _ => unreachable!(),
398        }
399    }
400}
401
402fn cast_enum_as<C, F>(expr: Expr, col: &C, f: F) -> SimpleExpr
403where
404    C: ColumnTrait,
405    F: Fn(Expr, DynIden, &ColumnType) -> SimpleExpr,
406{
407    let col_def = col.def();
408    let col_type = col_def.get_column_type();
409
410    match col_type {
411        #[cfg(all(feature = "with-json", feature = "postgres-array"))]
412        ColumnType::Json | ColumnType::JsonBinary => {
413            use sea_query::ArrayType;
414            use serde_json::Value as Json;
415
416            match expr {
417                SimpleExpr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
418                    // flatten Array(Vec<Json>) into Json
419                    let json_vec: Vec<Json> = json_vec
420                        .into_iter()
421                        .filter_map(|val| match val {
422                            Value::Json(Some(json)) => Some(json),
423                            _ => None,
424                        })
425                        .collect();
426                    SimpleExpr::Value(Value::Json(Some(json_vec.into())))
427                }
428                SimpleExpr::Value(Value::Array(ArrayType::Json, None)) => {
429                    SimpleExpr::Value(Value::Json(None))
430                }
431                _ => expr,
432            }
433        }
434        _ => match col_type.get_enum_name() {
435            Some(enum_name) => f(expr, SeaRc::clone(enum_name), col_type),
436            None => expr,
437        },
438    }
439}
440
441#[cfg(test)]
442mod tests {
443    use crate::{
444        ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, tests_cfg::*,
445    };
446    use sea_query::Query;
447
448    #[test]
449    fn test_in_subquery_1() {
450        assert_eq!(
451            cake::Entity::find()
452                .filter(
453                    Condition::any().add(
454                        cake::Column::Id.in_subquery(
455                            Query::select()
456                                .expr(cake::Column::Id.max())
457                                .from(cake::Entity)
458                                .to_owned()
459                        )
460                    )
461                )
462                .build(DbBackend::MySql)
463                .to_string(),
464            [
465                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
466                "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
467            ]
468            .join(" ")
469        );
470    }
471
472    #[test]
473    fn test_in_subquery_2() {
474        assert_eq!(
475            cake::Entity::find()
476                .filter(
477                    Condition::any().add(
478                        cake::Column::Id.in_subquery(
479                            Query::select()
480                                .column(cake_filling::Column::CakeId)
481                                .from(cake_filling::Entity)
482                                .to_owned()
483                        )
484                    )
485                )
486                .build(DbBackend::MySql)
487                .to_string(),
488            [
489                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
490                "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
491            ]
492            .join(" ")
493        );
494    }
495
496    #[test]
497    #[cfg(feature = "macros")]
498    fn select_as_1() {
499        use crate::{ActiveModelTrait, ActiveValue, Update};
500
501        mod hello_expanded {
502            use crate as sea_orm;
503            use crate::entity::prelude::*;
504            use crate::sea_query::{Expr, ExprTrait, SimpleExpr};
505
506            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
507            pub struct Entity;
508
509            impl EntityName for Entity {
510                fn table_name(&self) -> &'static str {
511                    "hello"
512                }
513            }
514
515            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
516            pub struct Model {
517                pub id: i32,
518                #[sea_orm(enum_name = "One1")]
519                pub one: i32,
520                pub two: i32,
521                #[sea_orm(enum_name = "Three3")]
522                pub three: i32,
523            }
524
525            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
526            pub enum Column {
527                Id,
528                One1,
529                Two,
530                Three3,
531            }
532
533            impl ColumnTrait for Column {
534                type EntityName = Entity;
535
536                fn def(&self) -> ColumnDef {
537                    match self {
538                        Column::Id => ColumnType::Integer.def(),
539                        Column::One1 => ColumnType::Integer.def(),
540                        Column::Two => ColumnType::Integer.def(),
541                        Column::Three3 => ColumnType::Integer.def(),
542                    }
543                }
544
545                fn select_as(&self, expr: Expr) -> SimpleExpr {
546                    match self {
547                        Self::Two => expr.cast_as("integer"),
548                        _ => self.select_enum_as(expr),
549                    }
550                }
551            }
552
553            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
554            pub enum PrimaryKey {
555                Id,
556            }
557
558            impl PrimaryKeyTrait for PrimaryKey {
559                type ValueType = i32;
560
561                fn auto_increment() -> bool {
562                    true
563                }
564            }
565
566            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
567            pub enum Relation {}
568
569            impl ActiveModelBehavior for ActiveModel {}
570        }
571
572        #[allow(clippy::enum_variant_names)]
573        mod hello_compact {
574            use crate as sea_orm;
575            use crate::entity::prelude::*;
576
577            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
578            #[sea_orm(table_name = "hello")]
579            pub struct Model {
580                #[sea_orm(primary_key)]
581                pub id: i32,
582                #[sea_orm(enum_name = "One1")]
583                pub one: i32,
584                #[sea_orm(select_as = "integer")]
585                pub two: i32,
586                #[sea_orm(enum_name = "Three3")]
587                pub three: i32,
588            }
589
590            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
591            pub enum Relation {}
592
593            impl ActiveModelBehavior for ActiveModel {}
594        }
595
596        fn assert_it<E, A>(active_model: A)
597        where
598            E: EntityTrait,
599            A: ActiveModelTrait<Entity = E>,
600        {
601            assert_eq!(
602                E::find().build(DbBackend::Postgres).to_string(),
603                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
604            );
605            assert_eq!(
606                Update::one(active_model)
607                    .build(DbBackend::Postgres)
608                    .to_string(),
609                r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
610            );
611        }
612
613        assert_it(hello_expanded::ActiveModel {
614            id: ActiveValue::set(1),
615            one: ActiveValue::set(1),
616            two: ActiveValue::set(2),
617            three: ActiveValue::set(3),
618        });
619        assert_it(hello_compact::ActiveModel {
620            id: ActiveValue::set(1),
621            one: ActiveValue::set(1),
622            two: ActiveValue::set(2),
623            three: ActiveValue::set(3),
624        });
625    }
626
627    #[test]
628    #[cfg(feature = "macros")]
629    fn save_as_1() {
630        use crate::{ActiveModelTrait, ActiveValue, Update};
631
632        mod hello_expanded {
633            use crate as sea_orm;
634            use crate::entity::prelude::*;
635            use crate::sea_query::{Expr, ExprTrait, SimpleExpr};
636
637            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
638            pub struct Entity;
639
640            impl EntityName for Entity {
641                fn table_name(&self) -> &'static str {
642                    "hello"
643                }
644            }
645
646            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
647            pub struct Model {
648                pub id: i32,
649                #[sea_orm(enum_name = "One1")]
650                pub one: i32,
651                pub two: i32,
652                #[sea_orm(enum_name = "Three3")]
653                pub three: i32,
654            }
655
656            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
657            pub enum Column {
658                Id,
659                One1,
660                Two,
661                Three3,
662            }
663
664            impl ColumnTrait for Column {
665                type EntityName = Entity;
666
667                fn def(&self) -> ColumnDef {
668                    match self {
669                        Column::Id => ColumnType::Integer.def(),
670                        Column::One1 => ColumnType::Integer.def(),
671                        Column::Two => ColumnType::Integer.def(),
672                        Column::Three3 => ColumnType::Integer.def(),
673                    }
674                }
675
676                fn save_as(&self, val: Expr) -> SimpleExpr {
677                    match self {
678                        Self::Two => val.cast_as("text"),
679                        _ => self.save_enum_as(val),
680                    }
681                }
682            }
683
684            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
685            pub enum PrimaryKey {
686                Id,
687            }
688
689            impl PrimaryKeyTrait for PrimaryKey {
690                type ValueType = i32;
691
692                fn auto_increment() -> bool {
693                    true
694                }
695            }
696
697            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
698            pub enum Relation {}
699
700            impl ActiveModelBehavior for ActiveModel {}
701        }
702
703        #[allow(clippy::enum_variant_names)]
704        mod hello_compact {
705            use crate as sea_orm;
706            use crate::entity::prelude::*;
707
708            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
709            #[sea_orm(table_name = "hello")]
710            pub struct Model {
711                #[sea_orm(primary_key)]
712                pub id: i32,
713                #[sea_orm(enum_name = "One1")]
714                pub one: i32,
715                #[sea_orm(save_as = "text")]
716                pub two: i32,
717                #[sea_orm(enum_name = "Three3")]
718                pub three: i32,
719            }
720
721            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
722            pub enum Relation {}
723
724            impl ActiveModelBehavior for ActiveModel {}
725        }
726
727        fn assert_it<E, A>(active_model: A)
728        where
729            E: EntityTrait,
730            A: ActiveModelTrait<Entity = E>,
731        {
732            assert_eq!(
733                E::find().build(DbBackend::Postgres).to_string(),
734                r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
735            );
736            assert_eq!(
737                Update::one(active_model)
738                    .build(DbBackend::Postgres)
739                    .to_string(),
740                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
741            );
742        }
743
744        assert_it(hello_expanded::ActiveModel {
745            id: ActiveValue::set(1),
746            one: ActiveValue::set(1),
747            two: ActiveValue::set(2),
748            three: ActiveValue::set(3),
749        });
750        assert_it(hello_compact::ActiveModel {
751            id: ActiveValue::set(1),
752            one: ActiveValue::set(1),
753            two: ActiveValue::set(2),
754            three: ActiveValue::set(3),
755        });
756    }
757
758    #[test]
759    #[cfg(feature = "macros")]
760    fn select_as_and_value_1() {
761        use crate::{ActiveModelTrait, ActiveValue, Update};
762
763        mod hello_expanded {
764            use crate as sea_orm;
765            use crate::entity::prelude::*;
766            use crate::sea_query::{Expr, ExprTrait, SimpleExpr};
767
768            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
769            pub struct Entity;
770
771            impl EntityName for Entity {
772                fn table_name(&self) -> &'static str {
773                    "hello"
774                }
775            }
776
777            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
778            pub struct Model {
779                pub id: i32,
780                #[sea_orm(enum_name = "One1")]
781                pub one: i32,
782                pub two: i32,
783                #[sea_orm(enum_name = "Three3")]
784                pub three: i32,
785            }
786
787            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
788            pub enum Column {
789                Id,
790                One1,
791                Two,
792                Three3,
793            }
794
795            impl ColumnTrait for Column {
796                type EntityName = Entity;
797
798                fn def(&self) -> ColumnDef {
799                    match self {
800                        Column::Id => ColumnType::Integer.def(),
801                        Column::One1 => ColumnType::Integer.def(),
802                        Column::Two => ColumnType::Integer.def(),
803                        Column::Three3 => ColumnType::Integer.def(),
804                    }
805                }
806
807                fn select_as(&self, expr: Expr) -> SimpleExpr {
808                    match self {
809                        Self::Two => expr.cast_as("integer"),
810                        _ => self.select_enum_as(expr),
811                    }
812                }
813
814                fn save_as(&self, val: Expr) -> SimpleExpr {
815                    match self {
816                        Self::Two => val.cast_as("text"),
817                        _ => self.save_enum_as(val),
818                    }
819                }
820            }
821
822            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
823            pub enum PrimaryKey {
824                Id,
825            }
826
827            impl PrimaryKeyTrait for PrimaryKey {
828                type ValueType = i32;
829
830                fn auto_increment() -> bool {
831                    true
832                }
833            }
834
835            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
836            pub enum Relation {}
837
838            impl ActiveModelBehavior for ActiveModel {}
839        }
840
841        #[allow(clippy::enum_variant_names)]
842        mod hello_compact {
843            use crate as sea_orm;
844            use crate::entity::prelude::*;
845
846            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
847            #[sea_orm(table_name = "hello")]
848            pub struct Model {
849                #[sea_orm(primary_key)]
850                pub id: i32,
851                #[sea_orm(enum_name = "One1")]
852                pub one: i32,
853                #[sea_orm(select_as = "integer", save_as = "text")]
854                pub two: i32,
855                #[sea_orm(enum_name = "Three3")]
856                pub three: i32,
857            }
858
859            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
860            pub enum Relation {}
861
862            impl ActiveModelBehavior for ActiveModel {}
863        }
864
865        fn assert_it<E, A>(active_model: A)
866        where
867            E: EntityTrait,
868            A: ActiveModelTrait<Entity = E>,
869        {
870            assert_eq!(
871                E::find().build(DbBackend::Postgres).to_string(),
872                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
873            );
874            assert_eq!(
875                Update::one(active_model)
876                    .build(DbBackend::Postgres)
877                    .to_string(),
878                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
879            );
880        }
881
882        assert_it(hello_expanded::ActiveModel {
883            id: ActiveValue::set(1),
884            one: ActiveValue::set(1),
885            two: ActiveValue::set(2),
886            three: ActiveValue::set(3),
887        });
888        assert_it(hello_compact::ActiveModel {
889            id: ActiveValue::set(1),
890            one: ActiveValue::set(1),
891            two: ActiveValue::set(2),
892            three: ActiveValue::set(3),
893        });
894    }
895}