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