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) => Some(format!("custom(\"{iden}\")")),
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.get_column_spec().auto_increment;
286 let not_null = match col_def.get_column_spec().nullable {
287 Some(nullable) => !nullable,
288 None => false,
289 };
290 let unique = col_def.get_column_spec().unique;
291 Self {
292 name,
293 col_type,
294 auto_increment,
295 not_null,
296 unique,
297 }
298 }
299}
300
301#[cfg(test)]
302mod tests {
303 use crate::{Column, DateTimeCrate};
304 use proc_macro2::TokenStream;
305 use quote::quote;
306 use sea_query::{Alias, ColumnDef, ColumnType, SeaRc, StringLen};
307
308 fn setup() -> Vec<Column> {
309 macro_rules! make_col {
310 ($name:expr, $col_type:expr) => {
311 Column {
312 name: $name.to_owned(),
313 col_type: $col_type,
314 auto_increment: false,
315 not_null: false,
316 unique: false,
317 }
318 };
319 }
320 vec![
321 make_col!("id", ColumnType::String(StringLen::N(255))),
322 make_col!("id", ColumnType::String(StringLen::None)),
323 make_col!(
324 "cake_id",
325 ColumnType::Custom(SeaRc::new(Alias::new("cus_col")))
326 ),
327 make_col!("CakeId", ColumnType::TinyInteger),
328 make_col!("CakeId", ColumnType::TinyUnsigned),
329 make_col!("CakeId", ColumnType::SmallInteger),
330 make_col!("CakeId", ColumnType::SmallUnsigned),
331 make_col!("CakeId", ColumnType::Integer),
332 make_col!("CakeId", ColumnType::Unsigned),
333 make_col!("CakeFillingId", ColumnType::BigInteger),
334 make_col!("CakeFillingId", ColumnType::BigUnsigned),
335 make_col!("cake-filling-id", ColumnType::Float),
336 make_col!("CAKE_FILLING_ID", ColumnType::Double),
337 make_col!("CAKE-FILLING-ID", ColumnType::Binary(10)),
338 make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::None)),
339 make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::N(10))),
340 make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::Max)),
341 make_col!("CAKE", ColumnType::Boolean),
342 make_col!("date", ColumnType::Date),
343 make_col!("time", ColumnType::Time),
344 make_col!("date_time", ColumnType::DateTime),
345 make_col!("timestamp", ColumnType::Timestamp),
346 make_col!("timestamp_tz", ColumnType::TimestampWithTimeZone),
347 ]
348 }
349
350 #[test]
351 fn test_get_name_snake_case() {
352 let columns = setup();
353 let snack_cases = vec![
354 "id",
355 "id",
356 "cake_id",
357 "cake_id",
358 "cake_id",
359 "cake_id",
360 "cake_id",
361 "cake_id",
362 "cake_id",
363 "cake_filling_id",
364 "cake_filling_id",
365 "cake_filling_id",
366 "cake_filling_id",
367 "cake_filling_id",
368 "cake_filling_id",
369 "cake_filling_id",
370 "cake_filling_id",
371 "cake",
372 "date",
373 "time",
374 "date_time",
375 "timestamp",
376 "timestamp_tz",
377 ];
378 for (col, snack_case) in columns.into_iter().zip(snack_cases) {
379 assert_eq!(col.get_name_snake_case().to_string(), snack_case);
380 }
381 }
382
383 #[test]
384 fn test_get_name_camel_case() {
385 let columns = setup();
386 let camel_cases = vec![
387 "Id",
388 "Id",
389 "CakeId",
390 "CakeId",
391 "CakeId",
392 "CakeId",
393 "CakeId",
394 "CakeId",
395 "CakeId",
396 "CakeFillingId",
397 "CakeFillingId",
398 "CakeFillingId",
399 "CakeFillingId",
400 "CakeFillingId",
401 "CakeFillingId",
402 "CakeFillingId",
403 "CakeFillingId",
404 "Cake",
405 "Date",
406 "Time",
407 "DateTime",
408 "Timestamp",
409 "TimestampTz",
410 ];
411 for (col, camel_case) in columns.into_iter().zip(camel_cases) {
412 assert_eq!(col.get_name_camel_case().to_string(), camel_case);
413 }
414 }
415
416 #[test]
417 fn test_get_rs_type_with_chrono() {
418 let columns = setup();
419 let chrono_crate = DateTimeCrate::Chrono;
420 let rs_types = vec![
421 "String",
422 "String",
423 "String",
424 "i8",
425 "u8",
426 "i16",
427 "u16",
428 "i32",
429 "u32",
430 "i64",
431 "u64",
432 "f32",
433 "f64",
434 "Vec<u8>",
435 "Vec<u8>",
436 "Vec<u8>",
437 "Vec<u8>",
438 "bool",
439 "Date",
440 "Time",
441 "DateTime",
442 "DateTimeUtc",
443 "DateTimeWithTimeZone",
444 ];
445 for (mut col, rs_type) in columns.into_iter().zip(rs_types) {
446 let rs_type: TokenStream = rs_type.parse().unwrap();
447
448 col.not_null = true;
449 assert_eq!(
450 col.get_rs_type(&chrono_crate).to_string(),
451 quote!(#rs_type).to_string()
452 );
453
454 col.not_null = false;
455 assert_eq!(
456 col.get_rs_type(&chrono_crate).to_string(),
457 quote!(Option<#rs_type>).to_string()
458 );
459 }
460 }
461
462 #[test]
463 fn test_get_rs_type_with_time() {
464 let columns = setup();
465 let time_crate = DateTimeCrate::Time;
466 let rs_types = vec![
467 "String",
468 "String",
469 "String",
470 "i8",
471 "u8",
472 "i16",
473 "u16",
474 "i32",
475 "u32",
476 "i64",
477 "u64",
478 "f32",
479 "f64",
480 "Vec<u8>",
481 "Vec<u8>",
482 "Vec<u8>",
483 "Vec<u8>",
484 "bool",
485 "TimeDate",
486 "TimeTime",
487 "TimeDateTime",
488 "TimeDateTime",
489 "TimeDateTimeWithTimeZone",
490 ];
491 for (mut col, rs_type) in columns.into_iter().zip(rs_types) {
492 let rs_type: TokenStream = rs_type.parse().unwrap();
493
494 col.not_null = true;
495 assert_eq!(
496 col.get_rs_type(&time_crate).to_string(),
497 quote!(#rs_type).to_string()
498 );
499
500 col.not_null = false;
501 assert_eq!(
502 col.get_rs_type(&time_crate).to_string(),
503 quote!(Option<#rs_type>).to_string()
504 );
505 }
506 }
507
508 #[test]
509 fn test_get_def() {
510 let columns = setup();
511 let col_defs = vec![
512 "ColumnType::String(StringLen::N(255u32)).def()",
513 "ColumnType::String(StringLen::None).def()",
514 "ColumnType::custom(\"cus_col\").def()",
515 "ColumnType::TinyInteger.def()",
516 "ColumnType::TinyUnsigned.def()",
517 "ColumnType::SmallInteger.def()",
518 "ColumnType::SmallUnsigned.def()",
519 "ColumnType::Integer.def()",
520 "ColumnType::Unsigned.def()",
521 "ColumnType::BigInteger.def()",
522 "ColumnType::BigUnsigned.def()",
523 "ColumnType::Float.def()",
524 "ColumnType::Double.def()",
525 "ColumnType::Binary(10u32).def()",
526 "ColumnType::VarBinary(StringLen::None).def()",
527 "ColumnType::VarBinary(StringLen::N(10u32)).def()",
528 "ColumnType::VarBinary(StringLen::Max).def()",
529 "ColumnType::Boolean.def()",
530 "ColumnType::Date.def()",
531 "ColumnType::Time.def()",
532 "ColumnType::DateTime.def()",
533 "ColumnType::Timestamp.def()",
534 "ColumnType::TimestampWithTimeZone.def()",
535 ];
536 for (mut col, col_def) in columns.into_iter().zip(col_defs) {
537 let mut col_def: TokenStream = col_def.parse().unwrap();
538
539 col.not_null = true;
540 assert_eq!(col.get_def().to_string(), col_def.to_string());
541
542 col.not_null = false;
543 col_def.extend(quote!(.null()));
544 assert_eq!(col.get_def().to_string(), col_def.to_string());
545
546 col.unique = true;
547 col_def.extend(quote!(.unique()));
548 assert_eq!(col.get_def().to_string(), col_def.to_string());
549 }
550 }
551
552 #[test]
553 fn test_get_info() {
554 let column: Column = ColumnDef::new(Alias::new("id")).string().to_owned().into();
555 assert_eq!(
556 column.get_info(&DateTimeCrate::Chrono).as_str(),
557 "Column `id`: Option<String>"
558 );
559
560 let column: Column = ColumnDef::new(Alias::new("id"))
561 .string()
562 .not_null()
563 .to_owned()
564 .into();
565 assert_eq!(
566 column.get_info(&DateTimeCrate::Chrono).as_str(),
567 "Column `id`: String, not_null"
568 );
569
570 let column: Column = ColumnDef::new(Alias::new("id"))
571 .string()
572 .not_null()
573 .unique_key()
574 .to_owned()
575 .into();
576 assert_eq!(
577 column.get_info(&DateTimeCrate::Chrono).as_str(),
578 "Column `id`: String, not_null, unique"
579 );
580
581 let column: Column = ColumnDef::new(Alias::new("id"))
582 .string()
583 .not_null()
584 .unique_key()
585 .auto_increment()
586 .to_owned()
587 .into();
588 assert_eq!(
589 column.get_info(&DateTimeCrate::Chrono).as_str(),
590 "Column `id`: String, auto_increment, not_null, unique"
591 );
592
593 let column: Column = ColumnDef::new(Alias::new("date_field"))
594 .date()
595 .not_null()
596 .to_owned()
597 .into();
598 assert_eq!(
599 column.get_info(&DateTimeCrate::Chrono).as_str(),
600 "Column `date_field`: Date, not_null"
601 );
602
603 let column: Column = ColumnDef::new(Alias::new("date_field"))
604 .date()
605 .not_null()
606 .to_owned()
607 .into();
608 assert_eq!(
609 column.get_info(&DateTimeCrate::Time).as_str(),
610 "Column `date_field`: TimeDate, not_null"
611 );
612
613 let column: Column = ColumnDef::new(Alias::new("time_field"))
614 .time()
615 .not_null()
616 .to_owned()
617 .into();
618 assert_eq!(
619 column.get_info(&DateTimeCrate::Chrono).as_str(),
620 "Column `time_field`: Time, not_null"
621 );
622
623 let column: Column = ColumnDef::new(Alias::new("time_field"))
624 .time()
625 .not_null()
626 .to_owned()
627 .into();
628 assert_eq!(
629 column.get_info(&DateTimeCrate::Time).as_str(),
630 "Column `time_field`: TimeTime, not_null"
631 );
632
633 let column: Column = ColumnDef::new(Alias::new("date_time_field"))
634 .date_time()
635 .not_null()
636 .to_owned()
637 .into();
638 assert_eq!(
639 column.get_info(&DateTimeCrate::Chrono).as_str(),
640 "Column `date_time_field`: DateTime, not_null"
641 );
642
643 let column: Column = ColumnDef::new(Alias::new("date_time_field"))
644 .date_time()
645 .not_null()
646 .to_owned()
647 .into();
648 assert_eq!(
649 column.get_info(&DateTimeCrate::Time).as_str(),
650 "Column `date_time_field`: TimeDateTime, not_null"
651 );
652
653 let column: Column = ColumnDef::new(Alias::new("timestamp_field"))
654 .timestamp()
655 .not_null()
656 .to_owned()
657 .into();
658 assert_eq!(
659 column.get_info(&DateTimeCrate::Chrono).as_str(),
660 "Column `timestamp_field`: DateTimeUtc, not_null"
661 );
662
663 let column: Column = ColumnDef::new(Alias::new("timestamp_field"))
664 .timestamp()
665 .not_null()
666 .to_owned()
667 .into();
668 assert_eq!(
669 column.get_info(&DateTimeCrate::Time).as_str(),
670 "Column `timestamp_field`: TimeDateTime, not_null"
671 );
672
673 let column: Column = ColumnDef::new(Alias::new("timestamp_with_timezone_field"))
674 .timestamp_with_time_zone()
675 .not_null()
676 .to_owned()
677 .into();
678 assert_eq!(
679 column.get_info(&DateTimeCrate::Chrono).as_str(),
680 "Column `timestamp_with_timezone_field`: DateTimeWithTimeZone, not_null"
681 );
682
683 let column: Column = ColumnDef::new(Alias::new("timestamp_with_timezone_field"))
684 .timestamp_with_time_zone()
685 .not_null()
686 .to_owned()
687 .into();
688 assert_eq!(
689 column.get_info(&DateTimeCrate::Time).as_str(),
690 "Column `timestamp_with_timezone_field`: TimeDateTimeWithTimeZone, not_null"
691 );
692 }
693
694 #[test]
695 fn test_from_column_def() {
696 let column: Column = ColumnDef::new(Alias::new("id")).string().to_owned().into();
697 assert_eq!(
698 column.get_def().to_string(),
699 quote! {
700 ColumnType::String(StringLen::None).def().null()
701 }
702 .to_string()
703 );
704
705 let column: Column = ColumnDef::new(Alias::new("id"))
706 .string()
707 .not_null()
708 .to_owned()
709 .into();
710 assert!(column.not_null);
711
712 let column: Column = ColumnDef::new(Alias::new("id"))
713 .string()
714 .unique_key()
715 .not_null()
716 .to_owned()
717 .into();
718 assert!(column.unique);
719 assert!(column.not_null);
720
721 let column: Column = ColumnDef::new(Alias::new("id"))
722 .string()
723 .auto_increment()
724 .unique_key()
725 .not_null()
726 .to_owned()
727 .into();
728 assert!(column.auto_increment);
729 assert!(column.unique);
730 assert!(column.not_null);
731 }
732}