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