Skip to main content

sea_orm/entity/
column_def.rs

1use sea_query::{SimpleExpr, Value};
2
3// The original `sea_orm::ColumnType` enum was dropped since 0.11.0
4// It was replaced by `sea_query::ColumnType`, we reexport it here to keep the `ColumnType` symbol
5pub use sea_query::ColumnType;
6
7/// Schema metadata for a single column: SQL type, nullability, defaults,
8/// constraints, and other DDL-level options.
9///
10/// Returned by [`ColumnTrait::def`](crate::ColumnTrait::def) and used by
11/// SeaORM's schema builder to generate `CREATE TABLE` / `ALTER TABLE`
12/// statements. Most fields are set declaratively via attributes on a
13/// `#[derive(DeriveEntityModel)]` `Model`; the chainable methods below
14/// cover the cases that need to be configured at runtime.
15#[derive(Debug, Clone, PartialEq)]
16pub struct ColumnDef {
17    pub(crate) col_type: ColumnType,
18    pub(crate) null: bool,
19    pub(crate) unique: bool,
20    pub(crate) indexed: bool,
21    pub(crate) default: Option<SimpleExpr>,
22    pub(crate) comment: Option<String>,
23    pub(crate) unique_key: Option<String>,
24    pub(crate) renamed_from: Option<String>,
25    pub(crate) extra: Option<String>,
26    pub(crate) seaography: SeaographyColumnAttr,
27}
28
29/// Column-level attributes consumed by [Seaography](https://github.com/SeaQL/seaography)
30/// when generating GraphQL schemas.
31#[non_exhaustive]
32#[derive(Debug, Default, Clone, PartialEq)]
33pub struct SeaographyColumnAttr {
34    /// If `true`, this column is omitted from Seaography's GraphQL schema.
35    pub ignore: bool,
36}
37
38impl ColumnDef {
39    /// Marks the column as `UNIQUE`
40    pub fn unique(mut self) -> Self {
41        self.unique = true;
42        self
43    }
44
45    /// Set Seaography ignore
46    pub fn seaography_ignore(mut self) -> Self {
47        self.seaography.ignore = true;
48        self
49    }
50
51    /// This column belongs to a unique key
52    pub fn unique_key(mut self, key: &str) -> Self {
53        self.unique_key = Some(key.into());
54        self
55    }
56
57    /// This column is renamed from a previous name
58    pub fn renamed_from(mut self, col: &str) -> Self {
59        self.renamed_from = Some(col.into());
60        self
61    }
62
63    /// Set column comment
64    pub fn comment(mut self, v: &str) -> Self {
65        self.comment = Some(v.into());
66        self
67    }
68
69    /// Mark the column as nullable
70    pub fn null(self) -> Self {
71        self.nullable()
72    }
73
74    /// Mark the column as nullable
75    pub fn nullable(mut self) -> Self {
76        self.null = true;
77        self
78    }
79
80    /// Set the `indexed` field  to `true`
81    pub fn indexed(mut self) -> Self {
82        self.indexed = true;
83        self
84    }
85
86    /// Set the default value
87    pub fn default_value<T>(mut self, value: T) -> Self
88    where
89        T: Into<Value>,
90    {
91        self.default = Some(value.into().into());
92        self
93    }
94
95    /// Set the default value or expression of a column
96    pub fn default<T>(mut self, default: T) -> Self
97    where
98        T: Into<SimpleExpr>,
99    {
100        self.default = Some(default.into());
101        self
102    }
103
104    /// Set the extra SQL string for the column (e.g. "COLLATE NOCASE")
105    pub fn extra(mut self, value: &str) -> Self {
106        self.extra = Some(value.into());
107        self
108    }
109
110    /// Get [ColumnType] as reference
111    pub fn get_column_type(&self) -> &ColumnType {
112        &self.col_type
113    }
114
115    /// Get the column's default value/expression, if one is set.
116    pub fn get_column_default(&self) -> Option<&SimpleExpr> {
117        self.default.as_ref()
118    }
119
120    /// Returns true if the column is nullable
121    pub fn is_null(&self) -> bool {
122        self.null
123    }
124
125    /// Returns true if the column is unique
126    pub fn is_unique(&self) -> bool {
127        self.unique
128    }
129
130    /// Get Seaography attribute
131    pub fn seaography(&self) -> &SeaographyColumnAttr {
132        &self.seaography
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use crate::tests_cfg::*;
139
140    #[test]
141    fn test_col_from_str() {
142        use crate::IdenStatic;
143        use std::str::FromStr;
144
145        assert!(matches!(
146            fruit::Column::from_str("id"),
147            Ok(fruit::Column::Id)
148        ));
149        assert!(matches!(
150            fruit::Column::from_str("name"),
151            Ok(fruit::Column::Name)
152        ));
153        assert!(matches!(
154            fruit::Column::from_str("cake_id"),
155            Ok(fruit::Column::CakeId)
156        ));
157        assert!(matches!(
158            fruit::Column::from_str("cakeId"),
159            Ok(fruit::Column::CakeId)
160        ));
161        assert!(matches!(
162            fruit::Column::from_str("CakeId"),
163            Err(crate::ColumnFromStrErr(_))
164        ));
165        assert!(matches!(
166            fruit::Column::from_str("does_not_exist"),
167            Err(crate::ColumnFromStrErr(_))
168        ));
169        assert!(matches!(fruit::Column::CakeId.as_str(), "cake_id"));
170    }
171
172    #[test]
173    #[cfg(feature = "macros")]
174    fn entity_model_column_1() {
175        use crate::prelude::*;
176
177        mod hello {
178            use crate as sea_orm;
179            use crate::entity::prelude::*;
180
181            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
182            #[sea_orm(table_name = "hello")]
183            pub struct Model {
184                #[sea_orm(primary_key)]
185                pub id: i32,
186                pub one: i32,
187                #[sea_orm(unique)]
188                pub two: i8,
189                #[sea_orm(indexed)]
190                pub three: i16,
191                #[sea_orm(nullable)]
192                pub four: i32,
193                #[sea_orm(unique, indexed, nullable)]
194                pub five: i64,
195                #[sea_orm(unique)]
196                pub six: u8,
197                #[sea_orm(indexed)]
198                pub seven: u16,
199                #[sea_orm(nullable)]
200                pub eight: u32,
201                #[sea_orm(unique, indexed, nullable)]
202                pub nine: u64,
203                #[sea_orm(default_expr = "Expr::current_timestamp()")]
204                pub ten: DateTimeUtc,
205                #[sea_orm(default_value = 7)]
206                pub eleven: u8,
207                #[sea_orm(default_value = "twelve_value")]
208                pub twelve: String,
209                #[sea_orm(default_expr = "\"twelve_value\"")]
210                pub twelve_two: String,
211            }
212
213            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
214            pub enum Relation {}
215
216            impl ActiveModelBehavior for ActiveModel {}
217        }
218
219        assert_eq!(hello::Column::One.def(), ColumnType::Integer.def());
220        assert_eq!(
221            hello::Column::Two.def(),
222            ColumnType::TinyInteger.def().unique()
223        );
224        assert_eq!(
225            hello::Column::Three.def(),
226            ColumnType::SmallInteger.def().indexed()
227        );
228        assert_eq!(
229            hello::Column::Four.def(),
230            ColumnType::Integer.def().nullable()
231        );
232        assert_eq!(
233            hello::Column::Five.def(),
234            ColumnType::BigInteger.def().unique().indexed().nullable()
235        );
236        assert_eq!(
237            hello::Column::Six.def(),
238            ColumnType::TinyUnsigned.def().unique()
239        );
240        assert_eq!(
241            hello::Column::Seven.def(),
242            ColumnType::SmallUnsigned.def().indexed()
243        );
244        assert_eq!(
245            hello::Column::Eight.def(),
246            ColumnType::Unsigned.def().nullable()
247        );
248        assert_eq!(
249            hello::Column::Nine.def(),
250            ColumnType::BigUnsigned.def().unique().indexed().nullable()
251        );
252        assert_eq!(
253            hello::Column::Ten.def(),
254            ColumnType::TimestampWithTimeZone
255                .def()
256                .default(Expr::current_timestamp())
257        );
258        assert_eq!(
259            hello::Column::Eleven.def(),
260            ColumnType::TinyUnsigned.def().default(7)
261        );
262        assert_eq!(
263            hello::Column::Twelve.def(),
264            ColumnType::String(StringLen::None)
265                .def()
266                .default("twelve_value")
267        );
268        assert_eq!(
269            hello::Column::TwelveTwo.def(),
270            ColumnType::String(StringLen::None)
271                .def()
272                .default("twelve_value")
273        );
274    }
275
276    #[test]
277    #[cfg(feature = "macros")]
278    fn column_name_1() {
279        use crate::ColumnTrait;
280        use sea_query::Iden;
281
282        mod hello {
283            use crate as sea_orm;
284            use crate::entity::prelude::*;
285
286            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
287            #[sea_orm(table_name = "hello")]
288            pub struct Model {
289                #[sea_orm(primary_key)]
290                pub id: i32,
291                #[sea_orm(column_name = "ONE")]
292                pub one: i32,
293                #[seaography(ignore)]
294                pub two: i32,
295                #[sea_orm(column_name = "3")]
296                #[seaography(ignore)]
297                pub three: i32,
298            }
299
300            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
301            pub enum Relation {}
302
303            impl ActiveModelBehavior for ActiveModel {}
304        }
305
306        assert_eq!(hello::Column::One.to_string().as_str(), "ONE");
307        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
308        assert_eq!(hello::Column::Three.to_string().as_str(), "3");
309
310        assert!(!hello::Column::One.def().seaography().ignore);
311        assert!(hello::Column::Two.def().seaography().ignore);
312        assert!(hello::Column::Three.def().seaography().ignore);
313    }
314
315    #[test]
316    #[cfg(feature = "macros")]
317    fn column_name_2() {
318        use sea_query::Iden;
319
320        mod hello {
321            use crate as sea_orm;
322            use crate::entity::prelude::*;
323
324            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
325            pub struct Entity;
326
327            impl EntityName for Entity {
328                fn table_name(&self) -> &'static str {
329                    "hello"
330                }
331            }
332
333            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
334            pub struct Model {
335                pub id: i32,
336                pub one: i32,
337                pub two: i32,
338                pub three: i32,
339            }
340
341            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
342            pub enum Column {
343                Id,
344                #[sea_orm(column_name = "ONE")]
345                One,
346                Two,
347                #[sea_orm(column_name = "3")]
348                Three,
349            }
350
351            impl ColumnTrait for Column {
352                type EntityName = Entity;
353
354                fn def(&self) -> ColumnDef {
355                    match self {
356                        Column::Id => ColumnType::Integer.def(),
357                        Column::One => ColumnType::Integer.def(),
358                        Column::Two => ColumnType::Integer.def(),
359                        Column::Three => ColumnType::Integer.def(),
360                    }
361                }
362            }
363
364            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
365            pub enum PrimaryKey {
366                Id,
367            }
368
369            impl PrimaryKeyTrait for PrimaryKey {
370                type ValueType = i32;
371
372                fn auto_increment() -> bool {
373                    true
374                }
375            }
376
377            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
378            pub enum Relation {}
379
380            impl ActiveModelBehavior for ActiveModel {}
381        }
382
383        assert_eq!(hello::Column::One.to_string().as_str(), "ONE");
384        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
385        assert_eq!(hello::Column::Three.to_string().as_str(), "3");
386    }
387
388    #[test]
389    #[cfg(feature = "macros")]
390    fn enum_name_1() {
391        use sea_query::Iden;
392
393        mod hello {
394            use crate as sea_orm;
395            use crate::entity::prelude::*;
396
397            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
398            #[sea_orm(table_name = "hello")]
399            pub struct Model {
400                #[sea_orm(primary_key)]
401                pub id: i32,
402                #[sea_orm(enum_name = "One1")]
403                pub one: i32,
404                pub two: i32,
405                #[sea_orm(enum_name = "Three3")]
406                pub three: i32,
407            }
408
409            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
410            pub enum Relation {}
411
412            impl ActiveModelBehavior for ActiveModel {}
413        }
414
415        assert_eq!(hello::Column::One1.to_string().as_str(), "one1");
416        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
417        assert_eq!(hello::Column::Three3.to_string().as_str(), "three3");
418    }
419
420    #[test]
421    #[cfg(feature = "macros")]
422    fn enum_name_2() {
423        use sea_query::Iden;
424
425        mod hello {
426            use crate as sea_orm;
427            use crate::entity::prelude::*;
428
429            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
430            pub struct Entity;
431
432            impl EntityName for Entity {
433                fn table_name(&self) -> &'static str {
434                    "hello"
435                }
436            }
437
438            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
439            pub struct Model {
440                pub id: i32,
441                #[sea_orm(enum_name = "One1")]
442                pub one: i32,
443                pub two: i32,
444                #[sea_orm(enum_name = "Three3")]
445                pub three: i32,
446            }
447
448            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
449            pub enum Column {
450                Id,
451                One1,
452                Two,
453                Three3,
454            }
455
456            impl ColumnTrait for Column {
457                type EntityName = Entity;
458
459                fn def(&self) -> ColumnDef {
460                    match self {
461                        Column::Id => ColumnType::Integer.def(),
462                        Column::One1 => ColumnType::Integer.def(),
463                        Column::Two => ColumnType::Integer.def(),
464                        Column::Three3 => ColumnType::Integer.def(),
465                    }
466                }
467            }
468
469            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
470            pub enum PrimaryKey {
471                Id,
472            }
473
474            impl PrimaryKeyTrait for PrimaryKey {
475                type ValueType = i32;
476
477                fn auto_increment() -> bool {
478                    true
479                }
480            }
481
482            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
483            pub enum Relation {}
484
485            impl ActiveModelBehavior for ActiveModel {}
486        }
487
488        assert_eq!(hello::Column::One1.to_string().as_str(), "one1");
489        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
490        assert_eq!(hello::Column::Three3.to_string().as_str(), "three3");
491    }
492
493    #[test]
494    #[cfg(feature = "macros")]
495    fn column_name_enum_name_1() {
496        use sea_query::Iden;
497
498        #[allow(clippy::enum_variant_names)]
499        mod hello {
500            use crate as sea_orm;
501            use crate::entity::prelude::*;
502
503            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
504            #[sea_orm(table_name = "hello")]
505            pub struct Model {
506                #[sea_orm(primary_key, column_name = "ID", enum_name = "IdentityColumn")]
507                pub id: i32,
508                #[sea_orm(column_name = "ONE", enum_name = "One1")]
509                pub one: i32,
510                pub two: i32,
511                #[sea_orm(column_name = "THREE", enum_name = "Three3")]
512                pub three: i32,
513            }
514
515            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
516            pub enum Relation {}
517
518            impl ActiveModelBehavior for ActiveModel {}
519        }
520
521        assert_eq!(hello::Column::IdentityColumn.to_string().as_str(), "ID");
522        assert_eq!(hello::Column::One1.to_string().as_str(), "ONE");
523        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
524        assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE");
525    }
526
527    #[test]
528    #[cfg(feature = "macros")]
529    fn column_name_enum_name_2() {
530        use sea_query::Iden;
531
532        mod hello {
533            use crate as sea_orm;
534            use crate::entity::prelude::*;
535
536            #[derive(Copy, Clone, Default, Debug, DeriveEntity)]
537            pub struct Entity;
538
539            impl EntityName for Entity {
540                fn table_name(&self) -> &'static str {
541                    "hello"
542                }
543            }
544
545            #[derive(Clone, Debug, PartialEq, Eq, DeriveModel, DeriveActiveModel)]
546            pub struct Model {
547                #[sea_orm(enum_name = "IdentityCol")]
548                pub id: i32,
549                #[sea_orm(enum_name = "One1")]
550                pub one: i32,
551                pub two: i32,
552                #[sea_orm(enum_name = "Three3")]
553                pub three: i32,
554            }
555
556            #[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)]
557            pub enum Column {
558                #[sea_orm(column_name = "ID")]
559                IdentityCol,
560                #[sea_orm(column_name = "ONE")]
561                One1,
562                Two,
563                #[sea_orm(column_name = "THREE")]
564                Three3,
565            }
566
567            impl ColumnTrait for Column {
568                type EntityName = Entity;
569
570                fn def(&self) -> ColumnDef {
571                    match self {
572                        Column::IdentityCol => ColumnType::Integer.def(),
573                        Column::One1 => ColumnType::Integer.def(),
574                        Column::Two => ColumnType::Integer.def(),
575                        Column::Three3 => ColumnType::Integer.def(),
576                    }
577                }
578            }
579
580            #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)]
581            pub enum PrimaryKey {
582                IdentityCol,
583            }
584
585            impl PrimaryKeyTrait for PrimaryKey {
586                type ValueType = i32;
587
588                fn auto_increment() -> bool {
589                    true
590                }
591            }
592
593            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
594            pub enum Relation {}
595
596            impl ActiveModelBehavior for ActiveModel {}
597        }
598
599        assert_eq!(hello::Column::IdentityCol.to_string().as_str(), "ID");
600        assert_eq!(hello::Column::One1.to_string().as_str(), "ONE");
601        assert_eq!(hello::Column::Two.to_string().as_str(), "two");
602        assert_eq!(hello::Column::Three3.to_string().as_str(), "THREE");
603    }
604
605    #[test]
606    #[cfg(feature = "macros")]
607    fn column_name_enum_name_3() {
608        use sea_query::Iden;
609
610        mod my_entity {
611            use crate as sea_orm;
612            use crate::entity::prelude::*;
613
614            #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
615            #[sea_orm(table_name = "my_entity")]
616            pub struct Model {
617                #[sea_orm(primary_key, enum_name = "IdentityColumn", column_name = "id")]
618                pub id: i32,
619                #[sea_orm(column_name = "type")]
620                pub type_: String,
621            }
622
623            #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
624            pub enum Relation {}
625
626            impl ActiveModelBehavior for ActiveModel {}
627        }
628
629        assert_eq!(my_entity::Column::IdentityColumn.to_string().as_str(), "id");
630        assert_eq!(my_entity::Column::Type.to_string().as_str(), "type");
631    }
632
633    #[test]
634    #[cfg(feature = "macros")]
635    fn column_def_unique_key() {
636        use crate as sea_orm;
637        use crate::entity::prelude::*;
638
639        #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
640        #[sea_orm(table_name = "my_entity")]
641        pub struct Model {
642            #[sea_orm(primary_key)]
643            pub id: i32,
644            #[sea_orm(column_name = "my_a", unique_key = "my_unique")]
645            pub a: String,
646            #[sea_orm(unique_key = "my_unique")]
647            pub b: String,
648        }
649
650        #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
651        pub enum Relation {}
652
653        impl ActiveModelBehavior for ActiveModel {}
654
655        assert_eq!(
656            Column::A.def(),
657            ColumnType::string(None).def().unique_key("my_unique")
658        );
659        assert_eq!(
660            Column::B.def(),
661            ColumnType::string(None).def().unique_key("my_unique")
662        );
663    }
664
665    #[test]
666    #[cfg(feature = "macros")]
667    fn column_def_renamed_from() {
668        use crate as sea_orm;
669        use crate::entity::prelude::*;
670
671        #[derive(Clone, Debug, PartialEq, Eq, DeriveEntityModel)]
672        #[sea_orm(table_name = "my_entity")]
673        pub struct Model {
674            #[sea_orm(primary_key)]
675            pub id: i32,
676            #[sea_orm(column_name = "new_a", renamed_from = "old_a")]
677            pub a: String,
678            #[sea_orm(renamed_from = "old_b")]
679            pub b: String,
680        }
681
682        #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
683        pub enum Relation {}
684
685        impl ActiveModelBehavior for ActiveModel {}
686
687        assert_eq!(Column::A.to_string(), "new_a");
688        assert_eq!(Column::B.to_string(), "b");
689
690        assert_eq!(
691            Column::A.def(),
692            ColumnType::string(None).def().renamed_from("old_a")
693        );
694        assert_eq!(
695            Column::B.def(),
696            ColumnType::string(None).def().renamed_from("old_b")
697        );
698    }
699}