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