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::Vector".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::Interval(_, _)
84 | ColumnType::Cidr
85 | ColumnType::Inet
86 | ColumnType::MacAddr
87 | ColumnType::LTree => "String".to_owned(),
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) => Some(format!("custom(\"{}\")", iden.to_string())),
109 ColumnType::Binary(s) => Some(format!("Binary({s})")),
110 ColumnType::VarBinary(s) => match s {
111 StringLen::N(s) => Some(format!("VarBinary(StringLen::N({s}))")),
112 StringLen::None => Some("VarBinary(StringLen::None)".to_owned()),
113 StringLen::Max => Some("VarBinary(StringLen::Max)".to_owned()),
114 },
115 ColumnType::Blob => Some("Blob".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::Custom(s) => {
173 let s = s.to_string();
174 quote! { ColumnType::custom(#s) }
175 }
176 ColumnType::Enum { name, .. } => {
177 let enum_ident = format_ident!("{}", name.to_string().to_upper_camel_case());
178 quote! { #enum_ident::db_type() }
179 }
180 ColumnType::Array(column_type) => {
181 let column_type = write_col_def(column_type);
182 quote! { ColumnType::Array(RcOrArc::new(#column_type)) }
183 }
184 ColumnType::Vector(size) => match size {
185 Some(size) => quote! { ColumnType::Vector(Some(#size)) },
186 None => quote! { ColumnType::Vector(None) },
187 },
188 #[allow(unreachable_patterns)]
189 _ => unimplemented!(),
190 }
191 }
192 let mut col_def = write_col_def(&self.col_type);
193 col_def.extend(quote! {
194 .def()
195 });
196 if !self.not_null {
197 col_def.extend(quote! {
198 .null()
199 });
200 }
201 if self.unique {
202 col_def.extend(quote! {
203 .unique()
204 });
205 }
206 col_def
207 }
208
209 pub fn get_info(&self, date_time_crate: &DateTimeCrate) -> String {
210 let mut info = String::new();
211 let type_info = self
212 .get_rs_type(date_time_crate)
213 .to_string()
214 .replace(' ', "");
215 let col_info = self.col_info();
216 write!(
217 &mut info,
218 "Column `{}`: {}{}",
219 self.name, type_info, col_info
220 )
221 .unwrap();
222 info
223 }
224
225 fn col_info(&self) -> String {
226 let mut info = String::new();
227 if self.auto_increment {
228 write!(&mut info, ", auto_increment").unwrap();
229 }
230 if self.not_null {
231 write!(&mut info, ", not_null").unwrap();
232 }
233 if self.unique {
234 write!(&mut info, ", unique").unwrap();
235 }
236 info
237 }
238
239 pub fn get_serde_attribute(
240 &self,
241 is_primary_key: bool,
242 serde_skip_deserializing_primary_key: bool,
243 serde_skip_hidden_column: bool,
244 ) -> TokenStream {
245 if self.name.starts_with('_') && serde_skip_hidden_column {
246 quote! {
247 #[serde(skip)]
248 }
249 } else if serde_skip_deserializing_primary_key && is_primary_key {
250 quote! {
251 #[serde(skip_deserializing)]
252 }
253 } else {
254 quote! {}
255 }
256 }
257
258 pub fn get_inner_col_type(&self) -> &ColumnType {
259 match &self.col_type {
260 ColumnType::Array(inner_col_type) => inner_col_type.as_ref(),
261 _ => &self.col_type,
262 }
263 }
264}
265
266impl From<ColumnDef> for Column {
267 fn from(col_def: ColumnDef) -> Self {
268 (&col_def).into()
269 }
270}
271
272impl From<&ColumnDef> for Column {
273 fn from(col_def: &ColumnDef) -> Self {
274 let name = col_def.get_column_name();
275 let col_type = match col_def.get_column_type() {
276 Some(ty) => ty.clone(),
277 None => panic!("ColumnType should not be empty"),
278 };
279 let auto_increment = col_def
280 .get_column_spec()
281 .iter()
282 .any(|spec| matches!(spec, ColumnSpec::AutoIncrement));
283 let not_null = col_def
284 .get_column_spec()
285 .iter()
286 .any(|spec| matches!(spec, ColumnSpec::NotNull));
287 let unique = col_def
288 .get_column_spec()
289 .iter()
290 .any(|spec| matches!(spec, ColumnSpec::UniqueKey));
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}