sea_orm/entity/
column.rs

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