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 pub(crate) unique_key: Option<String>,
16}
17
18impl Column {
19 pub fn get_name_snake_case(&self) -> Ident {
20 format_ident!("{}", escape_rust_keyword(self.name.to_snake_case()))
21 }
22
23 pub fn get_name_camel_case(&self) -> Ident {
24 format_ident!("{}", escape_rust_keyword(self.name.to_upper_camel_case()))
25 }
26
27 pub fn is_snake_case_name(&self) -> bool {
28 self.name.to_snake_case() == self.name
29 }
30
31 pub fn get_rs_type(&self, date_time_crate: &DateTimeCrate) -> TokenStream {
32 fn write_rs_type(col_type: &ColumnType, date_time_crate: &DateTimeCrate) -> String {
33 #[allow(unreachable_patterns)]
34 match col_type {
35 ColumnType::Char(_)
36 | ColumnType::String(_)
37 | ColumnType::Text
38 | ColumnType::Custom(_) => "String".to_owned(),
39 ColumnType::TinyInteger => "i8".to_owned(),
40 ColumnType::SmallInteger => "i16".to_owned(),
41 ColumnType::Integer => "i32".to_owned(),
42 ColumnType::BigInteger => "i64".to_owned(),
43 ColumnType::TinyUnsigned => "u8".to_owned(),
44 ColumnType::SmallUnsigned => "u16".to_owned(),
45 ColumnType::Unsigned => "u32".to_owned(),
46 ColumnType::BigUnsigned => "u64".to_owned(),
47 ColumnType::Float => "f32".to_owned(),
48 ColumnType::Double => "f64".to_owned(),
49 ColumnType::Json | ColumnType::JsonBinary => "Json".to_owned(),
50 ColumnType::Date => match date_time_crate {
51 DateTimeCrate::Chrono => "Date".to_owned(),
52 DateTimeCrate::Time => "TimeDate".to_owned(),
53 },
54 ColumnType::Time => match date_time_crate {
55 DateTimeCrate::Chrono => "Time".to_owned(),
56 DateTimeCrate::Time => "TimeTime".to_owned(),
57 },
58 ColumnType::DateTime => match date_time_crate {
59 DateTimeCrate::Chrono => "DateTime".to_owned(),
60 DateTimeCrate::Time => "TimeDateTime".to_owned(),
61 },
62 ColumnType::Timestamp => match date_time_crate {
63 DateTimeCrate::Chrono => "DateTimeUtc".to_owned(),
64 DateTimeCrate::Time => "TimeDateTime".to_owned(),
65 },
66 ColumnType::TimestampWithTimeZone => match date_time_crate {
67 DateTimeCrate::Chrono => "DateTimeWithTimeZone".to_owned(),
68 DateTimeCrate::Time => "TimeDateTimeWithTimeZone".to_owned(),
69 },
70 ColumnType::Decimal(_) | ColumnType::Money(_) => "Decimal".to_owned(),
71 ColumnType::Uuid => "Uuid".to_owned(),
72 ColumnType::Binary(_) | ColumnType::VarBinary(_) | ColumnType::Blob => {
73 "Vec<u8>".to_owned()
74 }
75 ColumnType::Boolean => "bool".to_owned(),
76 ColumnType::Enum { name, .. } => name.to_string().to_upper_camel_case(),
77 ColumnType::Array(column_type) => {
78 format!("Vec<{}>", write_rs_type(column_type, date_time_crate))
79 }
80 ColumnType::Vector(_) => "PgVector".to_owned(),
81 ColumnType::Bit(None | Some(1)) => "bool".to_owned(),
82 ColumnType::Bit(_) | ColumnType::VarBit(_) => "Vec<u8>".to_owned(),
83 ColumnType::Year => "i32".to_owned(),
84 ColumnType::Cidr | ColumnType::Inet => "IpNetwork".to_owned(),
85 ColumnType::Interval(_, _) | ColumnType::MacAddr | ColumnType::LTree => {
86 "String".to_owned()
87 }
88 _ => unimplemented!(),
89 }
90 }
91 let ident: TokenStream = write_rs_type(&self.col_type, date_time_crate)
92 .parse()
93 .unwrap();
94 match self.not_null {
95 true => quote! { #ident },
96 false => quote! { Option<#ident> },
97 }
98 }
99
100 pub fn get_col_type_attrs(&self) -> Option<TokenStream> {
101 let col_type = match &self.col_type {
102 ColumnType::Float => Some("Float".to_owned()),
103 ColumnType::Double => Some("Double".to_owned()),
104 ColumnType::Decimal(Some((p, s))) => Some(format!("Decimal(Some(({p}, {s})))")),
105 ColumnType::Money(Some((p, s))) => Some(format!("Money(Some({p}, {s}))")),
106 ColumnType::Text => Some("Text".to_owned()),
107 ColumnType::JsonBinary => Some("JsonBinary".to_owned()),
108 ColumnType::Custom(iden) => {
109 let ty = format!("custom(\"{iden}\")");
110 return Some(quote! ( ignore, column_type = #ty, select_as = "text" ));
111 }
112 ColumnType::Binary(s) => Some(format!("Binary({s})")),
113 ColumnType::VarBinary(s) => match s {
114 StringLen::N(s) => Some(format!("VarBinary(StringLen::N({s}))")),
115 StringLen::None => Some("VarBinary(StringLen::None)".to_owned()),
116 StringLen::Max => Some("VarBinary(StringLen::Max)".to_owned()),
117 },
118 ColumnType::Blob => Some("Blob".to_owned()),
119 ColumnType::Cidr => Some("Cidr".to_owned()),
120 _ => None,
121 };
122 col_type.map(|ty| quote! { column_type = #ty })
123 }
124
125 pub fn get_def(&self) -> TokenStream {
126 fn write_col_def(col_type: &ColumnType) -> TokenStream {
127 match col_type {
128 ColumnType::Char(s) => match s {
129 Some(s) => quote! { ColumnType::Char(Some(#s)) },
130 None => quote! { ColumnType::Char(None) },
131 },
132 ColumnType::String(s) => match s {
133 StringLen::N(s) => quote! { ColumnType::String(StringLen::N(#s)) },
134 StringLen::None => quote! { ColumnType::String(StringLen::None) },
135 StringLen::Max => quote! { ColumnType::String(StringLen::Max) },
136 },
137 ColumnType::Text => quote! { ColumnType::Text },
138 ColumnType::TinyInteger => quote! { ColumnType::TinyInteger },
139 ColumnType::SmallInteger => quote! { ColumnType::SmallInteger },
140 ColumnType::Integer => quote! { ColumnType::Integer },
141 ColumnType::BigInteger => quote! { ColumnType::BigInteger },
142 ColumnType::TinyUnsigned => quote! { ColumnType::TinyUnsigned },
143 ColumnType::SmallUnsigned => quote! { ColumnType::SmallUnsigned },
144 ColumnType::Unsigned => quote! { ColumnType::Unsigned },
145 ColumnType::BigUnsigned => quote! { ColumnType::BigUnsigned },
146 ColumnType::Float => quote! { ColumnType::Float },
147 ColumnType::Double => quote! { ColumnType::Double },
148 ColumnType::Decimal(s) => match s {
149 Some((s1, s2)) => quote! { ColumnType::Decimal(Some((#s1, #s2))) },
150 None => quote! { ColumnType::Decimal(None) },
151 },
152 ColumnType::DateTime => quote! { ColumnType::DateTime },
153 ColumnType::Timestamp => quote! { ColumnType::Timestamp },
154 ColumnType::TimestampWithTimeZone => {
155 quote! { ColumnType::TimestampWithTimeZone }
156 }
157 ColumnType::Time => quote! { ColumnType::Time },
158 ColumnType::Date => quote! { ColumnType::Date },
159 ColumnType::Binary(s) => {
160 quote! { ColumnType::Binary(#s) }
161 }
162 ColumnType::VarBinary(s) => match s {
163 StringLen::N(s) => quote! { ColumnType::VarBinary(StringLen::N(#s)) },
164 StringLen::None => quote! { ColumnType::VarBinary(StringLen::None) },
165 StringLen::Max => quote! { ColumnType::VarBinary(StringLen::Max) },
166 },
167 ColumnType::Blob => quote! { ColumnType::Blob },
168 ColumnType::Boolean => quote! { ColumnType::Boolean },
169 ColumnType::Money(s) => match s {
170 Some((s1, s2)) => quote! { ColumnType::Money(Some((#s1, #s2))) },
171 None => quote! { ColumnType::Money(None) },
172 },
173 ColumnType::Json => quote! { ColumnType::Json },
174 ColumnType::JsonBinary => quote! { ColumnType::JsonBinary },
175 ColumnType::Uuid => quote! { ColumnType::Uuid },
176 ColumnType::Cidr => quote! { ColumnType::Cidr },
177 ColumnType::Inet => quote! { ColumnType::Inet },
178 ColumnType::Custom(s) => {
179 let s = s.to_string();
180 quote! { ColumnType::custom(#s) }
181 }
182 ColumnType::Enum { name, .. } => {
183 let enum_ident = format_ident!("{}", name.to_string().to_upper_camel_case());
184 quote! {
185 #enum_ident::db_type()
186 .get_column_type()
187 .to_owned()
188 }
189 }
190 ColumnType::Array(column_type) => {
191 let column_type = write_col_def(column_type);
192 quote! { ColumnType::Array(RcOrArc::new(#column_type)) }
193 }
194 ColumnType::Vector(size) => match size {
195 Some(size) => quote! { ColumnType::Vector(Some(#size)) },
196 None => quote! { ColumnType::Vector(None) },
197 },
198 #[allow(unreachable_patterns)]
199 _ => unimplemented!(),
200 }
201 }
202 let mut col_def = write_col_def(&self.col_type);
203 col_def.extend(quote! {
204 .def()
205 });
206 if !self.not_null {
207 col_def.extend(quote! {
208 .null()
209 });
210 }
211 if self.unique {
212 col_def.extend(quote! {
213 .unique()
214 });
215 }
216 col_def
217 }
218
219 pub fn get_info(&self, date_time_crate: &DateTimeCrate) -> String {
220 let mut info = String::new();
221 let type_info = self
222 .get_rs_type(date_time_crate)
223 .to_string()
224 .replace(' ', "");
225 let col_info = self.col_info();
226 write!(
227 &mut info,
228 "Column `{}`: {}{}",
229 self.name, type_info, col_info
230 )
231 .unwrap();
232 info
233 }
234
235 fn col_info(&self) -> String {
236 let mut info = String::new();
237 if self.auto_increment {
238 write!(&mut info, ", auto_increment").unwrap();
239 }
240 if self.not_null {
241 write!(&mut info, ", not_null").unwrap();
242 }
243 if self.unique {
244 write!(&mut info, ", unique").unwrap();
245 }
246 info
247 }
248
249 pub fn get_serde_attribute(
250 &self,
251 is_primary_key: bool,
252 serde_skip_deserializing_primary_key: bool,
253 serde_skip_hidden_column: bool,
254 ) -> TokenStream {
255 if self.name.starts_with('_') && serde_skip_hidden_column {
256 quote! {
257 #[serde(skip)]
258 }
259 } else if serde_skip_deserializing_primary_key && is_primary_key {
260 quote! {
261 #[serde(skip_deserializing)]
262 }
263 } else {
264 quote! {}
265 }
266 }
267
268 pub fn get_inner_col_type(&self) -> &ColumnType {
269 match &self.col_type {
270 ColumnType::Array(inner_col_type) => inner_col_type.as_ref(),
271 _ => &self.col_type,
272 }
273 }
274}
275
276impl From<ColumnDef> for Column {
277 fn from(col_def: ColumnDef) -> Self {
278 (&col_def).into()
279 }
280}
281
282impl From<&ColumnDef> for Column {
283 fn from(col_def: &ColumnDef) -> Self {
284 let name = col_def.get_column_name();
285 let col_type = match col_def.get_column_type() {
286 Some(ty) => ty.clone(),
287 None => panic!("ColumnType should not be empty"),
288 };
289 let auto_increment = col_def.get_column_spec().auto_increment;
290 let not_null = match col_def.get_column_spec().nullable {
291 Some(nullable) => !nullable,
292 None => false,
293 };
294 let unique = col_def.get_column_spec().unique;
295 Self {
296 name,
297 col_type,
298 auto_increment,
299 not_null,
300 unique,
301 unique_key: None,
302 }
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use crate::{Column, DateTimeCrate};
309 use proc_macro2::TokenStream;
310 use quote::quote;
311 use sea_query::{Alias, ColumnDef, ColumnType, SeaRc, StringLen};
312
313 fn setup() -> Vec<Column> {
314 macro_rules! make_col {
315 ($name:expr, $col_type:expr) => {
316 Column {
317 name: $name.to_owned(),
318 col_type: $col_type,
319 auto_increment: false,
320 not_null: false,
321 unique: false,
322 unique_key: None,
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}