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