sea_orm/entity/
column.rs

1use crate::{DbBackend, EntityName, Iden, IdenStatic, IntoSimpleExpr, Iterable};
2use sea_query::{
3    Alias, BinOper, DynIden, Expr, IntoIden, SeaRc, SelectStatement, SimpleExpr, Value,
4};
5use std::str::FromStr;
6
7// The original `sea_orm::ColumnType` enum was dropped since 0.11.0
8// It was replaced by `sea_query::ColumnType`, we reexport it here to keep the `ColumnType` symbol
9pub use sea_query::ColumnType;
10
11/// Defines a Column for an Entity
12#[derive(Debug, Clone, PartialEq)]
13pub struct ColumnDef {
14    pub(crate) col_type: ColumnType,
15    pub(crate) null: bool,
16    pub(crate) unique: bool,
17    pub(crate) indexed: bool,
18    pub(crate) default: Option<SimpleExpr>,
19    pub(crate) comment: Option<String>,
20}
21
22macro_rules! bind_oper {
23    ( $op: ident, $bin_op: ident ) => {
24        #[allow(missing_docs)]
25        fn $op<V>(&self, v: V) -> SimpleExpr
26        where
27            V: Into<Value>,
28        {
29            let expr = self.save_as(Expr::val(v));
30            Expr::col((self.entity_name(), *self)).binary(BinOper::$bin_op, expr)
31        }
32    };
33}
34
35macro_rules! bind_func_no_params {
36    ( $func: ident ) => {
37        /// See also SeaQuery's method with same name.
38        fn $func(&self) -> SimpleExpr {
39            Expr::col((self.entity_name(), *self)).$func()
40        }
41    };
42}
43
44macro_rules! bind_vec_func {
45    ( $func: ident ) => {
46        #[allow(missing_docs)]
47        #[allow(clippy::wrong_self_convention)]
48        fn $func<V, I>(&self, v: I) -> SimpleExpr
49        where
50            V: Into<Value>,
51            I: IntoIterator<Item = V>,
52        {
53            let v_with_enum_cast = v.into_iter().map(|v| self.save_as(Expr::val(v)));
54            Expr::col((self.entity_name(), *self)).$func(v_with_enum_cast)
55        }
56    };
57}
58
59macro_rules! bind_subquery_func {
60    ( $func: ident ) => {
61        #[allow(clippy::wrong_self_convention)]
62        #[allow(missing_docs)]
63        fn $func(&self, s: SelectStatement) -> SimpleExpr {
64            Expr::col((self.entity_name(), *self)).$func(s)
65        }
66    };
67}
68
69// LINT: when the operand value does not match column type
70/// API for working with a `Column`. Mostly a wrapper of the identically named methods in [`sea_query::Expr`]
71pub trait ColumnTrait: IdenStatic + Iterable + FromStr {
72    #[allow(missing_docs)]
73    type EntityName: EntityName;
74
75    /// Define a column for an Entity
76    fn def(&self) -> ColumnDef;
77
78    /// Get the enum name of the column type
79    fn enum_type_name(&self) -> Option<&'static str> {
80        None
81    }
82
83    /// Get the name of the entity the column belongs to
84    fn entity_name(&self) -> DynIden {
85        SeaRc::new(Self::EntityName::default()) as DynIden
86    }
87
88    /// get the name of the entity the column belongs to
89    fn as_column_ref(&self) -> (DynIden, DynIden) {
90        (self.entity_name(), SeaRc::new(*self) as DynIden)
91    }
92
93    bind_oper!(eq, Equal);
94    bind_oper!(ne, NotEqual);
95    bind_oper!(gt, GreaterThan);
96    bind_oper!(gte, GreaterThanOrEqual);
97    bind_oper!(lt, SmallerThan);
98    bind_oper!(lte, SmallerThanOrEqual);
99
100    /// ```
101    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
102    ///
103    /// assert_eq!(
104    ///     cake::Entity::find()
105    ///         .filter(cake::Column::Id.between(2, 3))
106    ///         .build(DbBackend::MySql)
107    ///         .to_string(),
108    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` BETWEEN 2 AND 3"
109    /// );
110    /// ```
111    fn between<V>(&self, a: V, b: V) -> SimpleExpr
112    where
113        V: Into<Value>,
114    {
115        Expr::col((self.entity_name(), *self)).between(a, b)
116    }
117
118    /// ```
119    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
120    ///
121    /// assert_eq!(
122    ///     cake::Entity::find()
123    ///         .filter(cake::Column::Id.not_between(2, 3))
124    ///         .build(DbBackend::MySql)
125    ///         .to_string(),
126    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` NOT BETWEEN 2 AND 3"
127    /// );
128    /// ```
129    fn not_between<V>(&self, a: V, b: V) -> SimpleExpr
130    where
131        V: Into<Value>,
132    {
133        Expr::col((self.entity_name(), *self)).not_between(a, b)
134    }
135
136    /// ```
137    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
138    ///
139    /// assert_eq!(
140    ///     cake::Entity::find()
141    ///         .filter(cake::Column::Name.like("cheese"))
142    ///         .build(DbBackend::MySql)
143    ///         .to_string(),
144    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'"
145    /// );
146    /// ```
147    fn like<T>(&self, s: T) -> SimpleExpr
148    where
149        T: Into<String>,
150    {
151        Expr::col((self.entity_name(), *self)).like(s)
152    }
153
154    /// ```
155    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
156    ///
157    /// assert_eq!(
158    ///     cake::Entity::find()
159    ///         .filter(cake::Column::Name.not_like("cheese"))
160    ///         .build(DbBackend::MySql)
161    ///         .to_string(),
162    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'"
163    /// );
164    /// ```
165    fn not_like<T>(&self, s: T) -> SimpleExpr
166    where
167        T: Into<String>,
168    {
169        Expr::col((self.entity_name(), *self)).not_like(s)
170    }
171
172    /// ```
173    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
174    ///
175    /// assert_eq!(
176    ///     cake::Entity::find()
177    ///         .filter(cake::Column::Name.starts_with("cheese"))
178    ///         .build(DbBackend::MySql)
179    ///         .to_string(),
180    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'"
181    /// );
182    /// ```
183    fn starts_with<T>(&self, s: T) -> SimpleExpr
184    where
185        T: Into<String>,
186    {
187        let pattern = format!("{}%", s.into());
188        Expr::col((self.entity_name(), *self)).like(pattern)
189    }
190
191    /// ```
192    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
193    ///
194    /// assert_eq!(
195    ///     cake::Entity::find()
196    ///         .filter(cake::Column::Name.ends_with("cheese"))
197    ///         .build(DbBackend::MySql)
198    ///         .to_string(),
199    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'"
200    /// );
201    /// ```
202    fn ends_with<T>(&self, s: T) -> SimpleExpr
203    where
204        T: Into<String>,
205    {
206        let pattern = format!("%{}", s.into());
207        Expr::col((self.entity_name(), *self)).like(pattern)
208    }
209
210    /// ```
211    /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
212    ///
213    /// assert_eq!(
214    ///     cake::Entity::find()
215    ///         .filter(cake::Column::Name.contains("cheese"))
216    ///         .build(DbBackend::MySql)
217    ///         .to_string(),
218    ///     "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
219    /// );
220    /// ```
221    fn contains<T>(&self, s: T) -> SimpleExpr
222    where
223        T: Into<String>,
224    {
225        let pattern = format!("%{}%", s.into());
226        Expr::col((self.entity_name(), *self)).like(pattern)
227    }
228
229    bind_func_no_params!(max);
230    bind_func_no_params!(min);
231    bind_func_no_params!(sum);
232    bind_func_no_params!(count);
233    bind_func_no_params!(is_null);
234    bind_func_no_params!(is_not_null);
235
236    /// Perform an operation if the column is null
237    fn if_null<V>(&self, v: V) -> SimpleExpr
238    where
239        V: Into<Value>,
240    {
241        Expr::col((self.entity_name(), *self)).if_null(v)
242    }
243
244    bind_vec_func!(is_in);
245    bind_vec_func!(is_not_in);
246
247    bind_subquery_func!(in_subquery);
248    bind_subquery_func!(not_in_subquery);
249
250    /// Construct a [`SimpleExpr::Column`] wrapped in [`Expr`].
251    fn into_expr(self) -> Expr {
252        Expr::expr(self.into_simple_expr())
253    }
254
255    /// Construct a returning [`Expr`].
256    #[allow(clippy::match_single_binding)]
257    fn into_returning_expr(self, db_backend: DbBackend) -> Expr {
258        match db_backend {
259            _ => Expr::col(self),
260        }
261    }
262
263    /// Cast column expression used in select statement.
264    /// It only cast database enum as text if it's an enum column.
265    fn select_as(&self, expr: Expr) -> SimpleExpr {
266        self.select_enum_as(expr)
267    }
268
269    /// Cast enum column as text; do nothing if `self` is not an enum.
270    fn select_enum_as(&self, expr: Expr) -> SimpleExpr {
271        cast_enum_as(expr, self, |col, _, col_type| {
272            let type_name = match col_type {
273                ColumnType::Array(_) => TextArray.into_iden(),
274                _ => Text.into_iden(),
275            };
276            col.as_enum(type_name)
277        })
278    }
279
280    /// Cast value of a column into the correct type for database storage.
281    /// It only cast text as enum type if it's an enum column.
282    fn save_as(&self, val: Expr) -> SimpleExpr {
283        self.save_enum_as(val)
284    }
285
286    /// Cast value of an enum column as enum type; do nothing if `self` is not an enum.
287    /// Will also transform `Array(Vec<Json>)` into `Json(Vec<Json>)` if the column type is `Json`.
288    fn save_enum_as(&self, val: Expr) -> SimpleExpr {
289        cast_enum_as(val, self, |col, enum_name, col_type| {
290            let type_name = match col_type {
291                ColumnType::Array(_) => {
292                    Alias::new(format!("{}[]", enum_name.to_string())).into_iden()
293                }
294                _ => enum_name,
295            };
296            col.as_enum(type_name)
297        })
298    }
299}
300
301/// SeaORM's utility methods that act on [ColumnType]
302pub trait ColumnTypeTrait {
303    /// Instantiate a new [ColumnDef]
304    fn def(self) -> ColumnDef;
305
306    /// Get the name of the enum if this is a enum column
307    fn get_enum_name(&self) -> Option<&DynIden>;
308}
309
310impl ColumnTypeTrait for ColumnType {
311    fn def(self) -> ColumnDef {
312        ColumnDef {
313            col_type: self,
314            null: false,
315            unique: false,
316            indexed: false,
317            default: None,
318            comment: None,
319        }
320    }
321
322    fn get_enum_name(&self) -> Option<&DynIden> {
323        enum_name(self)
324    }
325}
326
327impl ColumnTypeTrait for ColumnDef {
328    fn def(self) -> ColumnDef {
329        self
330    }
331
332    fn get_enum_name(&self) -> Option<&DynIden> {
333        enum_name(&self.col_type)
334    }
335}
336
337fn enum_name(col_type: &ColumnType) -> Option<&DynIden> {
338    match col_type {
339        ColumnType::Enum { name, .. } => Some(name),
340        ColumnType::Array(col_type) => enum_name(col_type),
341        _ => None,
342    }
343}
344
345impl ColumnDef {
346    /// Marks the column as `UNIQUE`
347    pub fn unique(mut self) -> Self {
348        self.unique = true;
349        self
350    }
351    /// Set column comment
352    pub fn comment(mut self, v: &str) -> Self {
353        self.comment = Some(v.into());
354        self
355    }
356
357    /// Mark the column as nullable
358    pub fn null(self) -> Self {
359        self.nullable()
360    }
361
362    /// Mark the column as nullable
363    pub fn nullable(mut self) -> Self {
364        self.null = true;
365        self
366    }
367
368    /// Set the `indexed` field  to `true`
369    pub fn indexed(mut self) -> Self {
370        self.indexed = true;
371        self
372    }
373
374    /// Set the default value
375    pub fn default_value<T>(mut self, value: T) -> Self
376    where
377        T: Into<Value>,
378    {
379        self.default = Some(value.into().into());
380        self
381    }
382
383    /// Set the default value or expression of a column
384    pub fn default<T>(mut self, default: T) -> Self
385    where
386        T: Into<SimpleExpr>,
387    {
388        self.default = Some(default.into());
389        self
390    }
391
392    /// Get [ColumnType] as reference
393    pub fn get_column_type(&self) -> &ColumnType {
394        &self.col_type
395    }
396
397    /// Get [Option<SimpleExpr>] as reference
398    pub fn get_column_default(&self) -> Option<&SimpleExpr> {
399        self.default.as_ref()
400    }
401
402    /// Returns true if the column is nullable
403    pub fn is_null(&self) -> bool {
404        self.null
405    }
406
407    /// Returns true if the column is unique
408    pub fn is_unique(&self) -> bool {
409        self.unique
410    }
411}
412
413struct Text;
414struct TextArray;
415
416impl Iden for Text {
417    fn unquoted(&self, s: &mut dyn std::fmt::Write) {
418        write!(s, "text").unwrap();
419    }
420}
421
422impl Iden for TextArray {
423    fn unquoted(&self, s: &mut dyn std::fmt::Write) {
424        write!(s, "text[]").unwrap();
425    }
426}
427
428fn cast_enum_as<C, F>(expr: Expr, col: &C, f: F) -> SimpleExpr
429where
430    C: ColumnTrait,
431    F: Fn(Expr, DynIden, &ColumnType) -> SimpleExpr,
432{
433    let col_def = col.def();
434    let col_type = col_def.get_column_type();
435
436    match col_type {
437        #[cfg(all(feature = "with-json", feature = "postgres-array"))]
438        ColumnType::Json | ColumnType::JsonBinary => {
439            use sea_query::ArrayType;
440            use serde_json::Value as Json;
441
442            #[allow(clippy::boxed_local)]
443            fn unbox<T>(boxed: Box<T>) -> T {
444                *boxed
445            }
446
447            let expr = expr.into();
448            match expr {
449                SimpleExpr::Value(Value::Array(ArrayType::Json, Some(json_vec))) => {
450                    // flatten Array(Vec<Json>) into Json
451                    let json_vec: Vec<Json> = json_vec
452                        .into_iter()
453                        .filter_map(|val| match val {
454                            Value::Json(Some(json)) => Some(unbox(json)),
455                            _ => None,
456                        })
457                        .collect();
458                    SimpleExpr::Value(Value::Json(Some(Box::new(json_vec.into()))))
459                }
460                SimpleExpr::Value(Value::Array(ArrayType::Json, None)) => {
461                    SimpleExpr::Value(Value::Json(None))
462                }
463                _ => expr,
464            }
465        }
466        _ => match col_type.get_enum_name() {
467            Some(enum_name) => f(expr, SeaRc::clone(enum_name), col_type),
468            None => expr.into(),
469        },
470    }
471}
472
473#[cfg(test)]
474mod tests {
475    use crate::{
476        tests_cfg::*, ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait,
477    };
478    use sea_query::Query;
479
480    #[test]
481    fn test_in_subquery_1() {
482        assert_eq!(
483            cake::Entity::find()
484                .filter(
485                    Condition::any().add(
486                        cake::Column::Id.in_subquery(
487                            Query::select()
488                                .expr(cake::Column::Id.max())
489                                .from(cake::Entity)
490                                .to_owned()
491                        )
492                    )
493                )
494                .build(DbBackend::MySql)
495                .to_string(),
496            [
497                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
498                "WHERE `cake`.`id` IN (SELECT MAX(`cake`.`id`) FROM `cake`)",
499            ]
500            .join(" ")
501        );
502    }
503
504    #[test]
505    fn test_in_subquery_2() {
506        assert_eq!(
507            cake::Entity::find()
508                .filter(
509                    Condition::any().add(
510                        cake::Column::Id.in_subquery(
511                            Query::select()
512                                .column(cake_filling::Column::CakeId)
513                                .from(cake_filling::Entity)
514                                .to_owned()
515                        )
516                    )
517                )
518                .build(DbBackend::MySql)
519                .to_string(),
520            [
521                "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
522                "WHERE `cake`.`id` IN (SELECT `cake_id` FROM `cake_filling`)",
523            ]
524            .join(" ")
525        );
526    }
527
528    #[test]
529    fn test_col_from_str() {
530        use std::str::FromStr;
531
532        assert!(matches!(
533            fruit::Column::from_str("id"),
534            Ok(fruit::Column::Id)
535        ));
536        assert!(matches!(
537            fruit::Column::from_str("name"),
538            Ok(fruit::Column::Name)
539        ));
540        assert!(matches!(
541            fruit::Column::from_str("cake_id"),
542            Ok(fruit::Column::CakeId)
543        ));
544        assert!(matches!(
545            fruit::Column::from_str("cakeId"),
546            Ok(fruit::Column::CakeId)
547        ));
548        assert!(matches!(
549            fruit::Column::from_str("does_not_exist"),
550            Err(crate::ColumnFromStrErr(_))
551        ));
552    }
553
554    #[test]
555    #[cfg(feature = "macros")]
556    fn entity_model_column_1() {
557        use crate::prelude::*;
558
559        mod hello {
560            use crate as sea_orm;
561            use crate::entity::prelude::*;
562
563            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
564            #[sea_orm(table_name = "hello")]
565            pub struct Model {
566                #[sea_orm(primary_key)]
567                pub id: i32,
568                pub one: i32,
569                #[sea_orm(unique)]
570                pub two: i8,
571                #[sea_orm(indexed)]
572                pub three: i16,
573                #[sea_orm(nullable)]
574                pub four: i32,
575                #[sea_orm(unique, indexed, nullable)]
576                pub five: i64,
577                #[sea_orm(unique)]
578                pub six: u8,
579                #[sea_orm(indexed)]
580                pub seven: u16,
581                #[sea_orm(nullable)]
582                pub eight: u32,
583                #[sea_orm(unique, indexed, nullable)]
584                pub nine: u64,
585                #[sea_orm(default_expr = "Expr::current_timestamp()")]
586                pub ten: DateTimeUtc,
587                #[sea_orm(default_value = 7)]
588                pub eleven: u8,
589                #[sea_orm(default_value = "twelve_value")]
590                pub twelve: String,
591                #[sea_orm(default_expr = "\"twelve_value\"")]
592                pub twelve_two: String,
593            }
594
595            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
596            pub enum Relation {}
597
598            impl ActiveModelBehavior for ActiveModel {}
599        }
600
601        assert_eq!(hello::Column::One.def(), ColumnType::Integer.def());
602        assert_eq!(
603            hello::Column::Two.def(),
604            ColumnType::TinyInteger.def().unique()
605        );
606        assert_eq!(
607            hello::Column::Three.def(),
608            ColumnType::SmallInteger.def().indexed()
609        );
610        assert_eq!(
611            hello::Column::Four.def(),
612            ColumnType::Integer.def().nullable()
613        );
614        assert_eq!(
615            hello::Column::Five.def(),
616            ColumnType::BigInteger.def().unique().indexed().nullable()
617        );
618        assert_eq!(
619            hello::Column::Six.def(),
620            ColumnType::TinyUnsigned.def().unique()
621        );
622        assert_eq!(
623            hello::Column::Seven.def(),
624            ColumnType::SmallUnsigned.def().indexed()
625        );
626        assert_eq!(
627            hello::Column::Eight.def(),
628            ColumnType::Unsigned.def().nullable()
629        );
630        assert_eq!(
631            hello::Column::Nine.def(),
632            ColumnType::BigUnsigned.def().unique().indexed().nullable()
633        );
634        assert_eq!(
635            hello::Column::Ten.def(),
636            ColumnType::TimestampWithTimeZone
637                .def()
638                .default(Expr::current_timestamp())
639        );
640        assert_eq!(
641            hello::Column::Eleven.def(),
642            ColumnType::TinyUnsigned.def().default(7)
643        );
644        assert_eq!(
645            hello::Column::Twelve.def(),
646            ColumnType::String(StringLen::None)
647                .def()
648                .default("twelve_value")
649        );
650        assert_eq!(
651            hello::Column::TwelveTwo.def(),
652            ColumnType::String(StringLen::None)
653                .def()
654                .default("twelve_value")
655        );
656    }
657
658    #[test]
659    #[cfg(feature = "macros")]
660    fn column_name_1() {
661        use sea_query::Iden;
662
663        mod hello {
664            use crate as sea_orm;
665            use crate::entity::prelude::*;
666
667            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
668            #[sea_orm(table_name = "hello")]
669            pub struct Model {
670                #[sea_orm(primary_key)]
671                pub id: i32,
672                #[sea_orm(column_name = "ONE")]
673                pub one: i32,
674                pub two: i32,
675                #[sea_orm(column_name = "3")]
676                pub three: i32,
677            }
678
679            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
680            pub enum Relation {}
681
682            impl ActiveModelBehavior for ActiveModel {}
683        }
684
685        assert_eq!(hello::Column::One.to_string().as_str(), "ONE");
686        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
687        assert_eq!(hello::Column::Three.to_string().as_str(), "3");
688    }
689
690    #[test]
691    #[cfg(feature = "macros")]
692    fn column_name_2() {
693        use sea_query::Iden;
694
695        mod hello {
696            use crate as sea_orm;
697            use crate::entity::prelude::*;
698
699            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
700            pub struct Entity;
701
702            impl EntityName for Entity {
703                fn table_name(&self) -> &str {
704                    "hello"
705                }
706            }
707
708            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
709            pub struct Model {
710                pub id: i32,
711                pub one: i32,
712                pub two: i32,
713                pub three: i32,
714            }
715
716            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
717            pub enum Column {
718                Id,
719                #[sea_orm(column_name = "ONE")]
720                One,
721                Two,
722                #[sea_orm(column_name = "3")]
723                Three,
724            }
725
726            impl ColumnTrait for Column {
727                type EntityName = Entity;
728
729                fn def(&self) -> ColumnDef {
730                    match self {
731                        Column::Id => ColumnType::Integer.def(),
732                        Column::One => ColumnType::Integer.def(),
733                        Column::Two => ColumnType::Integer.def(),
734                        Column::Three => ColumnType::Integer.def(),
735                    }
736                }
737            }
738
739            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
740            pub enum PrimaryKey {
741                Id,
742            }
743
744            impl PrimaryKeyTrait for PrimaryKey {
745                type ValueType = i32;
746
747                fn auto_increment() -> bool {
748                    true
749                }
750            }
751
752            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
753            pub enum Relation {}
754
755            impl ActiveModelBehavior for ActiveModel {}
756        }
757
758        assert_eq!(hello::Column::One.to_string().as_str(), "ONE");
759        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
760        assert_eq!(hello::Column::Three.to_string().as_str(), "3");
761    }
762
763    #[test]
764    #[cfg(feature = "macros")]
765    fn enum_name_1() {
766        use sea_query::Iden;
767
768        mod hello {
769            use crate as sea_orm;
770            use crate::entity::prelude::*;
771
772            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
773            #[sea_orm(table_name = "hello")]
774            pub struct Model {
775                #[sea_orm(primary_key)]
776                pub id: i32,
777                #[sea_orm(enum_name = "One1")]
778                pub one: i32,
779                pub two: i32,
780                #[sea_orm(enum_name = "Three3")]
781                pub three: i32,
782            }
783
784            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
785            pub enum Relation {}
786
787            impl ActiveModelBehavior for ActiveModel {}
788        }
789
790        assert_eq!(hello::Column::One1.to_string().as_str(), "one1");
791        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
792        assert_eq!(hello::Column::Three3.to_string().as_str(), "three3");
793    }
794
795    #[test]
796    #[cfg(feature = "macros")]
797    fn enum_name_2() {
798        use sea_query::Iden;
799
800        mod hello {
801            use crate as sea_orm;
802            use crate::entity::prelude::*;
803
804            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
805            pub struct Entity;
806
807            impl EntityName for Entity {
808                fn table_name(&self) -> &str {
809                    "hello"
810                }
811            }
812
813            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
814            pub struct Model {
815                pub id: i32,
816                #[sea_orm(enum_name = "One1")]
817                pub one: i32,
818                pub two: i32,
819                #[sea_orm(enum_name = "Three3")]
820                pub three: i32,
821            }
822
823            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
824            pub enum Column {
825                Id,
826                One1,
827                Two,
828                Three3,
829            }
830
831            impl ColumnTrait for Column {
832                type EntityName = Entity;
833
834                fn def(&self) -> ColumnDef {
835                    match self {
836                        Column::Id => ColumnType::Integer.def(),
837                        Column::One1 => ColumnType::Integer.def(),
838                        Column::Two => ColumnType::Integer.def(),
839                        Column::Three3 => ColumnType::Integer.def(),
840                    }
841                }
842            }
843
844            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
845            pub enum PrimaryKey {
846                Id,
847            }
848
849            impl PrimaryKeyTrait for PrimaryKey {
850                type ValueType = i32;
851
852                fn auto_increment() -> bool {
853                    true
854                }
855            }
856
857            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
858            pub enum Relation {}
859
860            impl ActiveModelBehavior for ActiveModel {}
861        }
862
863        assert_eq!(hello::Column::One1.to_string().as_str(), "one1");
864        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
865        assert_eq!(hello::Column::Three3.to_string().as_str(), "three3");
866    }
867
868    #[test]
869    #[cfg(feature = "macros")]
870    fn column_name_enum_name_1() {
871        use sea_query::Iden;
872
873        #[allow(clippy::enum_variant_names)]
874        mod hello {
875            use crate as sea_orm;
876            use crate::entity::prelude::*;
877
878            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
879            #[sea_orm(table_name = "hello")]
880            pub struct Model {
881                #[sea_orm(primary_key, column_name = "ID", enum_name = "IdentityColumn")]
882                pub id: i32,
883                #[sea_orm(column_name = "ONE", enum_name = "One1")]
884                pub one: i32,
885                pub two: i32,
886                #[sea_orm(column_name = "THREE", enum_name = "Three3")]
887                pub three: i32,
888            }
889
890            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
891            pub enum Relation {}
892
893            impl ActiveModelBehavior for ActiveModel {}
894        }
895
896        assert_eq!(hello::Column::IdentityColumn.to_string().as_str(), "ID");
897        assert_eq!(hello::Column::One1.to_string().as_str(), "ONE");
898        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
899        assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE");
900    }
901
902    #[test]
903    #[cfg(feature = "macros")]
904    fn column_name_enum_name_2() {
905        use sea_query::Iden;
906
907        mod hello {
908            use crate as sea_orm;
909            use crate::entity::prelude::*;
910
911            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
912            pub struct Entity;
913
914            impl EntityName for Entity {
915                fn table_name(&self) -> &str {
916                    "hello"
917                }
918            }
919
920            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
921            pub struct Model {
922                #[sea_orm(enum_name = "IdentityCol")]
923                pub id: i32,
924                #[sea_orm(enum_name = "One1")]
925                pub one: i32,
926                pub two: i32,
927                #[sea_orm(enum_name = "Three3")]
928                pub three: i32,
929            }
930
931            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
932            pub enum Column {
933                #[sea_orm(column_name = "ID")]
934                IdentityCol,
935                #[sea_orm(column_name = "ONE")]
936                One1,
937                Two,
938                #[sea_orm(column_name = "THREE")]
939                Three3,
940            }
941
942            impl ColumnTrait for Column {
943                type EntityName = Entity;
944
945                fn def(&self) -> ColumnDef {
946                    match self {
947                        Column::IdentityCol => ColumnType::Integer.def(),
948                        Column::One1 => ColumnType::Integer.def(),
949                        Column::Two => ColumnType::Integer.def(),
950                        Column::Three3 => ColumnType::Integer.def(),
951                    }
952                }
953            }
954
955            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
956            pub enum PrimaryKey {
957                IdentityCol,
958            }
959
960            impl PrimaryKeyTrait for PrimaryKey {
961                type ValueType = i32;
962
963                fn auto_increment() -> bool {
964                    true
965                }
966            }
967
968            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
969            pub enum Relation {}
970
971            impl ActiveModelBehavior for ActiveModel {}
972        }
973
974        assert_eq!(hello::Column::IdentityCol.to_string().as_str(), "ID");
975        assert_eq!(hello::Column::One1.to_string().as_str(), "ONE");
976        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
977        assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE");
978    }
979
980    #[test]
981    #[cfg(feature = "macros")]
982    fn column_name_enum_name_3() {
983        use sea_query::Iden;
984
985        mod my_entity {
986            use crate as sea_orm;
987            use crate::entity::prelude::*;
988
989            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
990            #[sea_orm(table_name = "my_entity")]
991            pub struct Model {
992                #[sea_orm(primary_key, enum_name = "IdentityColumn", column_name = "id")]
993                pub id: i32,
994                #[sea_orm(column_name = "type")]
995                pub type_: String,
996            }
997
998            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
999            pub enum Relation {}
1000
1001            impl ActiveModelBehavior for ActiveModel {}
1002        }
1003
1004        assert_eq!(my_entity::Column::IdentityColumn.to_string().as_str(), "id");
1005        assert_eq!(my_entity::Column::Type.to_string().as_str(), "type");
1006    }
1007
1008    #[test]
1009    #[cfg(feature = "macros")]
1010    fn select_as_1() {
1011        use crate::{ActiveModelTrait, ActiveValue, Update};
1012
1013        mod hello_expanded {
1014            use crate as sea_orm;
1015            use crate::entity::prelude::*;
1016            use crate::sea_query::{Alias, Expr, SimpleExpr};
1017
1018            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1019            pub struct Entity;
1020
1021            impl EntityName for Entity {
1022                fn table_name(&self) -> &str {
1023                    "hello"
1024                }
1025            }
1026
1027            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1028            pub struct Model {
1029                pub id: i32,
1030                #[sea_orm(enum_name = "One1")]
1031                pub one: i32,
1032                pub two: i32,
1033                #[sea_orm(enum_name = "Three3")]
1034                pub three: i32,
1035            }
1036
1037            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1038            pub enum Column {
1039                Id,
1040                One1,
1041                Two,
1042                Three3,
1043            }
1044
1045            impl ColumnTrait for Column {
1046                type EntityName = Entity;
1047
1048                fn def(&self) -> ColumnDef {
1049                    match self {
1050                        Column::Id => ColumnType::Integer.def(),
1051                        Column::One1 => ColumnType::Integer.def(),
1052                        Column::Two => ColumnType::Integer.def(),
1053                        Column::Three3 => ColumnType::Integer.def(),
1054                    }
1055                }
1056
1057                fn select_as(&self, expr: Expr) -> SimpleExpr {
1058                    match self {
1059                        Self::Two => expr.cast_as(Alias::new("integer")),
1060                        _ => self.select_enum_as(expr),
1061                    }
1062                }
1063            }
1064
1065            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1066            pub enum PrimaryKey {
1067                Id,
1068            }
1069
1070            impl PrimaryKeyTrait for PrimaryKey {
1071                type ValueType = i32;
1072
1073                fn auto_increment() -> bool {
1074                    true
1075                }
1076            }
1077
1078            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1079            pub enum Relation {}
1080
1081            impl ActiveModelBehavior for ActiveModel {}
1082        }
1083
1084        #[allow(clippy::enum_variant_names)]
1085        mod hello_compact {
1086            use crate as sea_orm;
1087            use crate::entity::prelude::*;
1088
1089            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1090            #[sea_orm(table_name = "hello")]
1091            pub struct Model {
1092                #[sea_orm(primary_key)]
1093                pub id: i32,
1094                #[sea_orm(enum_name = "One1")]
1095                pub one: i32,
1096                #[sea_orm(select_as = "integer")]
1097                pub two: i32,
1098                #[sea_orm(enum_name = "Three3")]
1099                pub three: i32,
1100            }
1101
1102            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1103            pub enum Relation {}
1104
1105            impl ActiveModelBehavior for ActiveModel {}
1106        }
1107
1108        fn assert_it<E, A>(active_model: A)
1109        where
1110            E: EntityTrait,
1111            A: ActiveModelTrait<Entity = E>,
1112        {
1113            assert_eq!(
1114                E::find().build(DbBackend::Postgres).to_string(),
1115                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
1116            );
1117            assert_eq!(
1118                Update::one(active_model)
1119                    .build(DbBackend::Postgres)
1120                    .to_string(),
1121                r#"UPDATE "hello" SET "one1" = 1, "two" = 2, "three3" = 3 WHERE "hello"."id" = 1"#,
1122            );
1123        }
1124
1125        assert_it(hello_expanded::ActiveModel {
1126            id: ActiveValue::set(1),
1127            one: ActiveValue::set(1),
1128            two: ActiveValue::set(2),
1129            three: ActiveValue::set(3),
1130        });
1131        assert_it(hello_compact::ActiveModel {
1132            id: ActiveValue::set(1),
1133            one: ActiveValue::set(1),
1134            two: ActiveValue::set(2),
1135            three: ActiveValue::set(3),
1136        });
1137    }
1138
1139    #[test]
1140    #[cfg(feature = "macros")]
1141    fn save_as_1() {
1142        use crate::{ActiveModelTrait, ActiveValue, Update};
1143
1144        mod hello_expanded {
1145            use crate as sea_orm;
1146            use crate::entity::prelude::*;
1147            use crate::sea_query::{Alias, Expr, SimpleExpr};
1148
1149            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1150            pub struct Entity;
1151
1152            impl EntityName for Entity {
1153                fn table_name(&self) -> &str {
1154                    "hello"
1155                }
1156            }
1157
1158            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1159            pub struct Model {
1160                pub id: i32,
1161                #[sea_orm(enum_name = "One1")]
1162                pub one: i32,
1163                pub two: i32,
1164                #[sea_orm(enum_name = "Three3")]
1165                pub three: i32,
1166            }
1167
1168            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1169            pub enum Column {
1170                Id,
1171                One1,
1172                Two,
1173                Three3,
1174            }
1175
1176            impl ColumnTrait for Column {
1177                type EntityName = Entity;
1178
1179                fn def(&self) -> ColumnDef {
1180                    match self {
1181                        Column::Id => ColumnType::Integer.def(),
1182                        Column::One1 => ColumnType::Integer.def(),
1183                        Column::Two => ColumnType::Integer.def(),
1184                        Column::Three3 => ColumnType::Integer.def(),
1185                    }
1186                }
1187
1188                fn save_as(&self, val: Expr) -> SimpleExpr {
1189                    match self {
1190                        Self::Two => val.cast_as(Alias::new("text")),
1191                        _ => self.save_enum_as(val),
1192                    }
1193                }
1194            }
1195
1196            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1197            pub enum PrimaryKey {
1198                Id,
1199            }
1200
1201            impl PrimaryKeyTrait for PrimaryKey {
1202                type ValueType = i32;
1203
1204                fn auto_increment() -> bool {
1205                    true
1206                }
1207            }
1208
1209            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1210            pub enum Relation {}
1211
1212            impl ActiveModelBehavior for ActiveModel {}
1213        }
1214
1215        #[allow(clippy::enum_variant_names)]
1216        mod hello_compact {
1217            use crate as sea_orm;
1218            use crate::entity::prelude::*;
1219
1220            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1221            #[sea_orm(table_name = "hello")]
1222            pub struct Model {
1223                #[sea_orm(primary_key)]
1224                pub id: i32,
1225                #[sea_orm(enum_name = "One1")]
1226                pub one: i32,
1227                #[sea_orm(save_as = "text")]
1228                pub two: i32,
1229                #[sea_orm(enum_name = "Three3")]
1230                pub three: i32,
1231            }
1232
1233            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1234            pub enum Relation {}
1235
1236            impl ActiveModelBehavior for ActiveModel {}
1237        }
1238
1239        fn assert_it<E, A>(active_model: A)
1240        where
1241            E: EntityTrait,
1242            A: ActiveModelTrait<Entity = E>,
1243        {
1244            assert_eq!(
1245                E::find().build(DbBackend::Postgres).to_string(),
1246                r#"SELECT "hello"."id", "hello"."one1", "hello"."two", "hello"."three3" FROM "hello""#,
1247            );
1248            assert_eq!(
1249                Update::one(active_model)
1250                    .build(DbBackend::Postgres)
1251                    .to_string(),
1252                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1253            );
1254        }
1255
1256        assert_it(hello_expanded::ActiveModel {
1257            id: ActiveValue::set(1),
1258            one: ActiveValue::set(1),
1259            two: ActiveValue::set(2),
1260            three: ActiveValue::set(3),
1261        });
1262        assert_it(hello_compact::ActiveModel {
1263            id: ActiveValue::set(1),
1264            one: ActiveValue::set(1),
1265            two: ActiveValue::set(2),
1266            three: ActiveValue::set(3),
1267        });
1268    }
1269
1270    #[test]
1271    #[cfg(feature = "macros")]
1272    fn select_as_and_value_1() {
1273        use crate::{ActiveModelTrait, ActiveValue, Update};
1274
1275        mod hello_expanded {
1276            use crate as sea_orm;
1277            use crate::entity::prelude::*;
1278            use crate::sea_query::{Alias, Expr, SimpleExpr};
1279
1280            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
1281            pub struct Entity;
1282
1283            impl EntityName for Entity {
1284                fn table_name(&self) -> &str {
1285                    "hello"
1286                }
1287            }
1288
1289            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
1290            pub struct Model {
1291                pub id: i32,
1292                #[sea_orm(enum_name = "One1")]
1293                pub one: i32,
1294                pub two: i32,
1295                #[sea_orm(enum_name = "Three3")]
1296                pub three: i32,
1297            }
1298
1299            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
1300            pub enum Column {
1301                Id,
1302                One1,
1303                Two,
1304                Three3,
1305            }
1306
1307            impl ColumnTrait for Column {
1308                type EntityName = Entity;
1309
1310                fn def(&self) -> ColumnDef {
1311                    match self {
1312                        Column::Id => ColumnType::Integer.def(),
1313                        Column::One1 => ColumnType::Integer.def(),
1314                        Column::Two => ColumnType::Integer.def(),
1315                        Column::Three3 => ColumnType::Integer.def(),
1316                    }
1317                }
1318
1319                fn select_as(&self, expr: Expr) -> SimpleExpr {
1320                    match self {
1321                        Self::Two => expr.cast_as(Alias::new("integer")),
1322                        _ => self.select_enum_as(expr),
1323                    }
1324                }
1325
1326                fn save_as(&self, val: Expr) -> SimpleExpr {
1327                    match self {
1328                        Self::Two => val.cast_as(Alias::new("text")),
1329                        _ => self.save_enum_as(val),
1330                    }
1331                }
1332            }
1333
1334            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
1335            pub enum PrimaryKey {
1336                Id,
1337            }
1338
1339            impl PrimaryKeyTrait for PrimaryKey {
1340                type ValueType = i32;
1341
1342                fn auto_increment() -> bool {
1343                    true
1344                }
1345            }
1346
1347            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1348            pub enum Relation {}
1349
1350            impl ActiveModelBehavior for ActiveModel {}
1351        }
1352
1353        #[allow(clippy::enum_variant_names)]
1354        mod hello_compact {
1355            use crate as sea_orm;
1356            use crate::entity::prelude::*;
1357
1358            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
1359            #[sea_orm(table_name = "hello")]
1360            pub struct Model {
1361                #[sea_orm(primary_key)]
1362                pub id: i32,
1363                #[sea_orm(enum_name = "One1")]
1364                pub one: i32,
1365                #[sea_orm(select_as = "integer", save_as = "text")]
1366                pub two: i32,
1367                #[sea_orm(enum_name = "Three3")]
1368                pub three: i32,
1369            }
1370
1371            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
1372            pub enum Relation {}
1373
1374            impl ActiveModelBehavior for ActiveModel {}
1375        }
1376
1377        fn assert_it<E, A>(active_model: A)
1378        where
1379            E: EntityTrait,
1380            A: ActiveModelTrait<Entity = E>,
1381        {
1382            assert_eq!(
1383                E::find().build(DbBackend::Postgres).to_string(),
1384                r#"SELECT "hello"."id", "hello"."one1", CAST("hello"."two" AS integer), "hello"."three3" FROM "hello""#,
1385            );
1386            assert_eq!(
1387                Update::one(active_model)
1388                    .build(DbBackend::Postgres)
1389                    .to_string(),
1390                r#"UPDATE "hello" SET "one1" = 1, "two" = CAST(2 AS text), "three3" = 3 WHERE "hello"."id" = 1"#,
1391            );
1392        }
1393
1394        assert_it(hello_expanded::ActiveModel {
1395            id: ActiveValue::set(1),
1396            one: ActiveValue::set(1),
1397            two: ActiveValue::set(2),
1398            three: ActiveValue::set(3),
1399        });
1400        assert_it(hello_compact::ActiveModel {
1401            id: ActiveValue::set(1),
1402            one: ActiveValue::set(1),
1403            two: ActiveValue::set(2),
1404            three: ActiveValue::set(3),
1405        });
1406    }
1407}