1pub mod add_column;
2pub mod add_constraint;
3pub mod create_table;
4pub mod delete_column;
5pub mod delete_table;
6pub mod helpers;
7pub mod modify_column_comment;
8pub mod modify_column_default;
9pub mod modify_column_nullable;
10pub mod modify_column_type;
11pub mod raw_sql;
12pub mod remove_constraint;
13pub mod rename_column;
14pub mod rename_table;
15pub mod types;
16
17pub use helpers::*;
18pub use types::{BuiltQuery, DatabaseBackend, RawSql};
19
20use crate::error::QueryError;
21use vespertide_core::{MigrationAction, TableConstraint, TableDef};
22
23use self::{
24 add_column::build_add_column, add_constraint::build_add_constraint,
25 create_table::build_create_table, delete_column::build_delete_column,
26 delete_table::build_delete_table, modify_column_comment::build_modify_column_comment,
27 modify_column_default::build_modify_column_default,
28 modify_column_nullable::build_modify_column_nullable,
29 modify_column_type::build_modify_column_type, raw_sql::build_raw_sql,
30 remove_constraint::build_remove_constraint, rename_column::build_rename_column,
31 rename_table::build_rename_table,
32};
33
34pub fn build_action_queries(
35 backend: &DatabaseBackend,
36 action: &MigrationAction,
37 current_schema: &[TableDef],
38) -> Result<Vec<BuiltQuery>, QueryError> {
39 build_action_queries_with_pending(backend, action, current_schema, &[])
40}
41
42pub fn build_action_queries_with_pending(
48 backend: &DatabaseBackend,
49 action: &MigrationAction,
50 current_schema: &[TableDef],
51 pending_constraints: &[TableConstraint],
52) -> Result<Vec<BuiltQuery>, QueryError> {
53 match action {
54 MigrationAction::CreateTable {
55 table,
56 columns,
57 constraints,
58 } => build_create_table(backend, table, columns, constraints),
59
60 MigrationAction::DeleteTable { table } => Ok(vec![build_delete_table(table)]),
61
62 MigrationAction::AddColumn {
63 table,
64 column,
65 fill_with,
66 } => build_add_column(backend, table, column, fill_with.as_deref(), current_schema),
67
68 MigrationAction::RenameColumn { table, from, to } => {
69 Ok(vec![build_rename_column(table, from, to)])
70 }
71
72 MigrationAction::DeleteColumn { table, column } => {
73 let column_type = current_schema
75 .iter()
76 .find(|t| t.name == *table)
77 .and_then(|t| t.columns.iter().find(|c| c.name == *column))
78 .map(|c| &c.r#type);
79 Ok(build_delete_column(
80 backend,
81 table,
82 column,
83 column_type,
84 current_schema,
85 ))
86 }
87
88 MigrationAction::ModifyColumnType {
89 table,
90 column,
91 new_type,
92 fill_with,
93 } => build_modify_column_type(
94 backend,
95 table,
96 column,
97 new_type,
98 fill_with.as_ref(),
99 current_schema,
100 ),
101
102 MigrationAction::ModifyColumnNullable {
103 table,
104 column,
105 nullable,
106 fill_with,
107 delete_null_rows,
108 } => build_modify_column_nullable(
109 backend,
110 table,
111 column,
112 *nullable,
113 fill_with.as_deref(),
114 delete_null_rows.unwrap_or(false),
115 current_schema,
116 ),
117
118 MigrationAction::ModifyColumnDefault {
119 table,
120 column,
121 new_default,
122 } => build_modify_column_default(
123 backend,
124 table,
125 column,
126 new_default.as_deref(),
127 current_schema,
128 ),
129
130 MigrationAction::ModifyColumnComment {
131 table,
132 column,
133 new_comment,
134 } => build_modify_column_comment(
135 backend,
136 table,
137 column,
138 new_comment.as_deref(),
139 current_schema,
140 ),
141
142 MigrationAction::RenameTable { from, to } => Ok(vec![build_rename_table(from, to)]),
143
144 MigrationAction::RawSql { sql } => Ok(vec![build_raw_sql(sql.clone())]),
145
146 MigrationAction::AddConstraint { table, constraint } => build_add_constraint(
147 backend,
148 table,
149 constraint,
150 current_schema,
151 pending_constraints,
152 ),
153
154 MigrationAction::RemoveConstraint { table, constraint } => {
155 build_remove_constraint(backend, table, constraint, current_schema)
156 }
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163 use insta::{assert_snapshot, with_settings};
164 use rstest::rstest;
165 use vespertide_core::schema::primary_key::PrimaryKeySyntax;
166 use vespertide_core::{
167 ColumnDef, ColumnType, MigrationAction, ReferenceAction, SimpleColumnType, TableConstraint,
168 };
169
170 fn col(name: &str, ty: ColumnType) -> ColumnDef {
171 ColumnDef {
172 name: name.to_string(),
173 r#type: ty,
174 nullable: true,
175 default: None,
176 comment: None,
177 primary_key: None,
178 unique: None,
179 index: None,
180 foreign_key: None,
181 }
182 }
183
184 #[test]
185 fn test_backend_specific_quoting() {
186 let action = MigrationAction::CreateTable {
187 table: "users".into(),
188 columns: vec![col("id", ColumnType::Simple(SimpleColumnType::Integer))],
189 constraints: vec![],
190 };
191 let result = build_action_queries(&DatabaseBackend::Postgres, &action, &[]).unwrap();
192
193 let pg_sql = result[0].build(DatabaseBackend::Postgres);
195 assert!(pg_sql.contains("\"users\""));
196
197 let mysql_sql = result[0].build(DatabaseBackend::MySql);
199 assert!(mysql_sql.contains("`users`"));
200
201 let sqlite_sql = result[0].build(DatabaseBackend::Sqlite);
203 assert!(sqlite_sql.contains("\"users\""));
204 }
205
206 #[rstest]
207 #[case::create_table_with_default_postgres(
208 "create_table_with_default_postgres",
209 MigrationAction::CreateTable {
210 table: "users".into(),
211 columns: vec![ColumnDef {
212 name: "status".into(),
213 r#type: ColumnType::Simple(SimpleColumnType::Text),
214 nullable: true,
215 default: Some("'active'".into()),
216 comment: None,
217 primary_key: None,
218 unique: None,
219 index: None,
220 foreign_key: None,
221 }],
222 constraints: vec![],
223 },
224 DatabaseBackend::Postgres,
225 &["DEFAULT", "'active'"]
226 )]
227 #[case::create_table_with_default_mysql(
228 "create_table_with_default_mysql",
229 MigrationAction::CreateTable {
230 table: "users".into(),
231 columns: vec![ColumnDef {
232 name: "status".into(),
233 r#type: ColumnType::Simple(SimpleColumnType::Text),
234 nullable: true,
235 default: Some("'active'".into()),
236 comment: None,
237 primary_key: None,
238 unique: None,
239 index: None,
240 foreign_key: None,
241 }],
242 constraints: vec![],
243 },
244 DatabaseBackend::Postgres,
245 &["DEFAULT", "'active'"]
246 )]
247 #[case::create_table_with_default_sqlite(
248 "create_table_with_default_sqlite",
249 MigrationAction::CreateTable {
250 table: "users".into(),
251 columns: vec![ColumnDef {
252 name: "status".into(),
253 r#type: ColumnType::Simple(SimpleColumnType::Text),
254 nullable: true,
255 default: Some("'active'".into()),
256 comment: None,
257 primary_key: None,
258 unique: None,
259 index: None,
260 foreign_key: None,
261 }],
262 constraints: vec![],
263 },
264 DatabaseBackend::Postgres,
265 &["DEFAULT", "'active'"]
266 )]
267 #[case::create_table_with_inline_primary_key_postgres(
268 "create_table_with_inline_primary_key_postgres",
269 MigrationAction::CreateTable {
270 table: "users".into(),
271 columns: vec![ColumnDef {
272 name: "id".into(),
273 r#type: ColumnType::Simple(SimpleColumnType::Integer),
274 nullable: false,
275 default: None,
276 comment: None,
277 primary_key: Some(PrimaryKeySyntax::Bool(true)),
278 unique: None,
279 index: None,
280 foreign_key: None,
281 }],
282 constraints: vec![],
283 },
284 DatabaseBackend::Postgres,
285 &["PRIMARY KEY"]
286 )]
287 #[case::create_table_with_inline_primary_key_mysql(
288 "create_table_with_inline_primary_key_mysql",
289 MigrationAction::CreateTable {
290 table: "users".into(),
291 columns: vec![ColumnDef {
292 name: "id".into(),
293 r#type: ColumnType::Simple(SimpleColumnType::Integer),
294 nullable: false,
295 default: None,
296 comment: None,
297 primary_key: Some(PrimaryKeySyntax::Bool(true)),
298 unique: None,
299 index: None,
300 foreign_key: None,
301 }],
302 constraints: vec![],
303 },
304 DatabaseBackend::Postgres,
305 &["PRIMARY KEY"]
306 )]
307 #[case::create_table_with_inline_primary_key_sqlite(
308 "create_table_with_inline_primary_key_sqlite",
309 MigrationAction::CreateTable {
310 table: "users".into(),
311 columns: vec![ColumnDef {
312 name: "id".into(),
313 r#type: ColumnType::Simple(SimpleColumnType::Integer),
314 nullable: false,
315 default: None,
316 comment: None,
317 primary_key: Some(PrimaryKeySyntax::Bool(true)),
318 unique: None,
319 index: None,
320 foreign_key: None,
321 }],
322 constraints: vec![],
323 },
324 DatabaseBackend::Postgres,
325 &["PRIMARY KEY"]
326 )]
327 #[case::create_table_with_fk_postgres(
328 "create_table_with_fk_postgres",
329 MigrationAction::CreateTable {
330 table: "posts".into(),
331 columns: vec![
332 col("id", ColumnType::Simple(SimpleColumnType::Integer)),
333 col("user_id", ColumnType::Simple(SimpleColumnType::Integer)),
334 ],
335 constraints: vec![TableConstraint::ForeignKey {
336 name: Some("fk_user".into()),
337 columns: vec!["user_id".into()],
338 ref_table: "users".into(),
339 ref_columns: vec!["id".into()],
340 on_delete: Some(ReferenceAction::Cascade),
341 on_update: Some(ReferenceAction::Restrict),
342 }],
343 },
344 DatabaseBackend::Postgres,
345 &["REFERENCES \"users\" (\"id\")", "ON DELETE CASCADE", "ON UPDATE RESTRICT"]
346 )]
347 #[case::create_table_with_fk_mysql(
348 "create_table_with_fk_mysql",
349 MigrationAction::CreateTable {
350 table: "posts".into(),
351 columns: vec![
352 col("id", ColumnType::Simple(SimpleColumnType::Integer)),
353 col("user_id", ColumnType::Simple(SimpleColumnType::Integer)),
354 ],
355 constraints: vec![TableConstraint::ForeignKey {
356 name: Some("fk_user".into()),
357 columns: vec!["user_id".into()],
358 ref_table: "users".into(),
359 ref_columns: vec!["id".into()],
360 on_delete: Some(ReferenceAction::Cascade),
361 on_update: Some(ReferenceAction::Restrict),
362 }],
363 },
364 DatabaseBackend::Postgres,
365 &["REFERENCES \"users\" (\"id\")", "ON DELETE CASCADE", "ON UPDATE RESTRICT"]
366 )]
367 #[case::create_table_with_fk_sqlite(
368 "create_table_with_fk_sqlite",
369 MigrationAction::CreateTable {
370 table: "posts".into(),
371 columns: vec![
372 col("id", ColumnType::Simple(SimpleColumnType::Integer)),
373 col("user_id", ColumnType::Simple(SimpleColumnType::Integer)),
374 ],
375 constraints: vec![TableConstraint::ForeignKey {
376 name: Some("fk_user".into()),
377 columns: vec!["user_id".into()],
378 ref_table: "users".into(),
379 ref_columns: vec!["id".into()],
380 on_delete: Some(ReferenceAction::Cascade),
381 on_update: Some(ReferenceAction::Restrict),
382 }],
383 },
384 DatabaseBackend::Postgres,
385 &["REFERENCES \"users\" (\"id\")", "ON DELETE CASCADE", "ON UPDATE RESTRICT"]
386 )]
387 fn test_build_migration_action(
388 #[case] title: &str,
389 #[case] action: MigrationAction,
390 #[case] backend: DatabaseBackend,
391 #[case] expected: &[&str],
392 ) {
393 let result = build_action_queries(&backend, &action, &[]).unwrap();
394 let sql = result[0].build(backend);
395 for exp in expected {
396 assert!(
397 sql.contains(exp),
398 "Expected SQL to contain '{}', got: {}",
399 exp,
400 sql
401 );
402 }
403
404 with_settings!({ snapshot_suffix => format!("build_migration_action_{}", title) }, {
405 assert_snapshot!(result.iter().map(|q| q.build(backend)).collect::<Vec<String>>().join("\n"));
406 });
407 }
408
409 #[rstest]
410 #[case::rename_column_postgres(DatabaseBackend::Postgres)]
411 #[case::rename_column_mysql(DatabaseBackend::MySql)]
412 #[case::rename_column_sqlite(DatabaseBackend::Sqlite)]
413 fn test_build_action_queries_rename_column(#[case] backend: DatabaseBackend) {
414 let action = MigrationAction::RenameColumn {
416 table: "users".into(),
417 from: "old_name".into(),
418 to: "new_name".into(),
419 };
420 let result = build_action_queries(&backend, &action, &[]).unwrap();
421 assert_eq!(result.len(), 1);
422 let sql = result[0].build(backend);
423 assert!(sql.contains("RENAME"));
424 assert!(sql.contains("old_name"));
425 assert!(sql.contains("new_name"));
426
427 with_settings!({ snapshot_suffix => format!("rename_column_{:?}", backend) }, {
428 assert_snapshot!(sql);
429 });
430 }
431
432 #[rstest]
433 #[case::delete_column_postgres(DatabaseBackend::Postgres)]
434 #[case::delete_column_mysql(DatabaseBackend::MySql)]
435 #[case::delete_column_sqlite(DatabaseBackend::Sqlite)]
436 fn test_build_action_queries_delete_column(#[case] backend: DatabaseBackend) {
437 let action = MigrationAction::DeleteColumn {
439 table: "users".into(),
440 column: "email".into(),
441 };
442 let result = build_action_queries(&backend, &action, &[]).unwrap();
443 assert_eq!(result.len(), 1);
444 let sql = result[0].build(backend);
445 assert!(sql.contains("DROP COLUMN"));
446 assert!(sql.contains("email"));
447
448 with_settings!({ snapshot_suffix => format!("delete_column_{:?}", backend) }, {
449 assert_snapshot!(sql);
450 });
451 }
452
453 #[rstest]
454 #[case::modify_column_type_postgres(DatabaseBackend::Postgres)]
455 #[case::modify_column_type_mysql(DatabaseBackend::MySql)]
456 #[case::modify_column_type_sqlite(DatabaseBackend::Sqlite)]
457 fn test_build_action_queries_modify_column_type(#[case] backend: DatabaseBackend) {
458 let action = MigrationAction::ModifyColumnType {
460 table: "users".into(),
461 column: "age".into(),
462 new_type: ColumnType::Simple(SimpleColumnType::BigInt),
463 fill_with: None,
464 };
465 let current_schema = vec![TableDef {
466 name: "users".into(),
467 description: None,
468 columns: vec![ColumnDef {
469 name: "age".into(),
470 r#type: ColumnType::Simple(SimpleColumnType::Integer),
471 nullable: true,
472 default: None,
473 comment: None,
474 primary_key: None,
475 unique: None,
476 index: None,
477 foreign_key: None,
478 }],
479 constraints: vec![],
480 }];
481 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
482 assert!(!result.is_empty());
483 let sql = result
484 .iter()
485 .map(|q| q.build(backend))
486 .collect::<Vec<String>>()
487 .join("\n");
488 assert!(sql.contains("ALTER TABLE"));
489
490 with_settings!({ snapshot_suffix => format!("modify_column_type_{:?}", backend) }, {
491 assert_snapshot!(sql);
492 });
493 }
494
495 #[rstest]
496 #[case::remove_index_constraint_postgres(DatabaseBackend::Postgres)]
497 #[case::remove_index_constraint_mysql(DatabaseBackend::MySql)]
498 #[case::remove_index_constraint_sqlite(DatabaseBackend::Sqlite)]
499 fn test_build_action_queries_remove_index_constraint(#[case] backend: DatabaseBackend) {
500 let action = MigrationAction::RemoveConstraint {
502 table: "users".into(),
503 constraint: TableConstraint::Index {
504 name: Some("idx_email".into()),
505 columns: vec!["email".into()],
506 },
507 };
508 let result = build_action_queries(&backend, &action, &[]).unwrap();
509 assert_eq!(result.len(), 1);
510 let sql = result[0].build(backend);
511 assert!(sql.contains("DROP INDEX"));
512 assert!(sql.contains("idx_email"));
513
514 with_settings!({ snapshot_suffix => format!("remove_index_constraint_{:?}", backend) }, {
515 assert_snapshot!(sql);
516 });
517 }
518
519 #[rstest]
520 #[case::rename_table_postgres(DatabaseBackend::Postgres)]
521 #[case::rename_table_mysql(DatabaseBackend::MySql)]
522 #[case::rename_table_sqlite(DatabaseBackend::Sqlite)]
523 fn test_build_action_queries_rename_table(#[case] backend: DatabaseBackend) {
524 let action = MigrationAction::RenameTable {
526 from: "old_table".into(),
527 to: "new_table".into(),
528 };
529 let result = build_action_queries(&backend, &action, &[]).unwrap();
530 assert_eq!(result.len(), 1);
531 let sql = result[0].build(backend);
532 assert!(sql.contains("RENAME"));
533 assert!(sql.contains("old_table"));
534 assert!(sql.contains("new_table"));
535
536 with_settings!({ snapshot_suffix => format!("rename_table_{:?}", backend) }, {
537 assert_snapshot!(sql);
538 });
539 }
540
541 #[rstest]
542 #[case::add_constraint_postgres(DatabaseBackend::Postgres)]
543 #[case::add_constraint_mysql(DatabaseBackend::MySql)]
544 #[case::add_constraint_sqlite(DatabaseBackend::Sqlite)]
545 fn test_build_action_queries_add_constraint(#[case] backend: DatabaseBackend) {
546 let action = MigrationAction::AddConstraint {
548 table: "users".into(),
549 constraint: TableConstraint::Unique {
550 name: Some("uq_email".into()),
551 columns: vec!["email".into()],
552 },
553 };
554 let current_schema = vec![TableDef {
555 name: "users".into(),
556 description: None,
557 columns: vec![
558 ColumnDef {
559 name: "id".into(),
560 r#type: ColumnType::Simple(SimpleColumnType::Integer),
561 nullable: false,
562 default: None,
563 comment: None,
564 primary_key: None,
565 unique: None,
566 index: None,
567 foreign_key: None,
568 },
569 ColumnDef {
570 name: "email".into(),
571 r#type: ColumnType::Simple(SimpleColumnType::Text),
572 nullable: true,
573 default: None,
574 comment: None,
575 primary_key: None,
576 unique: None,
577 index: None,
578 foreign_key: None,
579 },
580 ],
581 constraints: vec![],
582 }];
583 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
584 assert!(!result.is_empty());
585 let sql = result
586 .iter()
587 .map(|q| q.build(backend))
588 .collect::<Vec<String>>()
589 .join("\n");
590 assert!(sql.contains("UNIQUE") || sql.contains("uq_email"));
591
592 with_settings!({ snapshot_suffix => format!("add_constraint_{:?}", backend) }, {
593 assert_snapshot!(sql);
594 });
595 }
596
597 #[rstest]
598 #[case::remove_constraint_postgres(DatabaseBackend::Postgres)]
599 #[case::remove_constraint_mysql(DatabaseBackend::MySql)]
600 #[case::remove_constraint_sqlite(DatabaseBackend::Sqlite)]
601 fn test_build_action_queries_remove_constraint(#[case] backend: DatabaseBackend) {
602 let action = MigrationAction::RemoveConstraint {
604 table: "users".into(),
605 constraint: TableConstraint::Unique {
606 name: Some("uq_email".into()),
607 columns: vec!["email".into()],
608 },
609 };
610 let current_schema = vec![TableDef {
611 name: "users".into(),
612 description: None,
613 columns: vec![
614 ColumnDef {
615 name: "id".into(),
616 r#type: ColumnType::Simple(SimpleColumnType::Integer),
617 nullable: false,
618 default: None,
619 comment: None,
620 primary_key: None,
621 unique: None,
622 index: None,
623 foreign_key: None,
624 },
625 ColumnDef {
626 name: "email".into(),
627 r#type: ColumnType::Simple(SimpleColumnType::Text),
628 nullable: true,
629 default: None,
630 comment: None,
631 primary_key: None,
632 unique: None,
633 index: None,
634 foreign_key: None,
635 },
636 ],
637 constraints: vec![TableConstraint::Unique {
638 name: Some("uq_email".into()),
639 columns: vec!["email".into()],
640 }],
641 }];
642 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
643 assert!(!result.is_empty());
644 let sql = result
645 .iter()
646 .map(|q| q.build(backend))
647 .collect::<Vec<String>>()
648 .join("\n");
649 assert!(sql.contains("DROP") || sql.contains("CONSTRAINT"));
650
651 with_settings!({ snapshot_suffix => format!("remove_constraint_{:?}", backend) }, {
652 assert_snapshot!(sql);
653 });
654 }
655
656 #[rstest]
657 #[case::add_column_postgres(DatabaseBackend::Postgres)]
658 #[case::add_column_mysql(DatabaseBackend::MySql)]
659 #[case::add_column_sqlite(DatabaseBackend::Sqlite)]
660 fn test_build_action_queries_add_column(#[case] backend: DatabaseBackend) {
661 let action = MigrationAction::AddColumn {
663 table: "users".into(),
664 column: Box::new(ColumnDef {
665 name: "email".into(),
666 r#type: ColumnType::Simple(SimpleColumnType::Text),
667 nullable: true,
668 default: None,
669 comment: None,
670 primary_key: None,
671 unique: None,
672 index: None,
673 foreign_key: None,
674 }),
675 fill_with: None,
676 };
677 let current_schema = vec![TableDef {
678 name: "users".into(),
679 description: None,
680 columns: vec![ColumnDef {
681 name: "id".into(),
682 r#type: ColumnType::Simple(SimpleColumnType::Integer),
683 nullable: false,
684 default: None,
685 comment: None,
686 primary_key: None,
687 unique: None,
688 index: None,
689 foreign_key: None,
690 }],
691 constraints: vec![],
692 }];
693 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
694 assert!(!result.is_empty());
695 let sql = result
696 .iter()
697 .map(|q| q.build(backend))
698 .collect::<Vec<String>>()
699 .join("\n");
700 assert!(sql.contains("ALTER TABLE"));
701 assert!(sql.contains("ADD COLUMN") || sql.contains("ADD"));
702
703 with_settings!({ snapshot_suffix => format!("add_column_{:?}", backend) }, {
704 assert_snapshot!(sql);
705 });
706 }
707
708 #[rstest]
709 #[case::add_index_constraint_postgres(DatabaseBackend::Postgres)]
710 #[case::add_index_constraint_mysql(DatabaseBackend::MySql)]
711 #[case::add_index_constraint_sqlite(DatabaseBackend::Sqlite)]
712 fn test_build_action_queries_add_index_constraint(#[case] backend: DatabaseBackend) {
713 let action = MigrationAction::AddConstraint {
715 table: "users".into(),
716 constraint: TableConstraint::Index {
717 name: Some("idx_email".into()),
718 columns: vec!["email".into()],
719 },
720 };
721 let result = build_action_queries(&backend, &action, &[]).unwrap();
722 assert_eq!(result.len(), 1);
723 let sql = result[0].build(backend);
724 assert!(sql.contains("CREATE INDEX"));
725 assert!(sql.contains("idx_email"));
726
727 with_settings!({ snapshot_suffix => format!("add_index_constraint_{:?}", backend) }, {
728 assert_snapshot!(sql);
729 });
730 }
731
732 #[rstest]
733 #[case::raw_sql_postgres(DatabaseBackend::Postgres)]
734 #[case::raw_sql_mysql(DatabaseBackend::MySql)]
735 #[case::raw_sql_sqlite(DatabaseBackend::Sqlite)]
736 fn test_build_action_queries_raw_sql(#[case] backend: DatabaseBackend) {
737 let action = MigrationAction::RawSql {
739 sql: "SELECT 1;".into(),
740 };
741 let result = build_action_queries(&backend, &action, &[]).unwrap();
742 assert_eq!(result.len(), 1);
743 let sql = result[0].build(backend);
744 assert_eq!(sql, "SELECT 1;");
745
746 with_settings!({ snapshot_suffix => format!("raw_sql_{:?}", backend) }, {
747 assert_snapshot!(sql);
748 });
749 }
750
751 #[rstest]
753 #[case::add_index_with_custom_name_postgres(
754 DatabaseBackend::Postgres,
755 "hello",
756 vec!["email", "password"]
757 )]
758 #[case::add_index_with_custom_name_mysql(
759 DatabaseBackend::MySql,
760 "hello",
761 vec!["email", "password"]
762 )]
763 #[case::add_index_with_custom_name_sqlite(
764 DatabaseBackend::Sqlite,
765 "hello",
766 vec!["email", "password"]
767 )]
768 #[case::add_index_single_column_postgres(
769 DatabaseBackend::Postgres,
770 "email_idx",
771 vec!["email"]
772 )]
773 #[case::add_index_single_column_mysql(
774 DatabaseBackend::MySql,
775 "email_idx",
776 vec!["email"]
777 )]
778 #[case::add_index_single_column_sqlite(
779 DatabaseBackend::Sqlite,
780 "email_idx",
781 vec!["email"]
782 )]
783 fn test_add_index_with_custom_name(
784 #[case] backend: DatabaseBackend,
785 #[case] index_name: &str,
786 #[case] columns: Vec<&str>,
787 ) {
788 let action = MigrationAction::AddConstraint {
790 table: "user".into(),
791 constraint: TableConstraint::Index {
792 name: Some(index_name.into()),
793 columns: columns.iter().map(|s| s.to_string()).collect(),
794 },
795 };
796 let result = build_action_queries(&backend, &action, &[]).unwrap();
797 let sql = result[0].build(backend);
798
799 let expected_name = format!("ix_user__{}", index_name);
801 assert!(
802 sql.contains(&expected_name),
803 "Expected index name '{}' in SQL: {}",
804 expected_name,
805 sql
806 );
807
808 with_settings!({ snapshot_suffix => format!("add_index_custom_{}_{:?}", index_name, backend) }, {
809 assert_snapshot!(sql);
810 });
811 }
812
813 #[rstest]
814 #[case::add_unnamed_index_single_column_postgres(
815 DatabaseBackend::Postgres,
816 vec!["email"]
817 )]
818 #[case::add_unnamed_index_single_column_mysql(
819 DatabaseBackend::MySql,
820 vec!["email"]
821 )]
822 #[case::add_unnamed_index_single_column_sqlite(
823 DatabaseBackend::Sqlite,
824 vec!["email"]
825 )]
826 #[case::add_unnamed_index_multiple_columns_postgres(
827 DatabaseBackend::Postgres,
828 vec!["email", "password"]
829 )]
830 #[case::add_unnamed_index_multiple_columns_mysql(
831 DatabaseBackend::MySql,
832 vec!["email", "password"]
833 )]
834 #[case::add_unnamed_index_multiple_columns_sqlite(
835 DatabaseBackend::Sqlite,
836 vec!["email", "password"]
837 )]
838 fn test_add_unnamed_index(#[case] backend: DatabaseBackend, #[case] columns: Vec<&str>) {
839 let action = MigrationAction::AddConstraint {
841 table: "user".into(),
842 constraint: TableConstraint::Index {
843 name: None,
844 columns: columns.iter().map(|s| s.to_string()).collect(),
845 },
846 };
847 let result = build_action_queries(&backend, &action, &[]).unwrap();
848 let sql = result[0].build(backend);
849
850 let expected_name = format!("ix_user__{}", columns.join("_"));
852 assert!(
853 sql.contains(&expected_name),
854 "Expected index name '{}' in SQL: {}",
855 expected_name,
856 sql
857 );
858
859 with_settings!({ snapshot_suffix => format!("add_unnamed_index_{}_{:?}", columns.join("_"), backend) }, {
860 assert_snapshot!(sql);
861 });
862 }
863
864 #[rstest]
865 #[case::remove_index_with_custom_name_postgres(
866 DatabaseBackend::Postgres,
867 "hello",
868 vec!["email", "password"]
869 )]
870 #[case::remove_index_with_custom_name_mysql(
871 DatabaseBackend::MySql,
872 "hello",
873 vec!["email", "password"]
874 )]
875 #[case::remove_index_with_custom_name_sqlite(
876 DatabaseBackend::Sqlite,
877 "hello",
878 vec!["email", "password"]
879 )]
880 fn test_remove_index_with_custom_name(
881 #[case] backend: DatabaseBackend,
882 #[case] index_name: &str,
883 #[case] columns: Vec<&str>,
884 ) {
885 let action = MigrationAction::RemoveConstraint {
887 table: "user".into(),
888 constraint: TableConstraint::Index {
889 name: Some(index_name.into()),
890 columns: columns.iter().map(|s| s.to_string()).collect(),
891 },
892 };
893 let result = build_action_queries(&backend, &action, &[]).unwrap();
894 let sql = result[0].build(backend);
895
896 let expected_name = format!("ix_user__{}", index_name);
898 assert!(
899 sql.contains(&expected_name),
900 "Expected index name '{}' in SQL: {}",
901 expected_name,
902 sql
903 );
904
905 with_settings!({ snapshot_suffix => format!("remove_index_custom_{}_{:?}", index_name, backend) }, {
906 assert_snapshot!(sql);
907 });
908 }
909
910 #[rstest]
911 #[case::remove_unnamed_index_single_column_postgres(
912 DatabaseBackend::Postgres,
913 vec!["email"]
914 )]
915 #[case::remove_unnamed_index_single_column_mysql(
916 DatabaseBackend::MySql,
917 vec!["email"]
918 )]
919 #[case::remove_unnamed_index_single_column_sqlite(
920 DatabaseBackend::Sqlite,
921 vec!["email"]
922 )]
923 #[case::remove_unnamed_index_multiple_columns_postgres(
924 DatabaseBackend::Postgres,
925 vec!["email", "password"]
926 )]
927 #[case::remove_unnamed_index_multiple_columns_mysql(
928 DatabaseBackend::MySql,
929 vec!["email", "password"]
930 )]
931 #[case::remove_unnamed_index_multiple_columns_sqlite(
932 DatabaseBackend::Sqlite,
933 vec!["email", "password"]
934 )]
935 fn test_remove_unnamed_index(#[case] backend: DatabaseBackend, #[case] columns: Vec<&str>) {
936 let action = MigrationAction::RemoveConstraint {
938 table: "user".into(),
939 constraint: TableConstraint::Index {
940 name: None,
941 columns: columns.iter().map(|s| s.to_string()).collect(),
942 },
943 };
944 let result = build_action_queries(&backend, &action, &[]).unwrap();
945 let sql = result[0].build(backend);
946
947 let expected_name = format!("ix_user__{}", columns.join("_"));
949 assert!(
950 sql.contains(&expected_name),
951 "Expected index name '{}' in SQL: {}",
952 expected_name,
953 sql
954 );
955
956 with_settings!({ snapshot_suffix => format!("remove_unnamed_index_{}_{:?}", columns.join("_"), backend) }, {
957 assert_snapshot!(sql);
958 });
959 }
960
961 #[rstest]
963 #[case::add_unique_with_custom_name_postgres(
964 DatabaseBackend::Postgres,
965 "email_unique",
966 vec!["email"]
967 )]
968 #[case::add_unique_with_custom_name_mysql(
969 DatabaseBackend::MySql,
970 "email_unique",
971 vec!["email"]
972 )]
973 #[case::add_unique_with_custom_name_sqlite(
974 DatabaseBackend::Sqlite,
975 "email_unique",
976 vec!["email"]
977 )]
978 fn test_add_unique_with_custom_name(
979 #[case] backend: DatabaseBackend,
980 #[case] constraint_name: &str,
981 #[case] columns: Vec<&str>,
982 ) {
983 let action = MigrationAction::AddConstraint {
985 table: "user".into(),
986 constraint: TableConstraint::Unique {
987 name: Some(constraint_name.into()),
988 columns: columns.iter().map(|s| s.to_string()).collect(),
989 },
990 };
991
992 let current_schema = vec![TableDef {
993 name: "user".into(),
994 description: None,
995 columns: vec![ColumnDef {
996 name: "email".into(),
997 r#type: ColumnType::Simple(SimpleColumnType::Text),
998 nullable: true,
999 default: None,
1000 comment: None,
1001 primary_key: None,
1002 unique: None,
1003 index: None,
1004 foreign_key: None,
1005 }],
1006 constraints: vec![],
1007 }];
1008
1009 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
1010 let sql = result
1011 .iter()
1012 .map(|q| q.build(backend))
1013 .collect::<Vec<String>>()
1014 .join("\n");
1015
1016 let expected_name = format!("uq_user__{}", constraint_name);
1018 assert!(
1019 sql.contains(&expected_name),
1020 "Expected unique constraint name '{}' in SQL: {}",
1021 expected_name,
1022 sql
1023 );
1024
1025 with_settings!({ snapshot_suffix => format!("add_unique_custom_{}_{:?}", constraint_name, backend) }, {
1026 assert_snapshot!(sql);
1027 });
1028 }
1029
1030 #[rstest]
1031 #[case::add_unnamed_unique_single_column_postgres(
1032 DatabaseBackend::Postgres,
1033 vec!["email"]
1034 )]
1035 #[case::add_unnamed_unique_single_column_mysql(
1036 DatabaseBackend::MySql,
1037 vec!["email"]
1038 )]
1039 #[case::add_unnamed_unique_single_column_sqlite(
1040 DatabaseBackend::Sqlite,
1041 vec!["email"]
1042 )]
1043 #[case::add_unnamed_unique_multiple_columns_postgres(
1044 DatabaseBackend::Postgres,
1045 vec!["email", "username"]
1046 )]
1047 #[case::add_unnamed_unique_multiple_columns_mysql(
1048 DatabaseBackend::MySql,
1049 vec!["email", "username"]
1050 )]
1051 #[case::add_unnamed_unique_multiple_columns_sqlite(
1052 DatabaseBackend::Sqlite,
1053 vec!["email", "username"]
1054 )]
1055 fn test_add_unnamed_unique(#[case] backend: DatabaseBackend, #[case] columns: Vec<&str>) {
1056 let action = MigrationAction::AddConstraint {
1058 table: "user".into(),
1059 constraint: TableConstraint::Unique {
1060 name: None,
1061 columns: columns.iter().map(|s| s.to_string()).collect(),
1062 },
1063 };
1064
1065 let schema_columns: Vec<ColumnDef> = columns
1066 .iter()
1067 .map(|col| ColumnDef {
1068 name: col.to_string(),
1069 r#type: ColumnType::Simple(SimpleColumnType::Text),
1070 nullable: true,
1071 default: None,
1072 comment: None,
1073 primary_key: None,
1074 unique: None,
1075 index: None,
1076 foreign_key: None,
1077 })
1078 .collect();
1079
1080 let current_schema = vec![TableDef {
1081 name: "user".into(),
1082 description: None,
1083 columns: schema_columns,
1084 constraints: vec![],
1085 }];
1086
1087 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
1088 let sql = result
1089 .iter()
1090 .map(|q| q.build(backend))
1091 .collect::<Vec<String>>()
1092 .join("\n");
1093
1094 let expected_name = format!("uq_user__{}", columns.join("_"));
1096 assert!(
1097 sql.contains(&expected_name),
1098 "Expected unique constraint name '{}' in SQL: {}",
1099 expected_name,
1100 sql
1101 );
1102
1103 with_settings!({ snapshot_suffix => format!("add_unnamed_unique_{}_{:?}", columns.join("_"), backend) }, {
1104 assert_snapshot!(sql);
1105 });
1106 }
1107
1108 #[rstest]
1109 #[case::remove_unique_with_custom_name_postgres(
1110 DatabaseBackend::Postgres,
1111 "email_unique",
1112 vec!["email"]
1113 )]
1114 #[case::remove_unique_with_custom_name_mysql(
1115 DatabaseBackend::MySql,
1116 "email_unique",
1117 vec!["email"]
1118 )]
1119 #[case::remove_unique_with_custom_name_sqlite(
1120 DatabaseBackend::Sqlite,
1121 "email_unique",
1122 vec!["email"]
1123 )]
1124 fn test_remove_unique_with_custom_name(
1125 #[case] backend: DatabaseBackend,
1126 #[case] constraint_name: &str,
1127 #[case] columns: Vec<&str>,
1128 ) {
1129 let constraint = TableConstraint::Unique {
1131 name: Some(constraint_name.into()),
1132 columns: columns.iter().map(|s| s.to_string()).collect(),
1133 };
1134
1135 let current_schema = vec![TableDef {
1136 name: "user".into(),
1137 description: None,
1138 columns: vec![ColumnDef {
1139 name: "email".into(),
1140 r#type: ColumnType::Simple(SimpleColumnType::Text),
1141 nullable: true,
1142 default: None,
1143 comment: None,
1144 primary_key: None,
1145 unique: None,
1146 index: None,
1147 foreign_key: None,
1148 }],
1149 constraints: vec![constraint.clone()],
1150 }];
1151
1152 let action = MigrationAction::RemoveConstraint {
1153 table: "user".into(),
1154 constraint,
1155 };
1156
1157 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
1158 let sql = result
1159 .iter()
1160 .map(|q| q.build(backend))
1161 .collect::<Vec<String>>()
1162 .join("\n");
1163
1164 if backend != DatabaseBackend::Sqlite {
1166 let expected_name = format!("uq_user__{}", constraint_name);
1167 assert!(
1168 sql.contains(&expected_name),
1169 "Expected unique constraint name '{}' in SQL: {}",
1170 expected_name,
1171 sql
1172 );
1173 }
1174
1175 with_settings!({ snapshot_suffix => format!("remove_unique_custom_{}_{:?}", constraint_name, backend) }, {
1176 assert_snapshot!(sql);
1177 });
1178 }
1179
1180 #[rstest]
1181 #[case::remove_unnamed_unique_single_column_postgres(
1182 DatabaseBackend::Postgres,
1183 vec!["email"]
1184 )]
1185 #[case::remove_unnamed_unique_single_column_mysql(
1186 DatabaseBackend::MySql,
1187 vec!["email"]
1188 )]
1189 #[case::remove_unnamed_unique_single_column_sqlite(
1190 DatabaseBackend::Sqlite,
1191 vec!["email"]
1192 )]
1193 #[case::remove_unnamed_unique_multiple_columns_postgres(
1194 DatabaseBackend::Postgres,
1195 vec!["email", "username"]
1196 )]
1197 #[case::remove_unnamed_unique_multiple_columns_mysql(
1198 DatabaseBackend::MySql,
1199 vec!["email", "username"]
1200 )]
1201 #[case::remove_unnamed_unique_multiple_columns_sqlite(
1202 DatabaseBackend::Sqlite,
1203 vec!["email", "username"]
1204 )]
1205 fn test_remove_unnamed_unique(#[case] backend: DatabaseBackend, #[case] columns: Vec<&str>) {
1206 let constraint = TableConstraint::Unique {
1208 name: None,
1209 columns: columns.iter().map(|s| s.to_string()).collect(),
1210 };
1211
1212 let schema_columns: Vec<ColumnDef> = columns
1213 .iter()
1214 .map(|col| ColumnDef {
1215 name: col.to_string(),
1216 r#type: ColumnType::Simple(SimpleColumnType::Text),
1217 nullable: true,
1218 default: None,
1219 comment: None,
1220 primary_key: None,
1221 unique: None,
1222 index: None,
1223 foreign_key: None,
1224 })
1225 .collect();
1226
1227 let current_schema = vec![TableDef {
1228 name: "user".into(),
1229 description: None,
1230 columns: schema_columns,
1231 constraints: vec![constraint.clone()],
1232 }];
1233
1234 let action = MigrationAction::RemoveConstraint {
1235 table: "user".into(),
1236 constraint,
1237 };
1238
1239 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
1240 let sql = result
1241 .iter()
1242 .map(|q| q.build(backend))
1243 .collect::<Vec<String>>()
1244 .join("\n");
1245
1246 if backend != DatabaseBackend::Sqlite {
1248 let expected_name = format!("uq_user__{}", columns.join("_"));
1249 assert!(
1250 sql.contains(&expected_name),
1251 "Expected unique constraint name '{}' in SQL: {}",
1252 expected_name,
1253 sql
1254 );
1255 }
1256
1257 with_settings!({ snapshot_suffix => format!("remove_unnamed_unique_{}_{:?}", columns.join("_"), backend) }, {
1258 assert_snapshot!(sql);
1259 });
1260 }
1261
1262 #[rstest]
1264 #[case::postgres_modify_nullable(DatabaseBackend::Postgres)]
1265 #[case::mysql_modify_nullable(DatabaseBackend::MySql)]
1266 #[case::sqlite_modify_nullable(DatabaseBackend::Sqlite)]
1267 fn test_build_action_queries_modify_column_nullable(#[case] backend: DatabaseBackend) {
1268 let action = MigrationAction::ModifyColumnNullable {
1269 table: "users".into(),
1270 column: "email".into(),
1271 nullable: false,
1272 fill_with: Some("'unknown'".into()),
1273 delete_null_rows: None,
1274 };
1275 let current_schema = vec![TableDef {
1276 name: "users".into(),
1277 description: None,
1278 columns: vec![ColumnDef {
1279 name: "email".into(),
1280 r#type: ColumnType::Simple(SimpleColumnType::Text),
1281 nullable: true,
1282 default: None,
1283 comment: None,
1284 primary_key: None,
1285 unique: None,
1286 index: None,
1287 foreign_key: None,
1288 }],
1289 constraints: vec![],
1290 }];
1291 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
1292 assert!(!result.is_empty());
1293 let sql = result
1294 .iter()
1295 .map(|q| q.build(backend))
1296 .collect::<Vec<String>>()
1297 .join("\n");
1298
1299 assert!(sql.contains("UPDATE"));
1301 assert!(sql.contains("unknown"));
1302
1303 let suffix = format!(
1304 "{}_modify_nullable",
1305 match backend {
1306 DatabaseBackend::Postgres => "postgres",
1307 DatabaseBackend::MySql => "mysql",
1308 DatabaseBackend::Sqlite => "sqlite",
1309 }
1310 );
1311
1312 with_settings!({ snapshot_suffix => suffix }, {
1313 assert_snapshot!(sql);
1314 });
1315 }
1316
1317 #[rstest]
1319 #[case::postgres_modify_default(DatabaseBackend::Postgres)]
1320 #[case::mysql_modify_default(DatabaseBackend::MySql)]
1321 #[case::sqlite_modify_default(DatabaseBackend::Sqlite)]
1322 fn test_build_action_queries_modify_column_default(#[case] backend: DatabaseBackend) {
1323 let action = MigrationAction::ModifyColumnDefault {
1324 table: "users".into(),
1325 column: "status".into(),
1326 new_default: Some("'active'".into()),
1327 };
1328 let current_schema = vec![TableDef {
1329 name: "users".into(),
1330 description: None,
1331 columns: vec![ColumnDef {
1332 name: "status".into(),
1333 r#type: ColumnType::Simple(SimpleColumnType::Text),
1334 nullable: true,
1335 default: None,
1336 comment: None,
1337 primary_key: None,
1338 unique: None,
1339 index: None,
1340 foreign_key: None,
1341 }],
1342 constraints: vec![],
1343 }];
1344 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
1345 assert!(!result.is_empty());
1346 let sql = result
1347 .iter()
1348 .map(|q| q.build(backend))
1349 .collect::<Vec<String>>()
1350 .join("\n");
1351
1352 assert!(sql.contains("DEFAULT") || sql.contains("active"));
1354
1355 let suffix = format!(
1356 "{}_modify_default",
1357 match backend {
1358 DatabaseBackend::Postgres => "postgres",
1359 DatabaseBackend::MySql => "mysql",
1360 DatabaseBackend::Sqlite => "sqlite",
1361 }
1362 );
1363
1364 with_settings!({ snapshot_suffix => suffix }, {
1365 assert_snapshot!(sql);
1366 });
1367 }
1368
1369 #[rstest]
1371 #[case::postgres_modify_comment(DatabaseBackend::Postgres)]
1372 #[case::mysql_modify_comment(DatabaseBackend::MySql)]
1373 #[case::sqlite_modify_comment(DatabaseBackend::Sqlite)]
1374 fn test_build_action_queries_modify_column_comment(#[case] backend: DatabaseBackend) {
1375 let action = MigrationAction::ModifyColumnComment {
1376 table: "users".into(),
1377 column: "email".into(),
1378 new_comment: Some("User email address".into()),
1379 };
1380 let current_schema = vec![TableDef {
1381 name: "users".into(),
1382 description: None,
1383 columns: vec![ColumnDef {
1384 name: "email".into(),
1385 r#type: ColumnType::Simple(SimpleColumnType::Text),
1386 nullable: true,
1387 default: None,
1388 comment: None,
1389 primary_key: None,
1390 unique: None,
1391 index: None,
1392 foreign_key: None,
1393 }],
1394 constraints: vec![],
1395 }];
1396 let result = build_action_queries(&backend, &action, ¤t_schema).unwrap();
1397 let sql = result
1398 .iter()
1399 .map(|q| q.build(backend))
1400 .collect::<Vec<String>>()
1401 .join("\n");
1402
1403 if backend != DatabaseBackend::Sqlite {
1405 assert!(sql.contains("COMMENT") || sql.contains("User email address"));
1406 }
1407
1408 let suffix = format!(
1409 "{}_modify_comment",
1410 match backend {
1411 DatabaseBackend::Postgres => "postgres",
1412 DatabaseBackend::MySql => "mysql",
1413 DatabaseBackend::Sqlite => "sqlite",
1414 }
1415 );
1416
1417 with_settings!({ snapshot_suffix => suffix }, {
1418 assert_snapshot!(sql);
1419 });
1420 }
1421
1422 #[rstest]
1423 #[case::create_table_func_default_postgres(DatabaseBackend::Postgres)]
1424 #[case::create_table_func_default_mysql(DatabaseBackend::MySql)]
1425 #[case::create_table_func_default_sqlite(DatabaseBackend::Sqlite)]
1426 fn test_create_table_with_function_default(#[case] backend: DatabaseBackend) {
1427 let action = MigrationAction::CreateTable {
1430 table: "users".into(),
1431 columns: vec![
1432 ColumnDef {
1433 name: "id".into(),
1434 r#type: ColumnType::Simple(SimpleColumnType::Uuid),
1435 nullable: false,
1436 default: Some("gen_random_uuid()".into()),
1437 comment: None,
1438 primary_key: None,
1439 unique: None,
1440 index: None,
1441 foreign_key: None,
1442 },
1443 ColumnDef {
1444 name: "created_at".into(),
1445 r#type: ColumnType::Simple(SimpleColumnType::Timestamptz),
1446 nullable: false,
1447 default: Some("now()".into()),
1448 comment: None,
1449 primary_key: None,
1450 unique: None,
1451 index: None,
1452 foreign_key: None,
1453 },
1454 ],
1455 constraints: vec![],
1456 };
1457 let result = build_action_queries(&backend, &action, &[]).unwrap();
1458 let sql = result
1459 .iter()
1460 .map(|q| q.build(backend))
1461 .collect::<Vec<_>>()
1462 .join(";\n");
1463
1464 with_settings!({ snapshot_suffix => format!("create_table_func_default_{:?}", backend) }, {
1465 assert_snapshot!(sql);
1466 });
1467 }
1468
1469 #[rstest]
1470 #[case::delete_enum_column_postgres(DatabaseBackend::Postgres)]
1471 #[case::delete_enum_column_mysql(DatabaseBackend::MySql)]
1472 #[case::delete_enum_column_sqlite(DatabaseBackend::Sqlite)]
1473 fn test_delete_column_with_enum_type(#[case] backend: DatabaseBackend) {
1474 let action = MigrationAction::DeleteColumn {
1477 table: "orders".into(),
1478 column: "status".into(),
1479 };
1480 let schema = vec![TableDef {
1481 name: "orders".into(),
1482 description: None,
1483 columns: vec![
1484 col("id", ColumnType::Simple(SimpleColumnType::Integer)),
1485 ColumnDef {
1486 name: "status".into(),
1487 r#type: ColumnType::Complex(vespertide_core::ComplexColumnType::Enum {
1488 name: "order_status".into(),
1489 values: vespertide_core::EnumValues::String(vec![
1490 "pending".into(),
1491 "shipped".into(),
1492 ]),
1493 }),
1494 nullable: false,
1495 default: None,
1496 comment: None,
1497 primary_key: None,
1498 unique: None,
1499 index: None,
1500 foreign_key: None,
1501 },
1502 ],
1503 constraints: vec![],
1504 }];
1505 let result = build_action_queries(&backend, &action, &schema).unwrap();
1506 let sql = result
1507 .iter()
1508 .map(|q| q.build(backend))
1509 .collect::<Vec<_>>()
1510 .join(";\n");
1511
1512 with_settings!({ snapshot_suffix => format!("delete_enum_column_{:?}", backend) }, {
1513 assert_snapshot!(sql);
1514 });
1515 }
1516}