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 fn get_def_inner(&self, enum_type_ident: Option<&Ident>) -> TokenStream {
134 fn write_col_def(col_type: &ColumnType, enum_type_ident: Option<&Ident>) -> 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 = enum_type_ident.cloned().unwrap_or_else(|| {
192 format_ident!("{}", name.to_string().to_upper_camel_case())
193 });
194 quote! {
195 #enum_ident::db_type()
196 .get_column_type()
197 .to_owned()
198 }
199 }
200 ColumnType::Array(column_type) => {
201 let column_type = write_col_def(column_type, enum_type_ident);
202 quote! { ColumnType::Array(RcOrArc::new(#column_type)) }
203 }
204 ColumnType::Vector(size) => match size {
205 Some(size) => quote! { ColumnType::Vector(Some(#size)) },
206 None => quote! { ColumnType::Vector(None) },
207 },
208 #[allow(unreachable_patterns)]
209 _ => unimplemented!(),
210 }
211 }
212 let mut col_def = write_col_def(&self.col_type, enum_type_ident);
213 col_def.extend(quote! {
214 .def()
215 });
216 if !self.not_null {
217 col_def.extend(quote! {
218 .null()
219 });
220 }
221 if self.unique {
222 col_def.extend(quote! {
223 .unique()
224 });
225 }
226 col_def
227 }
228
229 pub fn get_def(&self) -> TokenStream {
230 self.get_def_inner(None)
231 }
232
233 pub fn get_def_with_enum_type_ident(&self, enum_type_ident: &Ident) -> TokenStream {
234 self.get_def_inner(Some(enum_type_ident))
235 }
236
237 pub fn get_info(&self, opt: &ColumnOption) -> String {
238 let mut info = String::new();
239 let type_info = self.get_rs_type(opt).to_string().replace(' ', "");
240 let col_info = self.col_info();
241 write!(
242 &mut info,
243 "Column `{}`: {}{}",
244 self.name, type_info, col_info
245 )
246 .unwrap();
247 info
248 }
249
250 fn col_info(&self) -> String {
251 let mut info = String::new();
252 if self.auto_increment {
253 write!(&mut info, ", auto_increment").unwrap();
254 }
255 if self.not_null {
256 write!(&mut info, ", not_null").unwrap();
257 }
258 if self.unique {
259 write!(&mut info, ", unique").unwrap();
260 }
261 info
262 }
263
264 pub fn get_serde_attribute(
265 &self,
266 is_primary_key: bool,
267 serde_skip_deserializing_primary_key: bool,
268 serde_skip_hidden_column: bool,
269 ) -> TokenStream {
270 if self.name.starts_with('_') && serde_skip_hidden_column {
271 quote! {
272 #[serde(skip)]
273 }
274 } else if serde_skip_deserializing_primary_key && is_primary_key {
275 quote! {
276 #[serde(skip_deserializing)]
277 }
278 } else {
279 quote! {}
280 }
281 }
282
283 pub fn get_inner_col_type(&self) -> &ColumnType {
284 match &self.col_type {
285 ColumnType::Array(inner_col_type) => inner_col_type.as_ref(),
286 _ => &self.col_type,
287 }
288 }
289}
290
291impl From<ColumnDef> for Column {
292 fn from(col_def: ColumnDef) -> Self {
293 (&col_def).into()
294 }
295}
296
297impl From<&ColumnDef> for Column {
298 fn from(col_def: &ColumnDef) -> Self {
299 let name = col_def.get_column_name();
300 let col_type = match col_def.get_column_type() {
301 Some(ty) => ty.clone(),
302 None => panic!("ColumnType should not be empty"),
303 };
304 let auto_increment = col_def.get_column_spec().auto_increment;
305 let not_null = match col_def.get_column_spec().nullable {
306 Some(nullable) => !nullable,
307 None => false,
308 };
309 let unique = col_def.get_column_spec().unique;
310 Self {
311 name,
312 col_type,
313 auto_increment,
314 not_null,
315 unique,
316 unique_key: None,
317 }
318 }
319}
320
321#[cfg(test)]
322mod tests {
323 use crate::{Column, ColumnOption, DateTimeCrate};
324 use proc_macro2::TokenStream;
325 use quote::quote;
326 use sea_query::{Alias, ColumnDef, ColumnType, SeaRc, StringLen};
327
328 fn date_time_crate_chrono() -> ColumnOption {
329 ColumnOption {
330 date_time_crate: DateTimeCrate::Chrono,
331 big_integer_type: Default::default(),
332 }
333 }
334
335 fn date_time_crate_time() -> ColumnOption {
336 ColumnOption {
337 date_time_crate: DateTimeCrate::Time,
338 big_integer_type: Default::default(),
339 }
340 }
341
342 fn setup() -> Vec<Column> {
343 macro_rules! make_col {
344 ($name:expr, $col_type:expr) => {
345 Column {
346 name: $name.to_owned(),
347 col_type: $col_type,
348 auto_increment: false,
349 not_null: false,
350 unique: false,
351 unique_key: None,
352 }
353 };
354 }
355 vec![
356 make_col!("id", ColumnType::String(StringLen::N(255))),
357 make_col!("id", ColumnType::String(StringLen::None)),
358 make_col!(
359 "cake_id",
360 ColumnType::Custom(SeaRc::new(Alias::new("cus_col")))
361 ),
362 make_col!("CakeId", ColumnType::TinyInteger),
363 make_col!("CakeId", ColumnType::TinyUnsigned),
364 make_col!("CakeId", ColumnType::SmallInteger),
365 make_col!("CakeId", ColumnType::SmallUnsigned),
366 make_col!("CakeId", ColumnType::Integer),
367 make_col!("CakeId", ColumnType::Unsigned),
368 make_col!("CakeFillingId", ColumnType::BigInteger),
369 make_col!("CakeFillingId", ColumnType::BigUnsigned),
370 make_col!("cake-filling-id", ColumnType::Float),
371 make_col!("CAKE_FILLING_ID", ColumnType::Double),
372 make_col!("CAKE-FILLING-ID", ColumnType::Binary(10)),
373 make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::None)),
374 make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::N(10))),
375 make_col!("CAKE-FILLING-ID", ColumnType::VarBinary(StringLen::Max)),
376 make_col!("CAKE", ColumnType::Boolean),
377 make_col!("date", ColumnType::Date),
378 make_col!("time", ColumnType::Time),
379 make_col!("date_time", ColumnType::DateTime),
380 make_col!("timestamp", ColumnType::Timestamp),
381 make_col!("timestamp_tz", ColumnType::TimestampWithTimeZone),
382 ]
383 }
384
385 #[test]
386 fn test_get_name_snake_case() {
387 let columns = setup();
388 let snack_cases = vec![
389 "id",
390 "id",
391 "cake_id",
392 "cake_id",
393 "cake_id",
394 "cake_id",
395 "cake_id",
396 "cake_id",
397 "cake_id",
398 "cake_filling_id",
399 "cake_filling_id",
400 "cake_filling_id",
401 "cake_filling_id",
402 "cake_filling_id",
403 "cake_filling_id",
404 "cake_filling_id",
405 "cake_filling_id",
406 "cake",
407 "date",
408 "time",
409 "date_time",
410 "timestamp",
411 "timestamp_tz",
412 ];
413 for (col, snack_case) in columns.into_iter().zip(snack_cases) {
414 assert_eq!(col.get_name_snake_case().to_string(), snack_case);
415 }
416 }
417
418 #[test]
419 fn test_get_name_camel_case() {
420 let columns = setup();
421 let camel_cases = vec![
422 "Id",
423 "Id",
424 "CakeId",
425 "CakeId",
426 "CakeId",
427 "CakeId",
428 "CakeId",
429 "CakeId",
430 "CakeId",
431 "CakeFillingId",
432 "CakeFillingId",
433 "CakeFillingId",
434 "CakeFillingId",
435 "CakeFillingId",
436 "CakeFillingId",
437 "CakeFillingId",
438 "CakeFillingId",
439 "Cake",
440 "Date",
441 "Time",
442 "DateTime",
443 "Timestamp",
444 "TimestampTz",
445 ];
446 for (col, camel_case) in columns.into_iter().zip(camel_cases) {
447 assert_eq!(col.get_name_camel_case().to_string(), camel_case);
448 }
449 }
450
451 #[test]
452 fn test_get_rs_type_with_chrono() {
453 let columns = setup();
454 let rs_types = vec![
455 "String",
456 "String",
457 "String",
458 "i8",
459 "u8",
460 "i16",
461 "u16",
462 "i32",
463 "u32",
464 "i64",
465 "u64",
466 "f32",
467 "f64",
468 "Vec<u8>",
469 "Vec<u8>",
470 "Vec<u8>",
471 "Vec<u8>",
472 "bool",
473 "Date",
474 "Time",
475 "DateTime",
476 "DateTimeUtc",
477 "DateTimeWithTimeZone",
478 ];
479 for (mut col, rs_type) in columns.into_iter().zip(rs_types) {
480 let rs_type: TokenStream = rs_type.parse().unwrap();
481
482 col.not_null = true;
483 assert_eq!(
484 col.get_rs_type(&date_time_crate_chrono()).to_string(),
485 quote!(#rs_type).to_string()
486 );
487
488 col.not_null = false;
489 assert_eq!(
490 col.get_rs_type(&date_time_crate_chrono()).to_string(),
491 quote!(Option<#rs_type>).to_string()
492 );
493 }
494 }
495
496 #[test]
497 fn test_get_rs_type_with_time() {
498 let columns = setup();
499 let rs_types = vec![
500 "String",
501 "String",
502 "String",
503 "i8",
504 "u8",
505 "i16",
506 "u16",
507 "i32",
508 "u32",
509 "i64",
510 "u64",
511 "f32",
512 "f64",
513 "Vec<u8>",
514 "Vec<u8>",
515 "Vec<u8>",
516 "Vec<u8>",
517 "bool",
518 "TimeDate",
519 "TimeTime",
520 "TimeDateTime",
521 "TimeDateTime",
522 "TimeDateTimeWithTimeZone",
523 ];
524 for (mut col, rs_type) in columns.into_iter().zip(rs_types) {
525 let rs_type: TokenStream = rs_type.parse().unwrap();
526
527 col.not_null = true;
528 assert_eq!(
529 col.get_rs_type(&date_time_crate_time()).to_string(),
530 quote!(#rs_type).to_string()
531 );
532
533 col.not_null = false;
534 assert_eq!(
535 col.get_rs_type(&date_time_crate_time()).to_string(),
536 quote!(Option<#rs_type>).to_string()
537 );
538 }
539 }
540
541 #[test]
542 fn test_get_def() {
543 let columns = setup();
544 let col_defs = vec![
545 "ColumnType::String(StringLen::N(255u32)).def()",
546 "ColumnType::String(StringLen::None).def()",
547 "ColumnType::custom(\"cus_col\").def()",
548 "ColumnType::TinyInteger.def()",
549 "ColumnType::TinyUnsigned.def()",
550 "ColumnType::SmallInteger.def()",
551 "ColumnType::SmallUnsigned.def()",
552 "ColumnType::Integer.def()",
553 "ColumnType::Unsigned.def()",
554 "ColumnType::BigInteger.def()",
555 "ColumnType::BigUnsigned.def()",
556 "ColumnType::Float.def()",
557 "ColumnType::Double.def()",
558 "ColumnType::Binary(10u32).def()",
559 "ColumnType::VarBinary(StringLen::None).def()",
560 "ColumnType::VarBinary(StringLen::N(10u32)).def()",
561 "ColumnType::VarBinary(StringLen::Max).def()",
562 "ColumnType::Boolean.def()",
563 "ColumnType::Date.def()",
564 "ColumnType::Time.def()",
565 "ColumnType::DateTime.def()",
566 "ColumnType::Timestamp.def()",
567 "ColumnType::TimestampWithTimeZone.def()",
568 ];
569 for (mut col, col_def) in columns.into_iter().zip(col_defs) {
570 let mut col_def: TokenStream = col_def.parse().unwrap();
571
572 col.not_null = true;
573 assert_eq!(col.get_def().to_string(), col_def.to_string());
574
575 col.not_null = false;
576 col_def.extend(quote!(.null()));
577 assert_eq!(col.get_def().to_string(), col_def.to_string());
578
579 col.unique = true;
580 col_def.extend(quote!(.unique()));
581 assert_eq!(col.get_def().to_string(), col_def.to_string());
582 }
583 }
584
585 #[test]
586 fn test_get_info() {
587 let column: Column = ColumnDef::new(Alias::new("id")).string().to_owned().into();
588 assert_eq!(
589 column.get_info(&date_time_crate_chrono()).as_str(),
590 "Column `id`: Option<String>"
591 );
592
593 let column: Column = ColumnDef::new(Alias::new("id"))
594 .string()
595 .not_null()
596 .to_owned()
597 .into();
598 assert_eq!(
599 column.get_info(&date_time_crate_chrono()).as_str(),
600 "Column `id`: String, not_null"
601 );
602
603 let column: Column = ColumnDef::new(Alias::new("id"))
604 .string()
605 .not_null()
606 .unique_key()
607 .to_owned()
608 .into();
609 assert_eq!(
610 column.get_info(&date_time_crate_chrono()).as_str(),
611 "Column `id`: String, not_null, unique"
612 );
613
614 let column: Column = ColumnDef::new(Alias::new("id"))
615 .string()
616 .not_null()
617 .unique_key()
618 .auto_increment()
619 .to_owned()
620 .into();
621 assert_eq!(
622 column.get_info(&date_time_crate_chrono()).as_str(),
623 "Column `id`: String, auto_increment, not_null, unique"
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_chrono()).as_str(),
633 "Column `date_field`: Date, not_null"
634 );
635
636 let column: Column = ColumnDef::new(Alias::new("date_field"))
637 .date()
638 .not_null()
639 .to_owned()
640 .into();
641 assert_eq!(
642 column.get_info(&date_time_crate_time()).as_str(),
643 "Column `date_field`: TimeDate, 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_chrono()).as_str(),
653 "Column `time_field`: Time, not_null"
654 );
655
656 let column: Column = ColumnDef::new(Alias::new("time_field"))
657 .time()
658 .not_null()
659 .to_owned()
660 .into();
661 assert_eq!(
662 column.get_info(&date_time_crate_time()).as_str(),
663 "Column `time_field`: TimeTime, 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_chrono()).as_str(),
673 "Column `date_time_field`: DateTime, not_null"
674 );
675
676 let column: Column = ColumnDef::new(Alias::new("date_time_field"))
677 .date_time()
678 .not_null()
679 .to_owned()
680 .into();
681 assert_eq!(
682 column.get_info(&date_time_crate_time()).as_str(),
683 "Column `date_time_field`: TimeDateTime, 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_chrono()).as_str(),
693 "Column `timestamp_field`: DateTimeUtc, not_null"
694 );
695
696 let column: Column = ColumnDef::new(Alias::new("timestamp_field"))
697 .timestamp()
698 .not_null()
699 .to_owned()
700 .into();
701 assert_eq!(
702 column.get_info(&date_time_crate_time()).as_str(),
703 "Column `timestamp_field`: TimeDateTime, 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_chrono()).as_str(),
713 "Column `timestamp_with_timezone_field`: DateTimeWithTimeZone, not_null"
714 );
715
716 let column: Column = ColumnDef::new(Alias::new("timestamp_with_timezone_field"))
717 .timestamp_with_time_zone()
718 .not_null()
719 .to_owned()
720 .into();
721 assert_eq!(
722 column.get_info(&date_time_crate_time()).as_str(),
723 "Column `timestamp_with_timezone_field`: TimeDateTimeWithTimeZone, not_null"
724 );
725 }
726
727 #[test]
728 fn test_from_column_def() {
729 let column: Column = ColumnDef::new(Alias::new("id")).string().to_owned().into();
730 assert_eq!(
731 column.get_def().to_string(),
732 quote! {
733 ColumnType::String(StringLen::None).def().null()
734 }
735 .to_string()
736 );
737
738 let column: Column = ColumnDef::new(Alias::new("id"))
739 .string()
740 .not_null()
741 .to_owned()
742 .into();
743 assert!(column.not_null);
744
745 let column: Column = ColumnDef::new(Alias::new("id"))
746 .string()
747 .unique_key()
748 .not_null()
749 .to_owned()
750 .into();
751 assert!(column.unique);
752 assert!(column.not_null);
753
754 let column: Column = ColumnDef::new(Alias::new("id"))
755 .string()
756 .auto_increment()
757 .unique_key()
758 .not_null()
759 .to_owned()
760 .into();
761 assert!(column.auto_increment);
762 assert!(column.unique);
763 assert!(column.not_null);
764 }
765}