1pub mod check_violation_strategy;
2pub mod column;
3pub mod constraint;
4pub mod fk_orphan_strategy;
5pub mod foreign_key;
6pub mod index;
7pub mod names;
8pub mod pk_addition_strategy;
9pub mod primary_key;
10pub mod reference;
11pub mod str_or_bool;
12pub mod table;
13pub mod unique_strategy;
14
15pub use check_violation_strategy::CheckViolationStrategy;
16pub use column::{
17 ColumnDef, ColumnType, ComplexColumnType, EnumValues, NumValue, SimpleColumnType,
18};
19pub use constraint::{ConstraintKind, TableConstraint};
20pub use fk_orphan_strategy::ForeignKeyOrphanStrategy;
21pub use index::IndexDef;
22pub use names::{ColumnName, IndexName, TableName};
23pub use pk_addition_strategy::PrimaryKeyAdditionStrategy;
24pub use primary_key::PrimaryKeyDef;
25pub use reference::ReferenceAction;
26pub use str_or_bool::{DefaultValue, StrOrBoolOrArray, StringOrBool};
27pub use table::{TableDef, TableValidationError};
28pub use unique_strategy::{KeepPolicy, UniqueConstraintStrategy};
29
30#[cfg(test)]
31mod tests {
32 mod column {
33 use crate::schema::column::*;
34 use crate::schema::primary_key::PrimaryKeySyntax;
35 use crate::schema::str_or_bool::StrOrBoolOrArray;
36 use rstest::rstest;
37
38 #[test]
39 fn new_creates_minimal_column() {
40 let c = ColumnDef::new("id", ColumnType::Simple(SimpleColumnType::Integer), false);
41 assert_eq!(c.name.as_str(), "id");
42 assert!(!c.nullable);
43 assert!(c.primary_key.is_none());
44 assert!(c.unique.is_none());
45 assert!(c.index.is_none());
46 assert!(c.foreign_key.is_none());
47 assert!(c.default.is_none());
48 assert!(c.comment.is_none());
49 }
50
51 #[test]
52 fn builder_chain_sets_fields() {
53 let c = ColumnDef::new("email", ColumnType::Simple(SimpleColumnType::Text), false)
54 .unique(StrOrBoolOrArray::Bool(true))
55 .index(StrOrBoolOrArray::Bool(true))
56 .comment("user email");
57 assert!(c.unique.is_some());
58 assert!(c.index.is_some());
59 assert_eq!(c.comment.as_deref(), Some("user email"));
60 }
61
62 #[test]
63 fn builder_preserves_round_trip_with_existing_literal() {
64 let from_builder =
66 ColumnDef::new("name", ColumnType::Simple(SimpleColumnType::Text), false);
67 let from_literal = ColumnDef {
68 name: "name".into(),
69 r#type: ColumnType::Simple(SimpleColumnType::Text),
70 nullable: false,
71 default: None,
72 comment: None,
73 primary_key: None,
74 unique: None,
75 index: None,
76 foreign_key: None,
77 };
78 assert_eq!(from_builder, from_literal);
79 }
80
81 #[test]
82 fn primary_key_builder_accepts_existing_syntax_type() {
83 let c = ColumnDef::new("id", ColumnType::Simple(SimpleColumnType::Integer), false)
84 .primary_key(PrimaryKeySyntax::Bool(true));
85 assert_eq!(c.primary_key, Some(PrimaryKeySyntax::Bool(true)));
86 }
87
88 #[rstest]
89 #[case(SimpleColumnType::SmallInt, "i16")]
90 #[case(SimpleColumnType::Integer, "i32")]
91 #[case(SimpleColumnType::BigInt, "i64")]
92 #[case(SimpleColumnType::Real, "f32")]
93 #[case(SimpleColumnType::DoublePrecision, "f64")]
94 #[case(SimpleColumnType::Text, "String")]
95 #[case(SimpleColumnType::Boolean, "bool")]
96 #[case(SimpleColumnType::Date, "Date")]
97 #[case(SimpleColumnType::Time, "Time")]
98 #[case(SimpleColumnType::Timestamp, "DateTime")]
99 #[case(SimpleColumnType::Timestamptz, "DateTimeWithTimeZone")]
100 #[case(SimpleColumnType::Interval, "String")]
101 #[case(SimpleColumnType::Bytea, "Vec<u8>")]
102 #[case(SimpleColumnType::Uuid, "Uuid")]
103 #[case(SimpleColumnType::Json, "Json")]
104 #[case(SimpleColumnType::Inet, "String")]
106 #[case(SimpleColumnType::Cidr, "String")]
107 #[case(SimpleColumnType::Macaddr, "String")]
108 #[case(SimpleColumnType::Xml, "String")]
109 fn test_simple_column_type_to_rust_type_not_nullable(
110 #[case] column_type: SimpleColumnType,
111 #[case] expected: &str,
112 ) {
113 assert_eq!(
114 ColumnType::Simple(column_type).to_rust_type(false),
115 expected
116 );
117 }
118
119 #[rstest]
120 #[case(SimpleColumnType::SmallInt, "Option<i16>")]
121 #[case(SimpleColumnType::Integer, "Option<i32>")]
122 #[case(SimpleColumnType::BigInt, "Option<i64>")]
123 #[case(SimpleColumnType::Real, "Option<f32>")]
124 #[case(SimpleColumnType::DoublePrecision, "Option<f64>")]
125 #[case(SimpleColumnType::Text, "Option<String>")]
126 #[case(SimpleColumnType::Boolean, "Option<bool>")]
127 #[case(SimpleColumnType::Date, "Option<Date>")]
128 #[case(SimpleColumnType::Time, "Option<Time>")]
129 #[case(SimpleColumnType::Timestamp, "Option<DateTime>")]
130 #[case(SimpleColumnType::Timestamptz, "Option<DateTimeWithTimeZone>")]
131 #[case(SimpleColumnType::Interval, "Option<String>")]
132 #[case(SimpleColumnType::Bytea, "Option<Vec<u8>>")]
133 #[case(SimpleColumnType::Uuid, "Option<Uuid>")]
134 #[case(SimpleColumnType::Json, "Option<Json>")]
135 #[case(SimpleColumnType::Inet, "Option<String>")]
137 #[case(SimpleColumnType::Cidr, "Option<String>")]
138 #[case(SimpleColumnType::Macaddr, "Option<String>")]
139 #[case(SimpleColumnType::Xml, "Option<String>")]
140 fn test_simple_column_type_to_rust_type_nullable(
141 #[case] column_type: SimpleColumnType,
142 #[case] expected: &str,
143 ) {
144 assert_eq!(ColumnType::Simple(column_type).to_rust_type(true), expected);
145 }
146
147 #[rstest]
148 #[case(ComplexColumnType::Varchar { length: 255 }, false, "String")]
149 #[case(ComplexColumnType::Varchar { length: 50 }, false, "String")]
150 #[case(ComplexColumnType::Numeric { precision: 10, scale: 2 }, false, "Decimal")]
151 #[case(ComplexColumnType::Numeric { precision: 5, scale: 0 }, false, "Decimal")]
152 #[case(ComplexColumnType::Char { length: 10 }, false, "String")]
153 #[case(ComplexColumnType::Char { length: 1 }, false, "String")]
154 #[case(ComplexColumnType::Custom { custom_type: "MONEY".into() }, false, "String")]
155 #[case(ComplexColumnType::Custom { custom_type: "JSONB".into() }, false, "String")]
156 #[case(ComplexColumnType::Enum { name: "status".into(), values: EnumValues::String(vec!["active".into(), "inactive".into()]) }, false, "String")]
157 fn test_complex_column_type_to_rust_type_not_nullable(
158 #[case] column_type: ComplexColumnType,
159 #[case] nullable: bool,
160 #[case] expected: &str,
161 ) {
162 assert_eq!(
163 ColumnType::Complex(column_type).to_rust_type(nullable),
164 expected
165 );
166 }
167
168 #[rstest]
169 #[case(ComplexColumnType::Varchar { length: 255 }, "Option<String>")]
170 #[case(ComplexColumnType::Varchar { length: 50 }, "Option<String>")]
171 #[case(ComplexColumnType::Numeric { precision: 10, scale: 2 }, "Option<Decimal>")]
172 #[case(ComplexColumnType::Numeric { precision: 5, scale: 0 }, "Option<Decimal>")]
173 #[case(ComplexColumnType::Char { length: 10 }, "Option<String>")]
174 #[case(ComplexColumnType::Char { length: 1 }, "Option<String>")]
175 #[case(ComplexColumnType::Custom { custom_type: "MONEY".into() }, "Option<String>")]
176 #[case(ComplexColumnType::Custom { custom_type: "JSONB".into() }, "Option<String>")]
177 #[case(ComplexColumnType::Enum { name: "status".into(), values: EnumValues::String(vec!["active".into(), "inactive".into()]) }, "Option<String>")]
178 fn test_complex_column_type_to_rust_type_nullable(
179 #[case] column_type: ComplexColumnType,
180 #[case] expected: &str,
181 ) {
182 assert_eq!(
183 ColumnType::Complex(column_type).to_rust_type(true),
184 expected
185 );
186 }
187
188 #[rstest]
189 #[case(ComplexColumnType::Varchar { length: 255 })]
190 #[case(ComplexColumnType::Numeric { precision: 10, scale: 2 })]
191 #[case(ComplexColumnType::Char { length: 1 })]
192 #[case(ComplexColumnType::Custom { custom_type: "SERIAL".into() })]
193 #[case(ComplexColumnType::Enum { name: "status".into(), values: EnumValues::String(vec![]) })]
194 fn test_complex_column_type_does_not_support_auto_increment(
195 #[case] column_type: ComplexColumnType,
196 ) {
197 assert!(!ColumnType::Complex(column_type).supports_auto_increment());
199 }
200
201 #[test]
202 fn test_enum_values_is_string() {
203 let string_vals = EnumValues::String(vec!["active".into()]);
204 let int_vals = EnumValues::Integer(vec![NumValue {
205 name: "Active".into(),
206 value: 1,
207 }]);
208 assert!(string_vals.is_string());
209 assert!(!int_vals.is_string());
210 }
211
212 #[test]
213 fn test_enum_values_is_integer() {
214 let string_vals = EnumValues::String(vec!["active".into()]);
215 let int_vals = EnumValues::Integer(vec![NumValue {
216 name: "Active".into(),
217 value: 1,
218 }]);
219 assert!(!string_vals.is_integer());
220 assert!(int_vals.is_integer());
221 }
222
223 #[test]
224 fn test_enum_values_variant_names_string() {
225 let vals = EnumValues::String(vec!["pending".into(), "active".into()]);
226 assert_eq!(vals.variant_names(), vec!["pending", "active"]);
227 }
228
229 #[test]
230 fn test_enum_values_variant_names_integer() {
231 let vals = EnumValues::Integer(vec![
232 NumValue {
233 name: "Low".into(),
234 value: 0,
235 },
236 NumValue {
237 name: "High".into(),
238 value: 10,
239 },
240 ]);
241 assert_eq!(vals.variant_names(), vec!["Low", "High"]);
242 }
243
244 #[test]
245 fn test_enum_values_len_and_is_empty() {
246 let empty = EnumValues::String(vec![]);
248 let non_empty = EnumValues::String(vec!["a".into()]);
249 assert!(empty.is_empty());
250 assert_eq!(empty.len(), 0);
251 assert!(!non_empty.is_empty());
252 assert_eq!(non_empty.len(), 1);
253
254 let empty_int = EnumValues::Integer(vec![]);
256 let non_empty_int = EnumValues::Integer(vec![
257 NumValue {
258 name: "A".into(),
259 value: 0,
260 },
261 NumValue {
262 name: "B".into(),
263 value: 1,
264 },
265 ]);
266 assert!(empty_int.is_empty());
267 assert_eq!(empty_int.len(), 0);
268 assert!(!non_empty_int.is_empty());
269 assert_eq!(non_empty_int.len(), 2);
270 }
271
272 #[test]
273 fn test_enum_values_to_sql_values_string() {
274 let vals = EnumValues::String(vec!["active".into(), "pending".into()]);
275 assert_eq!(vals.to_sql_values(), vec!["'active'", "'pending'"]);
276 }
277
278 #[test]
279 fn to_sql_values_escapes_single_quotes() {
280 let vals =
281 EnumValues::String(vec!["O'Brien".into(), "Smith".into(), "'leading".into()]);
282 let sql = vals.to_sql_values();
283
284 assert!(
285 sql.iter().any(|s| s == "'O''Brien'"),
286 "single quote inside value must be doubled"
287 );
288 assert!(
289 sql.iter().any(|s| s == "'''leading'"),
290 "leading single quote must be doubled"
291 );
292 assert!(
293 sql.iter().any(|s| s == "'Smith'"),
294 "values without quotes are unchanged"
295 );
296 }
297
298 #[test]
299 fn test_enum_values_to_sql_values_integer() {
300 let vals = EnumValues::Integer(vec![
301 NumValue {
302 name: "Low".into(),
303 value: 0,
304 },
305 NumValue {
306 name: "High".into(),
307 value: 10,
308 },
309 ]);
310 assert_eq!(vals.to_sql_values(), vec!["0", "10"]);
311 }
312
313 #[test]
314 fn test_enum_values_from_vec_string() {
315 let vals: EnumValues = vec!["a".to_string(), "b".to_string()].into();
316 assert!(matches!(vals, EnumValues::String(_)));
317 }
318
319 #[test]
320 fn test_enum_values_from_vec_str() {
321 let vals: EnumValues = vec!["a", "b"].into();
322 assert!(matches!(vals, EnumValues::String(_)));
323 }
324
325 #[rstest]
326 #[case(SimpleColumnType::SmallInt, true)]
327 #[case(SimpleColumnType::Integer, true)]
328 #[case(SimpleColumnType::BigInt, true)]
329 #[case(SimpleColumnType::Text, false)]
330 #[case(SimpleColumnType::Boolean, false)]
331 fn test_simple_column_type_supports_auto_increment(
332 #[case] ty: SimpleColumnType,
333 #[case] expected: bool,
334 ) {
335 assert_eq!(ty.supports_auto_increment(), expected);
336 }
337
338 #[rstest]
339 #[case(SimpleColumnType::Integer, true)]
340 #[case(SimpleColumnType::Text, false)]
341 fn test_column_type_simple_supports_auto_increment(
342 #[case] ty: SimpleColumnType,
343 #[case] expected: bool,
344 ) {
345 assert_eq!(ColumnType::Simple(ty).supports_auto_increment(), expected);
346 }
347
348 #[test]
349 fn test_requires_migration_integer_enum_values_changed() {
350 let from = ColumnType::Complex(ComplexColumnType::Enum {
352 name: "status".into(),
353 values: EnumValues::Integer(vec![
354 NumValue {
355 name: "Pending".into(),
356 value: 0,
357 },
358 NumValue {
359 name: "Active".into(),
360 value: 1,
361 },
362 ]),
363 });
364 let to = ColumnType::Complex(ComplexColumnType::Enum {
365 name: "status".into(),
366 values: EnumValues::Integer(vec![
367 NumValue {
368 name: "Pending".into(),
369 value: 0,
370 },
371 NumValue {
372 name: "Active".into(),
373 value: 1,
374 },
375 NumValue {
376 name: "Completed".into(),
377 value: 100,
378 },
379 ]),
380 });
381 assert!(!from.requires_migration(&to));
382 }
383
384 #[test]
385 fn requires_migration_integer_enum_name_change_is_false() {
386 let e1 = ColumnType::Complex(ComplexColumnType::Enum {
387 name: "old_status".into(),
388 values: EnumValues::Integer(vec![
389 NumValue {
390 name: "active".into(),
391 value: 0,
392 },
393 NumValue {
394 name: "inactive".into(),
395 value: 1,
396 },
397 ]),
398 });
399 let e2 = ColumnType::Complex(ComplexColumnType::Enum {
400 name: "new_status".into(),
401 values: EnumValues::Integer(vec![
402 NumValue {
403 name: "active".into(),
404 value: 0,
405 },
406 NumValue {
407 name: "inactive".into(),
408 value: 1,
409 },
410 ]),
411 });
412
413 assert!(
414 !e1.requires_migration(&e2),
415 "integer enum name change should NOT require migration (stored as INTEGER, no DB schema change)"
416 );
417 }
418
419 #[test]
420 fn test_requires_migration_integer_enum_name_changed() {
421 let from = ColumnType::Complex(ComplexColumnType::Enum {
423 name: "old_status".into(),
424 values: EnumValues::Integer(vec![NumValue {
425 name: "Pending".into(),
426 value: 0,
427 }]),
428 });
429 let to = ColumnType::Complex(ComplexColumnType::Enum {
430 name: "new_status".into(),
431 values: EnumValues::Integer(vec![NumValue {
432 name: "Pending".into(),
433 value: 0,
434 }]),
435 });
436 assert!(!from.requires_migration(&to));
437 }
438
439 #[test]
440 fn test_requires_migration_string_enum_values_changed() {
441 let from = ColumnType::Complex(ComplexColumnType::Enum {
443 name: "status".into(),
444 values: EnumValues::String(vec!["pending".into(), "active".into()]),
445 });
446 let to = ColumnType::Complex(ComplexColumnType::Enum {
447 name: "status".into(),
448 values: EnumValues::String(vec![
449 "pending".into(),
450 "active".into(),
451 "completed".into(),
452 ]),
453 });
454 assert!(from.requires_migration(&to));
455 }
456
457 #[test]
458 fn test_requires_migration_simple_types() {
459 let int = ColumnType::Simple(SimpleColumnType::Integer);
460 let text = ColumnType::Simple(SimpleColumnType::Text);
461 assert!(int.requires_migration(&text));
462 assert!(!int.requires_migration(&int));
463 }
464
465 #[test]
466 fn test_requires_migration_mixed_enum_types() {
467 let string_enum = ColumnType::Complex(ComplexColumnType::Enum {
469 name: "status".into(),
470 values: EnumValues::String(vec!["pending".into()]),
471 });
472 let int_enum = ColumnType::Complex(ComplexColumnType::Enum {
473 name: "status".into(),
474 values: EnumValues::Integer(vec![NumValue {
475 name: "Pending".into(),
476 value: 0,
477 }]),
478 });
479 assert!(string_enum.requires_migration(&int_enum));
480 }
481
482 #[rstest]
484 #[case(SimpleColumnType::SmallInt, "smallint")]
485 #[case(SimpleColumnType::Integer, "integer")]
486 #[case(SimpleColumnType::BigInt, "bigint")]
487 #[case(SimpleColumnType::Real, "real")]
488 #[case(SimpleColumnType::DoublePrecision, "double precision")]
489 #[case(SimpleColumnType::Text, "text")]
490 #[case(SimpleColumnType::Boolean, "boolean")]
491 #[case(SimpleColumnType::Date, "date")]
492 #[case(SimpleColumnType::Time, "time")]
493 #[case(SimpleColumnType::Timestamp, "timestamp")]
494 #[case(SimpleColumnType::Timestamptz, "timestamptz")]
495 #[case(SimpleColumnType::Interval, "interval")]
496 #[case(SimpleColumnType::Bytea, "bytea")]
497 #[case(SimpleColumnType::Uuid, "uuid")]
498 #[case(SimpleColumnType::Json, "json")]
499 #[case(SimpleColumnType::Inet, "inet")]
500 #[case(SimpleColumnType::Cidr, "cidr")]
501 #[case(SimpleColumnType::Macaddr, "macaddr")]
502 #[case(SimpleColumnType::Xml, "xml")]
503 fn test_simple_column_type_to_display_string(
504 #[case] column_type: SimpleColumnType,
505 #[case] expected: &str,
506 ) {
507 assert_eq!(column_type.to_display_string(), expected);
508 }
509
510 #[rstest]
511 #[case(SimpleColumnType::SmallInt, "SMALLINT")]
512 #[case(SimpleColumnType::Integer, "INTEGER")]
513 #[case(SimpleColumnType::BigInt, "BIGINT")]
514 #[case(SimpleColumnType::Real, "REAL")]
515 #[case(SimpleColumnType::DoublePrecision, "DOUBLE PRECISION")]
516 #[case(SimpleColumnType::Text, "TEXT")]
517 #[case(SimpleColumnType::Boolean, "BOOLEAN")]
518 #[case(SimpleColumnType::Date, "DATE")]
519 #[case(SimpleColumnType::Time, "TIME")]
520 #[case(SimpleColumnType::Timestamp, "TIMESTAMP")]
521 #[case(SimpleColumnType::Timestamptz, "TIMESTAMPTZ")]
522 #[case(SimpleColumnType::Interval, "INTERVAL")]
523 #[case(SimpleColumnType::Bytea, "BYTEA")]
524 #[case(SimpleColumnType::Uuid, "UUID")]
525 #[case(SimpleColumnType::Json, "JSON")]
526 #[case(SimpleColumnType::Inet, "INET")]
527 #[case(SimpleColumnType::Cidr, "CIDR")]
528 #[case(SimpleColumnType::Macaddr, "MACADDR")]
529 #[case(SimpleColumnType::Xml, "XML")]
530 fn test_simple_column_type_sql_type(
531 #[case] column_type: SimpleColumnType,
532 #[case] expected: &str,
533 ) {
534 assert_eq!(column_type.sql_type(), expected);
535 }
536
537 #[rstest]
538 #[case(ComplexColumnType::Varchar { length: 255 }, "VARCHAR")]
539 #[case(ComplexColumnType::Numeric { precision: 10, scale: 2 }, "NUMERIC")]
540 #[case(ComplexColumnType::Char { length: 5 }, "CHAR")]
541 #[case(ComplexColumnType::Custom { custom_type: "MONEY".into() }, "CUSTOM")]
542 #[case(ComplexColumnType::Enum { name: "status".into(), values: EnumValues::String(vec!["active".into()]) }, "ENUM")]
543 fn test_complex_column_type_sql_type(
544 #[case] column_type: ComplexColumnType,
545 #[case] expected: &str,
546 ) {
547 assert_eq!(column_type.sql_type(), expected);
548 }
549
550 #[test]
551 fn test_complex_column_type_to_display_string_varchar() {
552 let ty = ComplexColumnType::Varchar { length: 255 };
553 assert_eq!(ty.to_display_string(), "varchar(255)");
554 }
555
556 #[test]
557 fn test_complex_column_type_to_display_string_numeric() {
558 let ty = ComplexColumnType::Numeric {
559 precision: 10,
560 scale: 2,
561 };
562 assert_eq!(ty.to_display_string(), "numeric(10,2)");
563 }
564
565 #[test]
566 fn test_complex_column_type_to_display_string_char() {
567 let ty = ComplexColumnType::Char { length: 5 };
568 assert_eq!(ty.to_display_string(), "char(5)");
569 }
570
571 #[test]
572 fn test_complex_column_type_to_display_string_custom() {
573 let ty = ComplexColumnType::Custom {
574 custom_type: "TSVECTOR".into(),
575 };
576 assert_eq!(ty.to_display_string(), "tsvector");
577 }
578
579 #[test]
580 fn test_complex_column_type_to_display_string_string_enum() {
581 let ty = ComplexColumnType::Enum {
582 name: "user_status".into(),
583 values: EnumValues::String(vec!["active".into(), "inactive".into()]),
584 };
585 assert_eq!(ty.to_display_string(), "enum<user_status>");
586 }
587
588 #[test]
589 fn test_complex_column_type_to_display_string_integer_enum() {
590 let ty = ComplexColumnType::Enum {
591 name: "priority".into(),
592 values: EnumValues::Integer(vec![
593 NumValue {
594 name: "Low".into(),
595 value: 0,
596 },
597 NumValue {
598 name: "High".into(),
599 value: 10,
600 },
601 ]),
602 };
603 assert_eq!(ty.to_display_string(), "enum<priority> (integer)");
604 }
605
606 #[test]
607 fn test_column_type_to_display_string_simple() {
608 let ty = ColumnType::Simple(SimpleColumnType::Integer);
609 assert_eq!(ty.to_display_string(), "integer");
610 }
611
612 #[test]
613 fn test_column_type_to_display_string_complex() {
614 let ty = ColumnType::Complex(ComplexColumnType::Varchar { length: 100 });
615 assert_eq!(ty.to_display_string(), "varchar(100)");
616 }
617
618 #[rstest]
620 #[case(SimpleColumnType::SmallInt, "0")]
621 #[case(SimpleColumnType::Integer, "0")]
622 #[case(SimpleColumnType::BigInt, "0")]
623 #[case(SimpleColumnType::Real, "0.0")]
624 #[case(SimpleColumnType::DoublePrecision, "0.0")]
625 #[case(SimpleColumnType::Boolean, "false")]
626 #[case(SimpleColumnType::Text, "''")]
627 #[case(SimpleColumnType::Date, "'1970-01-01'")]
628 #[case(SimpleColumnType::Time, "'00:00:00'")]
629 #[case(SimpleColumnType::Timestamp, "CURRENT_TIMESTAMP")]
630 #[case(SimpleColumnType::Timestamptz, "CURRENT_TIMESTAMP")]
631 #[case(SimpleColumnType::Interval, "'0'")]
632 #[case(SimpleColumnType::Bytea, "''")]
633 #[case(SimpleColumnType::Uuid, "'00000000-0000-0000-0000-000000000000'")]
634 #[case(SimpleColumnType::Json, "'{}'")]
635 #[case(SimpleColumnType::Inet, "'0.0.0.0'")]
636 #[case(SimpleColumnType::Cidr, "'0.0.0.0'")]
637 #[case(SimpleColumnType::Macaddr, "'00:00:00:00:00:00'")]
638 #[case(SimpleColumnType::Xml, "'<xml/>'")]
639 fn test_simple_column_type_default_fill_value(
640 #[case] column_type: SimpleColumnType,
641 #[case] expected: &str,
642 ) {
643 assert_eq!(column_type.default_fill_value(), expected);
644 }
645
646 #[test]
647 fn test_complex_column_type_default_fill_value_varchar() {
648 let ty = ComplexColumnType::Varchar { length: 255 };
649 assert_eq!(ty.default_fill_value(), "''");
650 }
651
652 #[test]
653 fn test_complex_column_type_default_fill_value_char() {
654 let ty = ComplexColumnType::Char { length: 1 };
655 assert_eq!(ty.default_fill_value(), "''");
656 }
657
658 #[test]
659 fn test_complex_column_type_default_fill_value_numeric() {
660 let ty = ComplexColumnType::Numeric {
661 precision: 10,
662 scale: 2,
663 };
664 assert_eq!(ty.default_fill_value(), "0");
665 }
666
667 #[test]
668 fn test_complex_column_type_default_fill_value_custom() {
669 let ty = ComplexColumnType::Custom {
670 custom_type: "MONEY".into(),
671 };
672 assert_eq!(ty.default_fill_value(), "''");
673 }
674
675 #[test]
676 fn test_complex_column_type_default_fill_value_enum() {
677 let ty = ComplexColumnType::Enum {
678 name: "status".into(),
679 values: EnumValues::String(vec!["active".into()]),
680 };
681 assert_eq!(ty.default_fill_value(), "''");
682 }
683
684 #[test]
685 fn test_column_type_default_fill_value_simple() {
686 let ty = ColumnType::Simple(SimpleColumnType::Integer);
687 assert_eq!(ty.default_fill_value(), "0");
688 }
689
690 #[test]
691 fn test_column_type_default_fill_value_complex() {
692 let ty = ColumnType::Complex(ComplexColumnType::Varchar { length: 100 });
693 assert_eq!(ty.default_fill_value(), "''");
694 }
695
696 #[test]
698 fn test_enum_variant_names_simple_type_returns_none() {
699 let ty = ColumnType::Simple(SimpleColumnType::Integer);
700 assert_eq!(ty.enum_variant_names(), None);
701 }
702
703 #[test]
704 fn test_enum_variant_names_complex_non_enum_returns_none() {
705 let ty = ColumnType::Complex(ComplexColumnType::Varchar { length: 255 });
706 assert_eq!(ty.enum_variant_names(), None);
707 }
708
709 #[test]
710 fn test_enum_variant_names_complex_numeric_returns_none() {
711 let ty = ColumnType::Complex(ComplexColumnType::Numeric {
712 precision: 10,
713 scale: 2,
714 });
715 assert_eq!(ty.enum_variant_names(), None);
716 }
717
718 #[test]
719 fn test_enum_variant_names_complex_char_returns_none() {
720 let ty = ColumnType::Complex(ComplexColumnType::Char { length: 1 });
721 assert_eq!(ty.enum_variant_names(), None);
722 }
723
724 #[test]
725 fn test_enum_variant_names_complex_custom_returns_none() {
726 let ty = ColumnType::Complex(ComplexColumnType::Custom {
727 custom_type: "TSVECTOR".into(),
728 });
729 assert_eq!(ty.enum_variant_names(), None);
730 }
731
732 #[test]
733 fn test_enum_variant_names_string_enum() {
734 let ty = ColumnType::Complex(ComplexColumnType::Enum {
735 name: "status".into(),
736 values: EnumValues::String(vec![
737 "active".into(),
738 "inactive".into(),
739 "pending".into(),
740 ]),
741 });
742 assert_eq!(
743 ty.enum_variant_names(),
744 Some(vec![
745 "active".to_string(),
746 "inactive".to_string(),
747 "pending".to_string()
748 ])
749 );
750 }
751
752 #[test]
753 fn test_enum_variant_names_integer_enum() {
754 let ty = ColumnType::Complex(ComplexColumnType::Enum {
755 name: "priority".into(),
756 values: EnumValues::Integer(vec![
757 NumValue {
758 name: "Low".into(),
759 value: 0,
760 },
761 NumValue {
762 name: "Medium".into(),
763 value: 5,
764 },
765 NumValue {
766 name: "High".into(),
767 value: 10,
768 },
769 ]),
770 });
771 assert_eq!(
772 ty.enum_variant_names(),
773 Some(vec![
774 "Low".to_string(),
775 "Medium".to_string(),
776 "High".to_string()
777 ])
778 );
779 }
780
781 #[test]
782 fn test_enum_variant_names_empty_string_enum() {
783 let ty = ColumnType::Complex(ComplexColumnType::Enum {
784 name: "empty".into(),
785 values: EnumValues::String(vec![]),
786 });
787 assert_eq!(ty.enum_variant_names(), Some(vec![]));
788 }
789
790 #[test]
791 fn test_enum_variant_names_empty_integer_enum() {
792 let ty = ColumnType::Complex(ComplexColumnType::Enum {
793 name: "empty".into(),
794 values: EnumValues::Integer(vec![]),
795 });
796 assert_eq!(ty.enum_variant_names(), Some(vec![]));
797 }
798 }
799}