sea_orm_codegen/entity/
column.rs

1use crate::{util::escape_rust_keyword, DateTimeCrate};
2use heck::{ToSnakeCase, ToUpperCamelCase};
3use proc_macro2::{Ident, TokenStream};
4use quote::{format_ident, quote};
5use sea_query::{ColumnDef, ColumnSpec, ColumnType, StringLen};
6use std::fmt::Write as FmtWrite;
7
8#[derive(Clone, Debug)]
9pub struct Column {
10    pub(crate) name: String,
11    pub(crate) col_type: ColumnType,
12    pub(crate) auto_increment: bool,
13    pub(crate) not_null: bool,
14    pub(crate) unique: bool,
15}
16
17impl Column {
18    pub fn get_name_snake_case(&self) -> Ident {
19        format_ident!("{}", escape_rust_keyword(self.name.to_snake_case()))
20    }
21
22    pub fn get_name_camel_case(&self) -> Ident {
23        format_ident!("{}", escape_rust_keyword(self.name.to_upper_camel_case()))
24    }
25
26    pub fn is_snake_case_name(&self) -> bool {
27        self.name.to_snake_case() == self.name
28    }
29
30    pub fn get_rs_type(&self, date_time_crate: &DateTimeCrate) -> TokenStream {
31        fn write_rs_type(col_type: &ColumnType, date_time_crate: &DateTimeCrate) -> String {
32            #[allow(unreachable_patterns)]
33            match col_type {
34                ColumnType::Char(_)
35                | ColumnType::String(_)
36                | ColumnType::Text
37                | ColumnType::Custom(_) => "String".to_owned(),
38                ColumnType::TinyInteger => "i8".to_owned(),
39                ColumnType::SmallInteger => "i16".to_owned(),
40                ColumnType::Integer => "i32".to_owned(),
41                ColumnType::BigInteger => "i64".to_owned(),
42                ColumnType::TinyUnsigned => "u8".to_owned(),
43                ColumnType::SmallUnsigned => "u16".to_owned(),
44                ColumnType::Unsigned => "u32".to_owned(),
45                ColumnType::BigUnsigned => "u64".to_owned(),
46                ColumnType::Float => "f32".to_owned(),
47                ColumnType::Double => "f64".to_owned(),
48                ColumnType::Json | ColumnType::JsonBinary => "Json".to_owned(),
49                ColumnType::Date => match date_time_crate {
50                    DateTimeCrate::Chrono => "Date".to_owned(),
51                    DateTimeCrate::Time => "TimeDate".to_owned(),
52                },
53                ColumnType::Time => match date_time_crate {
54                    DateTimeCrate::Chrono => "Time".to_owned(),
55                    DateTimeCrate::Time => "TimeTime".to_owned(),
56                },
57                ColumnType::DateTime => match date_time_crate {
58                    DateTimeCrate::Chrono => "DateTime".to_owned(),
59                    DateTimeCrate::Time => "TimeDateTime".to_owned(),
60                },
61                ColumnType::Timestamp => match date_time_crate {
62                    DateTimeCrate::Chrono => "DateTimeUtc".to_owned(),
63                    DateTimeCrate::Time => "TimeDateTime".to_owned(),
64                },
65                ColumnType::TimestampWithTimeZone => match date_time_crate {
66                    DateTimeCrate::Chrono => "DateTimeWithTimeZone".to_owned(),
67                    DateTimeCrate::Time => "TimeDateTimeWithTimeZone".to_owned(),
68                },
69                ColumnType::Decimal(_) | ColumnType::Money(_) => "Decimal".to_owned(),
70                ColumnType::Uuid => "Uuid".to_owned(),
71                ColumnType::Binary(_) | ColumnType::VarBinary(_) | ColumnType::Blob => {
72                    "Vec<u8>".to_owned()
73                }
74                ColumnType::Boolean => "bool".to_owned(),
75                ColumnType::Enum { name, .. } => name.to_string().to_upper_camel_case(),
76                ColumnType::Array(column_type) => {
77                    format!("Vec<{}>", write_rs_type(column_type, date_time_crate))
78                }
79                ColumnType::Bit(None | Some(1)) => "bool".to_owned(),
80                ColumnType::Bit(_) | ColumnType::VarBit(_) => "Vec<u8>".to_owned(),
81                ColumnType::Year => "i32".to_owned(),
82                ColumnType::Interval(_, _)
83                | ColumnType::Cidr
84                | ColumnType::Inet
85                | ColumnType::MacAddr
86                | ColumnType::LTree => "String".to_owned(),
87                _ => unimplemented!(),
88            }
89        }
90        let ident: TokenStream = write_rs_type(&self.col_type, date_time_crate)
91            .parse()
92            .unwrap();
93        match self.not_null {
94            true => quote! { #ident },
95            false => quote! { Option<#ident> },
96        }
97    }
98
99    pub fn get_col_type_attrs(&self) -> Option<TokenStream> {
100        let col_type = match &self.col_type {
101            ColumnType::Float => Some("Float".to_owned()),
102            ColumnType::Double => Some("Double".to_owned()),
103            ColumnType::Decimal(Some((p, s))) => Some(format!("Decimal(Some(({p}, {s})))")),
104            ColumnType::Money(Some((p, s))) => Some(format!("Money(Some({p}, {s}))")),
105            ColumnType::Text => Some("Text".to_owned()),
106            ColumnType::JsonBinary => Some("JsonBinary".to_owned()),
107            ColumnType::Custom(iden) => Some(format!("custom(\"{}\")", iden.to_string())),
108            ColumnType::Binary(s) => Some(format!("Binary({s})")),
109            ColumnType::VarBinary(s) => match s {
110                StringLen::N(s) => Some(format!("VarBinary(StringLen::N({s}))")),
111                StringLen::None => Some("VarBinary(StringLen::None)".to_owned()),
112                StringLen::Max => Some("VarBinary(StringLen::Max)".to_owned()),
113            },
114            ColumnType::Blob => Some("Blob".to_owned()),
115            _ => None,
116        };
117        col_type.map(|ty| quote! { column_type = #ty })
118    }
119
120    pub fn get_def(&self) -> TokenStream {
121        fn write_col_def(col_type: &ColumnType) -> TokenStream {
122            match col_type {
123                ColumnType::Char(s) => match s {
124                    Some(s) => quote! { ColumnType::Char(Some(#s)) },
125                    None => quote! { ColumnType::Char(None) },
126                },
127                ColumnType::String(s) => match s {
128                    StringLen::N(s) => quote! { ColumnType::String(StringLen::N(#s)) },
129                    StringLen::None => quote! { ColumnType::String(StringLen::None) },
130                    StringLen::Max => quote! { ColumnType::String(StringLen::Max) },
131                },
132                ColumnType::Text => quote! { ColumnType::Text },
133                ColumnType::TinyInteger => quote! { ColumnType::TinyInteger },
134                ColumnType::SmallInteger => quote! { ColumnType::SmallInteger },
135                ColumnType::Integer => quote! { ColumnType::Integer },
136                ColumnType::BigInteger => quote! { ColumnType::BigInteger },
137                ColumnType::TinyUnsigned => quote! { ColumnType::TinyUnsigned },
138                ColumnType::SmallUnsigned => quote! { ColumnType::SmallUnsigned },
139                ColumnType::Unsigned => quote! { ColumnType::Unsigned },
140                ColumnType::BigUnsigned => quote! { ColumnType::BigUnsigned },
141                ColumnType::Float => quote! { ColumnType::Float },
142                ColumnType::Double => quote! { ColumnType::Double },
143                ColumnType::Decimal(s) => match s {
144                    Some((s1, s2)) => quote! { ColumnType::Decimal(Some((#s1, #s2))) },
145                    None => quote! { ColumnType::Decimal(None) },
146                },
147                ColumnType::DateTime => quote! { ColumnType::DateTime },
148                ColumnType::Timestamp => quote! { ColumnType::Timestamp },
149                ColumnType::TimestampWithTimeZone => {
150                    quote! { ColumnType::TimestampWithTimeZone }
151                }
152                ColumnType::Time => quote! { ColumnType::Time },
153                ColumnType::Date => quote! { ColumnType::Date },
154                ColumnType::Binary(s) => {
155                    quote! { ColumnType::Binary(#s) }
156                }
157                ColumnType::VarBinary(s) => match s {
158                    StringLen::N(s) => quote! { ColumnType::VarBinary(StringLen::N(#s)) },
159                    StringLen::None => quote! { ColumnType::VarBinary(StringLen::None) },
160                    StringLen::Max => quote! { ColumnType::VarBinary(StringLen::Max) },
161                },
162                ColumnType::Blob => quote! { ColumnType::Blob },
163                ColumnType::Boolean => quote! { ColumnType::Boolean },
164                ColumnType::Money(s) => match s {
165                    Some((s1, s2)) => quote! { ColumnType::Money(Some((#s1, #s2))) },
166                    None => quote! { ColumnType::Money(None) },
167                },
168                ColumnType::Json => quote! { ColumnType::Json },
169                ColumnType::JsonBinary => quote! { ColumnType::JsonBinary },
170                ColumnType::Uuid => quote! { ColumnType::Uuid },
171                ColumnType::Custom(s) => {
172                    let s = s.to_string();
173                    quote! { ColumnType::custom(#s) }
174                }
175                ColumnType::Enum { name, .. } => {
176                    let enum_ident = format_ident!("{}", name.to_string().to_upper_camel_case());
177                    quote! { #enum_ident::db_type() }
178                }
179                ColumnType::Array(column_type) => {
180                    let column_type = write_col_def(column_type);
181                    quote! { ColumnType::Array(RcOrArc::new(#column_type)) }
182                }
183                #[allow(unreachable_patterns)]
184                _ => unimplemented!(),
185            }
186        }
187        let mut col_def = write_col_def(&self.col_type);
188        col_def.extend(quote! {
189            .def()
190        });
191        if !self.not_null {
192            col_def.extend(quote! {
193                .null()
194            });
195        }
196        if self.unique {
197            col_def.extend(quote! {
198                .unique()
199            });
200        }
201        col_def
202    }
203
204    pub fn get_info(&self, date_time_crate: &DateTimeCrate) -> String {
205        let mut info = String::new();
206        let type_info = self
207            .get_rs_type(date_time_crate)
208            .to_string()
209            .replace(' ', "");
210        let col_info = self.col_info();
211        write!(
212            &mut info,
213            "Column `{}`: {}{}",
214            self.name, type_info, col_info
215        )
216        .unwrap();
217        info
218    }
219
220    fn col_info(&self) -> String {
221        let mut info = String::new();
222        if self.auto_increment {
223            write!(&mut info, ", auto_increment").unwrap();
224        }
225        if self.not_null {
226            write!(&mut info, ", not_null").unwrap();
227        }
228        if self.unique {
229            write!(&mut info, ", unique").unwrap();
230        }
231        info
232    }
233
234    pub fn get_serde_attribute(
235        &self,
236        is_primary_key: bool,
237        serde_skip_deserializing_primary_key: bool,
238        serde_skip_hidden_column: bool,
239    ) -> TokenStream {
240        if self.name.starts_with('_') && serde_skip_hidden_column {
241            quote! {
242                #[serde(skip)]
243            }
244        } else if serde_skip_deserializing_primary_key && is_primary_key {
245            quote! {
246                #[serde(skip_deserializing)]
247            }
248        } else {
249            quote! {}
250        }
251    }
252
253    pub fn get_inner_col_type(&self) -> &ColumnType {
254        match &self.col_type {
255            ColumnType::Array(inner_col_type) => inner_col_type.as_ref(),
256            _ => &self.col_type,
257        }
258    }
259}
260
261impl From<ColumnDef> for Column {
262    fn from(col_def: ColumnDef) -> Self {
263        (&col_def).into()
264    }
265}
266
267impl From<&ColumnDef> for Column {
268    fn from(col_def: &ColumnDef) -> Self {
269        let name = col_def.get_column_name();
270        let col_type = match col_def.get_column_type() {
271            Some(ty) => ty.clone(),
272            None => panic!("ColumnType should not be empty"),
273        };
274        let auto_increment = col_def
275            .get_column_spec()
276            .iter()
277            .any(|spec| matches!(spec, ColumnSpec::AutoIncrement));
278        let not_null = col_def
279            .get_column_spec()
280            .iter()
281            .any(|spec| matches!(spec, ColumnSpec::NotNull));
282        let unique = col_def
283            .get_column_spec()
284            .iter()
285            .any(|spec| matches!(spec, ColumnSpec::UniqueKey));
286        Self {
287            name,
288            col_type,
289            auto_increment,
290            not_null,
291            unique,
292        }
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use crate::{Column, DateTimeCrate};
299    use proc_macro2::TokenStream;
300    use quote::quote;
301    use sea_query::{Alias, ColumnDef, ColumnType, SeaRc, StringLen};
302
303    fn setup() -> Vec<Column> {
304        macro_rules! make_col {
305            ($name:expr, $col_type:expr) => {
306                Column {
307                    name: $name.to_owned(),
308                    col_type: $col_type,
309                    auto_increment: false,
310                    not_null: false,
311                    unique: false,
312                }
313            };
314        }
315        vec![
316            make_col!("id", ColumnType::String(StringLen::N(255))),
317            make_col!("id", ColumnType::String(StringLen::None)),
318            make_col!(
319                "cake_id",
320                ColumnType::Custom(SeaRc::new(Alias::new("cus_col")))
321            ),
322            make_col!("CakeId", ColumnType::TinyInteger),
323            make_col!("CakeId", ColumnType::TinyUnsigned),
324            make_col!("CakeId", ColumnType::SmallInteger),
325            make_col!("CakeId", ColumnType::SmallUnsigned),
326            make_col!("CakeId", ColumnType::Integer),
327            make_col!("CakeId", ColumnType::Unsigned),
328            make_col!("CakeFillingId", ColumnType::BigInteger),
329            make_col!("CakeFillingId", ColumnType::BigUnsigned),
330            make_col!("cake-filling-id", ColumnType::Float),
331            make_col!("CAKE_FILLING_ID", ColumnType::Double),
332            make_col!("CAKE-FILLING-ID", ColumnType::Binary(10)),
333            make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::None)),
334            make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::N(10))),
335            make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::Max)),
336            make_col!("CAKE", ColumnType::Boolean),
337            make_col!("date", ColumnType::Date),
338            make_col!("time", ColumnType::Time),
339            make_col!("date_time", ColumnType::DateTime),
340            make_col!("timestamp", ColumnType::Timestamp),
341            make_col!("timestamp_tz", ColumnType::TimestampWithTimeZone),
342        ]
343    }
344
345    #[test]
346    fn test_get_name_snake_case() {
347        let columns = setup();
348        let snack_cases = vec![
349            "id",
350            "id",
351            "cake_id",
352            "cake_id",
353            "cake_id",
354            "cake_id",
355            "cake_id",
356            "cake_id",
357            "cake_id",
358            "cake_filling_id",
359            "cake_filling_id",
360            "cake_filling_id",
361            "cake_filling_id",
362            "cake_filling_id",
363            "cake_filling_id",
364            "cake_filling_id",
365            "cake_filling_id",
366            "cake",
367            "date",
368            "time",
369            "date_time",
370            "timestamp",
371            "timestamp_tz",
372        ];
373        for (col, snack_case) in columns.into_iter().zip(snack_cases) {
374            assert_eq!(col.get_name_snake_case().to_string(), snack_case);
375        }
376    }
377
378    #[test]
379    fn test_get_name_camel_case() {
380        let columns = setup();
381        let camel_cases = vec![
382            "Id",
383            "Id",
384            "CakeId",
385            "CakeId",
386            "CakeId",
387            "CakeId",
388            "CakeId",
389            "CakeId",
390            "CakeId",
391            "CakeFillingId",
392            "CakeFillingId",
393            "CakeFillingId",
394            "CakeFillingId",
395            "CakeFillingId",
396            "CakeFillingId",
397            "CakeFillingId",
398            "CakeFillingId",
399            "Cake",
400            "Date",
401            "Time",
402            "DateTime",
403            "Timestamp",
404            "TimestampTz",
405        ];
406        for (col, camel_case) in columns.into_iter().zip(camel_cases) {
407            assert_eq!(col.get_name_camel_case().to_string(), camel_case);
408        }
409    }
410
411    #[test]
412    fn test_get_rs_type_with_chrono() {
413        let columns = setup();
414        let chrono_crate = DateTimeCrate::Chrono;
415        let rs_types = vec![
416            "String",
417            "String",
418            "String",
419            "i8",
420            "u8",
421            "i16",
422            "u16",
423            "i32",
424            "u32",
425            "i64",
426            "u64",
427            "f32",
428            "f64",
429            "Vec<u8>",
430            "Vec<u8>",
431            "Vec<u8>",
432            "Vec<u8>",
433            "bool",
434            "Date",
435            "Time",
436            "DateTime",
437            "DateTimeUtc",
438            "DateTimeWithTimeZone",
439        ];
440        for (mut col, rs_type) in columns.into_iter().zip(rs_types) {
441            let rs_type: TokenStream = rs_type.parse().unwrap();
442
443            col.not_null = true;
444            assert_eq!(
445                col.get_rs_type(&chrono_crate).to_string(),
446                quote!(#rs_type).to_string()
447            );
448
449            col.not_null = false;
450            assert_eq!(
451                col.get_rs_type(&chrono_crate).to_string(),
452                quote!(Option<#rs_type>).to_string()
453            );
454        }
455    }
456
457    #[test]
458    fn test_get_rs_type_with_time() {
459        let columns = setup();
460        let time_crate = DateTimeCrate::Time;
461        let rs_types = vec![
462            "String",
463            "String",
464            "String",
465            "i8",
466            "u8",
467            "i16",
468            "u16",
469            "i32",
470            "u32",
471            "i64",
472            "u64",
473            "f32",
474            "f64",
475            "Vec<u8>",
476            "Vec<u8>",
477            "Vec<u8>",
478            "Vec<u8>",
479            "bool",
480            "TimeDate",
481            "TimeTime",
482            "TimeDateTime",
483            "TimeDateTime",
484            "TimeDateTimeWithTimeZone",
485        ];
486        for (mut col, rs_type) in columns.into_iter().zip(rs_types) {
487            let rs_type: TokenStream = rs_type.parse().unwrap();
488
489            col.not_null = true;
490            assert_eq!(
491                col.get_rs_type(&time_crate).to_string(),
492                quote!(#rs_type).to_string()
493            );
494
495            col.not_null = false;
496            assert_eq!(
497                col.get_rs_type(&time_crate).to_string(),
498                quote!(Option<#rs_type>).to_string()
499            );
500        }
501    }
502
503    #[test]
504    fn test_get_def() {
505        let columns = setup();
506        let col_defs = vec![
507            "ColumnType::String(StringLen::N(255u32)).def()",
508            "ColumnType::String(StringLen::None).def()",
509            "ColumnType::custom(\"cus_col\").def()",
510            "ColumnType::TinyInteger.def()",
511            "ColumnType::TinyUnsigned.def()",
512            "ColumnType::SmallInteger.def()",
513            "ColumnType::SmallUnsigned.def()",
514            "ColumnType::Integer.def()",
515            "ColumnType::Unsigned.def()",
516            "ColumnType::BigInteger.def()",
517            "ColumnType::BigUnsigned.def()",
518            "ColumnType::Float.def()",
519            "ColumnType::Double.def()",
520            "ColumnType::Binary(10u32).def()",
521            "ColumnType::VarBinary(StringLen::None).def()",
522            "ColumnType::VarBinary(StringLen::N(10u32)).def()",
523            "ColumnType::VarBinary(StringLen::Max).def()",
524            "ColumnType::Boolean.def()",
525            "ColumnType::Date.def()",
526            "ColumnType::Time.def()",
527            "ColumnType::DateTime.def()",
528            "ColumnType::Timestamp.def()",
529            "ColumnType::TimestampWithTimeZone.def()",
530        ];
531        for (mut col, col_def) in columns.into_iter().zip(col_defs) {
532            let mut col_def: TokenStream = col_def.parse().unwrap();
533
534            col.not_null = true;
535            assert_eq!(col.get_def().to_string(), col_def.to_string());
536
537            col.not_null = false;
538            col_def.extend(quote!(.null()));
539            assert_eq!(col.get_def().to_string(), col_def.to_string());
540
541            col.unique = true;
542            col_def.extend(quote!(.unique()));
543            assert_eq!(col.get_def().to_string(), col_def.to_string());
544        }
545    }
546
547    #[test]
548    fn test_get_info() {
549        let column: Column = ColumnDef::new(Alias::new("id")).string().to_owned().into();
550        assert_eq!(
551            column.get_info(&DateTimeCrate::Chrono).as_str(),
552            "Column `id`: Option<String>"
553        );
554
555        let column: Column = ColumnDef::new(Alias::new("id"))
556            .string()
557            .not_null()
558            .to_owned()
559            .into();
560        assert_eq!(
561            column.get_info(&DateTimeCrate::Chrono).as_str(),
562            "Column `id`: String, not_null"
563        );
564
565        let column: Column = ColumnDef::new(Alias::new("id"))
566            .string()
567            .not_null()
568            .unique_key()
569            .to_owned()
570            .into();
571        assert_eq!(
572            column.get_info(&DateTimeCrate::Chrono).as_str(),
573            "Column `id`: String, not_null, unique"
574        );
575
576        let column: Column = ColumnDef::new(Alias::new("id"))
577            .string()
578            .not_null()
579            .unique_key()
580            .auto_increment()
581            .to_owned()
582            .into();
583        assert_eq!(
584            column.get_info(&DateTimeCrate::Chrono).as_str(),
585            "Column `id`: String, auto_increment, not_null, unique"
586        );
587
588        let column: Column = ColumnDef::new(Alias::new("date_field"))
589            .date()
590            .not_null()
591            .to_owned()
592            .into();
593        assert_eq!(
594            column.get_info(&DateTimeCrate::Chrono).as_str(),
595            "Column `date_field`: Date, not_null"
596        );
597
598        let column: Column = ColumnDef::new(Alias::new("date_field"))
599            .date()
600            .not_null()
601            .to_owned()
602            .into();
603        assert_eq!(
604            column.get_info(&DateTimeCrate::Time).as_str(),
605            "Column `date_field`: TimeDate, not_null"
606        );
607
608        let column: Column = ColumnDef::new(Alias::new("time_field"))
609            .time()
610            .not_null()
611            .to_owned()
612            .into();
613        assert_eq!(
614            column.get_info(&DateTimeCrate::Chrono).as_str(),
615            "Column `time_field`: Time, not_null"
616        );
617
618        let column: Column = ColumnDef::new(Alias::new("time_field"))
619            .time()
620            .not_null()
621            .to_owned()
622            .into();
623        assert_eq!(
624            column.get_info(&DateTimeCrate::Time).as_str(),
625            "Column `time_field`: TimeTime, not_null"
626        );
627
628        let column: Column = ColumnDef::new(Alias::new("date_time_field"))
629            .date_time()
630            .not_null()
631            .to_owned()
632            .into();
633        assert_eq!(
634            column.get_info(&DateTimeCrate::Chrono).as_str(),
635            "Column `date_time_field`: DateTime, not_null"
636        );
637
638        let column: Column = ColumnDef::new(Alias::new("date_time_field"))
639            .date_time()
640            .not_null()
641            .to_owned()
642            .into();
643        assert_eq!(
644            column.get_info(&DateTimeCrate::Time).as_str(),
645            "Column `date_time_field`: TimeDateTime, not_null"
646        );
647
648        let column: Column = ColumnDef::new(Alias::new("timestamp_field"))
649            .timestamp()
650            .not_null()
651            .to_owned()
652            .into();
653        assert_eq!(
654            column.get_info(&DateTimeCrate::Chrono).as_str(),
655            "Column `timestamp_field`: DateTimeUtc, not_null"
656        );
657
658        let column: Column = ColumnDef::new(Alias::new("timestamp_field"))
659            .timestamp()
660            .not_null()
661            .to_owned()
662            .into();
663        assert_eq!(
664            column.get_info(&DateTimeCrate::Time).as_str(),
665            "Column `timestamp_field`: TimeDateTime, not_null"
666        );
667
668        let column: Column = ColumnDef::new(Alias::new("timestamp_with_timezone_field"))
669            .timestamp_with_time_zone()
670            .not_null()
671            .to_owned()
672            .into();
673        assert_eq!(
674            column.get_info(&DateTimeCrate::Chrono).as_str(),
675            "Column `timestamp_with_timezone_field`: DateTimeWithTimeZone, not_null"
676        );
677
678        let column: Column = ColumnDef::new(Alias::new("timestamp_with_timezone_field"))
679            .timestamp_with_time_zone()
680            .not_null()
681            .to_owned()
682            .into();
683        assert_eq!(
684            column.get_info(&DateTimeCrate::Time).as_str(),
685            "Column `timestamp_with_timezone_field`: TimeDateTimeWithTimeZone, not_null"
686        );
687    }
688
689    #[test]
690    fn test_from_column_def() {
691        let column: Column = ColumnDef::new(Alias::new("id")).string().to_owned().into();
692        assert_eq!(
693            column.get_def().to_string(),
694            quote! {
695                ColumnType::String(StringLen::None).def().null()
696            }
697            .to_string()
698        );
699
700        let column: Column = ColumnDef::new(Alias::new("id"))
701            .string()
702            .not_null()
703            .to_owned()
704            .into();
705        assert!(column.not_null);
706
707        let column: Column = ColumnDef::new(Alias::new("id"))
708            .string()
709            .unique_key()
710            .not_null()
711            .to_owned()
712            .into();
713        assert!(column.unique);
714        assert!(column.not_null);
715
716        let column: Column = ColumnDef::new(Alias::new("id"))
717            .string()
718            .auto_increment()
719            .unique_key()
720            .not_null()
721            .to_owned()
722            .into();
723        assert!(column.auto_increment);
724        assert!(column.unique);
725        assert!(column.not_null);
726    }
727}