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}