@@ -1,45 +1,61 @@
1+use reshape::migrations::{
2+ AddIndex, AlterColumn, ColumnBuilder, ColumnChanges, CreateTableBuilder, Index, Migration,
5fn alter_column_data() {
8fn alter_column_data() {
6− let mut test = Test::new("Alter column");
9+ let (mut reshape, mut old_db, mut new_db) = common::setup();
8− test.first_migration(
11+ let create_users_table = Migration::new("create_user_table", None).with_action(
9− r#"
12+ CreateTableBuilder::default()
10− name = "create_user_table"
13− type = "create_table"
14− name = "users"
13+ .name("users")
15− primary_key = ["id"]
14+ .primary_key(vec!["id".to_string()])
16+ ColumnBuilder::default()
18+ .data_type("INTEGER")
21+ ColumnBuilder::default()
30+ let uppercase_name = Migration::new("uppercase_name", None).with_action(AlterColumn {
31+ table: "users".to_string(),
32+ column: "name".to_string(),
33+ up: Some("UPPER(name)".to_string()),
34+ down: Some("LOWER(name)".to_string()),
35+ changes: ColumnChanges {
17− [[actions.columns]]
43+ let first_migrations = vec![create_users_table.clone()];
18− name = "id"
44+ let second_migrations = vec![create_users_table.clone(), uppercase_name.clone()];
21− [[actions.columns]]
46+ // Run first migration, should automatically finish
22− name = "name"
47+ reshape.migrate(first_migrations.clone()).unwrap();
27− test.second_migration(
49+ // Update search paths
29− name = "uppercase_name"
51+ .simple_query(&reshape::schema_query_for_migration(
30−
52+ &first_migrations.last().unwrap().name,
32− type = "alter_column"
54+ .unwrap();
40− test.after_first(|db| {
41− // Insert some test users
56+ // Insert some test users
42− db.simple_query(
58+ .simple_query(
44 INSERT INTO users (id, name) VALUES
60 INSERT INTO users (id, name) VALUES
45 (1, 'john Doe'),
61 (1, 'john Doe'),
@@ -47,81 +63,98 @@ fn alter_column_data() {
49 .unwrap();
65 .unwrap();
52− test.intermediate(|old_db, new_db| {
67+ // Run second migration
68+ reshape.migrate(second_migrations.clone()).unwrap();
70+ .simple_query(&reshape::schema_query_for_migration(
71+ &second_migrations.last().unwrap().name,
53− // Check that the existing users has the altered data
75+ // Check that the existing users has the altered data
54− let expected = vec!["JOHN DOE", "JANE DOE"];
76+ let expected = vec!["JOHN DOE", "JANE DOE"];
55− assert!(new_db
77+ assert!(new_db
56− .query("SELECT name FROM users ORDER BY id", &[],)
78+ .query("SELECT name FROM users ORDER BY id", &[],)
57− .unwrap()
79+ .unwrap()
59− .map(|row| row.get::<_, String>("name"))
81+ .map(|row| row.get::<_, String>("name"))
60− .eq(expected));
82+ .eq(expected));
62− // Insert data using old schema and make sure the new schema gets correct values
84+ // Insert data using old schema and make sure the new schema gets correct values
64− .simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
86+ .simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
65− .unwrap();
87+ .unwrap();
66− let result = new_db
88+ let result = new_db
67− .query_one("SELECT name from users WHERE id = 3", &[])
89+ .query_one("SELECT name from users WHERE id = 3", &[])
68− .unwrap();
90+ .unwrap();
69− assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
91+ assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
71− // Insert data using new schema and make sure the old schema gets correct values
93+ // Insert data using new schema and make sure the old schema gets correct values
73− .simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
95+ .simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
74− .unwrap();
96+ .unwrap();
75− let result = old_db
97+ let result = old_db
76− .query_one("SELECT name from users WHERE id = 4", &[])
98+ .query_one("SELECT name from users WHERE id = 4", &[])
77− .unwrap();
99+ .unwrap();
78− assert_eq!("test testsson", result.get::<_, &str>("name"));
100+ assert_eq!("test testsson", result.get::<_, &str>("name"));
81− test.run();
102+ reshape.complete().unwrap();
103+ common::assert_cleaned_up(&mut new_db);
85fn alter_column_set_not_null() {
107fn alter_column_set_not_null() {
86− let mut test = Test::new("Set column not null");
108+ let (mut reshape, mut old_db, mut new_db) = common::setup();
88− test.first_migration(
110+ let create_users_table = Migration::new("create_user_table", None).with_action(
89− r#"
111+ CreateTableBuilder::default()
90− name = "create_user_table"
93− type = "create_table"
94− name = "users"
112+ .name("users")
95− primary_key = ["id"]
113+ .primary_key(vec!["id".to_string()])
97− [[actions.columns]]
114+ .columns(vec![
115+ ColumnBuilder::default()
98− name = "id"
116+ .name("id")
99− type = "INTEGER"
117+ .data_type("INTEGER")
101− [[actions.columns]]
119+ .unwrap(),
120+ ColumnBuilder::default()
102− name = "name"
121+ .name("name")
103− type = "TEXT"
122+ .data_type("TEXT")
129+ let set_name_not_null = Migration::new("set_name_not_null", None).with_action(AlterColumn {
130+ table: "users".to_string(),
131+ column: "name".to_string(),
132+ up: Some("COALESCE(name, 'TEST_DEFAULT_VALUE')".to_string()),
133+ down: Some("name".to_string()),
134+ changes: ColumnChanges {
136+ nullable: Some(false),
107− test.second_migration(
142+ let first_migrations = vec![create_users_table.clone()];
108− r#"
143+ let second_migrations = vec![create_users_table.clone(), set_name_not_null.clone()];
109− name = "set_name_not_null"
111− [[actions]]
145+ // Run first migration, should automatically finish
112− type = "alter_column"
146+ reshape.migrate(first_migrations.clone()).unwrap();
115− up = "COALESCE(name, 'TEST_DEFAULT_VALUE')"
117− [actions.changes]
148+ // Update search paths
118− nullable = false
149+ old_db
119− "#,
150+ .simple_query(&reshape::schema_query_for_migration(
120− );
151+ &first_migrations.last().unwrap().name,
122− test.after_first(|db| {
123− // Insert some test users
155+ // Insert some test users
124− db.simple_query(
157+ .simple_query(
126 INSERT INTO users (id, name) VALUES
159 INSERT INTO users (id, name) VALUES
127 (1, 'John Doe'),
160 (1, 'John Doe'),
@@ -129,180 +162,99 @@ fn alter_column_set_not_null() {
131 .unwrap();
164 .unwrap();
134− test.intermediate(|old_db, new_db| {
135− // Check that existing users got the correct values
136− let expected = vec!["John Doe", "TEST_DEFAULT_VALUE"];
138− .query("SELECT name FROM users ORDER BY id", &[],)
141− .map(|row| row.get::<_, String>("name"))
144− // Insert data using old schema and make sure the new schema gets correct values
146− .simple_query("INSERT INTO users (id, name) VALUES (3, NULL)")
149− .query_one("SELECT name from users WHERE id = 3", &[])
151− assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
153− // Insert data using new schema and make sure the old schema gets correct values
155− .simple_query("INSERT INTO users (id, name) VALUES (4, 'Jane Doe')")
158− .query_one("SELECT name from users WHERE id = 4", &[])
160− assert_eq!("Jane Doe", result.get::<_, &str>("name"));
162− // Ensure NULL can't be inserted using the new schema
163− let result = new_db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
164− assert!(result.is_err(), "expected insert to fail");
167− test.after_completion(|db| {
168− // Ensure NULL can't be inserted
169− let result = db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
170− assert!(result.is_err(), "expected insert to fail");
173− test.after_abort(|db| {
174− // Ensure NULL can be inserted
175− let result = db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
176− assert!(result.is_ok(), "expected insert to succeed");
179− test.run();
166+ // Run second migration
180−}
167+ reshape.migrate(second_migrations.clone()).unwrap();
183−fn alter_column_set_nullable() {
184− let mut test = Test::new("Set column nullable");
186− test.first_migration(
188− name = "create_user_table"
191− type = "create_table"
193− primary_key = ["id"]
206− test.second_migration(
208− name = "set_name_nullable"
211− type = "alter_column"
214− down = "COALESCE(name, 'TEST_DEFAULT_VALUE')"
221− test.after_first(|db| {
222− // Insert a test user
223− db.simple_query(
169+ .simple_query(&reshape::schema_query_for_migration(
224− "
170+ &second_migrations.last().unwrap().name,
225− INSERT INTO users (id, name) VALUES
229 .unwrap();
172 .unwrap();
232− test.intermediate(|old_db, new_db| {
233− // Insert data using new schema and make sure the old schema gets correct values
235− .simple_query("INSERT INTO users (id, name) VALUES (2, NULL)")
238− .query_one("SELECT name from users WHERE id = 2", &[])
240− assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
242− // Ensure NULL can't be inserted using the old schema
243− let result = old_db.simple_query("INSERT INTO users (id, name) VALUES (3, NULL)");
244− assert!(result.is_err(), "expected insert to fail");
246− // Ensure NULL can be inserted using the new schema
247− let result = new_db.simple_query("INSERT INTO users (id, name) VALUES (4, NULL)");
248− assert!(result.is_ok(), "expected insert to succeed");
251− test.after_completion(|db| {
174+ // Check that existing users got the correct values
252− // Ensure NULL can be inserted
175+ let expected = vec!["John Doe", "TEST_DEFAULT_VALUE"];
177+ .query("SELECT name FROM users ORDER BY id", &[],)
180+ .map(|row| row.get::<_, String>("name"))
183+ // Insert data using old schema and make sure the new schema gets correct values
253− let result = db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
185+ .simple_query("INSERT INTO users (id, name) VALUES (3, NULL)")
254− assert!(result.is_ok(), "expected insert to succeed");
186+ .unwrap();
255− });
187+ let result = new_db
188+ .query_one("SELECT name from users WHERE id = 3", &[])
190+ assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
257− test.after_abort(|db| {
192+ // Insert data using new schema and make sure the old schema gets correct values
258− // Ensure NULL can't be inserted
193+ new_db
259− let result = db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
194+ .simple_query("INSERT INTO users (id, name) VALUES (4, 'Jane Doe')")
260− assert!(result.is_err(), "expected insert to fail");
195+ .unwrap();
261− });
196+ let result = old_db
197+ .query_one("SELECT name from users WHERE id = 4", &[])
199+ assert_eq!("Jane Doe", result.get::<_, &str>("name"));
263− test.run();
201+ reshape.complete().unwrap();
202+ common::assert_cleaned_up(&mut new_db);
267fn alter_column_rename() {
206fn alter_column_rename() {
268− let mut test = Test::new("Rename column");
207+ let (mut reshape, mut old_db, mut new_db) = common::setup();
270− test.first_migration(
209+ let create_users_table = Migration::new("create_user_table", None).with_action(
271− r#"
210+ CreateTableBuilder::default()
272− name = "create_user_table"
275− type = "create_table"
276− name = "users"
211+ .name("users")
277− primary_key = ["id"]
212+ .primary_key(vec!["id".to_string()])
279− [[actions.columns]]
213+ .columns(vec![
214+ ColumnBuilder::default()
280− name = "id"
215+ .name("id")
281− type = "INTEGER"
216+ .data_type("INTEGER")
283− [[actions.columns]]
218+ .unwrap(),
219+ ColumnBuilder::default()
284− name = "name"
220+ .name("name")
285− type = "TEXT"
221+ .data_type("TEXT")
289− test.second_migration(
225+ .build()
291− name = "set_name_not_null"
294− type = "alter_column"
228+ let rename_to_full_name =
229+ Migration::new("rename_to_full_name", None).with_action(AlterColumn {
230+ table: "users".to_string(),
231+ column: "name".to_string(),
232+ up: None, // up and down are not required when only renaming a column
234+ changes: ColumnChanges {
237+ name: Some("full_name".to_string()),
242+ let first_migrations = vec![create_users_table.clone()];
243+ let second_migrations = vec![create_users_table.clone(), rename_to_full_name.clone()];
245+ // Run first migration, should automatically finish
246+ reshape.migrate(first_migrations.clone()).unwrap();
248+ // Update search paths
250+ .simple_query(&reshape::schema_query_for_migration(
251+ &first_migrations.last().unwrap().name,
303− test.after_first(|db| {
304− // Insert some test data
255+ // Insert some test data
305− db.simple_query(
257+ .simple_query(
307 INSERT INTO users (id, name) VALUES
259 INSERT INTO users (id, name) VALUES
308 (1, 'John Doe'),
260 (1, 'John Doe'),
@@ -310,69 +262,94 @@ fn alter_column_rename() {
312 .unwrap();
264 .unwrap();
315− test.intermediate(|_, new_db| {
266+ // Run second migration
316− // Check that existing values can be queried using new column name
267+ reshape.migrate(second_migrations.clone()).unwrap();
317− let expected = vec!["John Doe", "Jane Doe"];
268+ new_db
318− assert!(new_db
269+ .simple_query(&reshape::schema_query_for_migration(
319− .query("SELECT full_name FROM users ORDER BY id", &[],)
270+ &second_migrations.last().unwrap().name,
320− .unwrap()
272+ .unwrap();
322− .map(|row| row.get::<_, String>("full_name"))
326− test.run();
274+ // Check that existing values can be queried using new column name
275+ let expected = vec!["John Doe", "Jane Doe"];
277+ .query("SELECT full_name FROM users ORDER BY id", &[],)
280+ .map(|row| row.get::<_, String>("full_name"))
283+ reshape.complete().unwrap();
284+ common::assert_cleaned_up(&mut new_db);
330fn alter_column_multiple() {
288fn alter_column_multiple() {
331− let mut test = Test::new("Alter column value multiple times");
289+ let (mut reshape, mut old_db, mut new_db) = common::setup();
333− test.first_migration(
291+ let create_users_table = Migration::new("create_user_table", None).with_action(
334− r#"
292+ CreateTableBuilder::default()
335− name = "create_user_table"
338− type = "create_table"
339− name = "users"
293+ .name("users")
340− primary_key = ["id"]
294+ .primary_key(vec!["id".to_string()])
342− [[actions.columns]]
295+ .columns(vec![
296+ ColumnBuilder::default()
343− name = "id"
297+ .name("id")
344− type = "INTEGER"
298+ .data_type("INTEGER")
346− [[actions.columns]]
300+ .unwrap(),
301+ ColumnBuilder::default()
347− name = "counter"
302+ .name("counter")
348− type = "INTEGER"
303+ .data_type("INTEGER")
349− nullable = false
304+ .nullable(false)
353− test.second_migration(
308+ .build()
355− name = "increment_counter_twice"
358− type = "alter_column"
362− down = "counter - 1"
365− type = "alter_column"
369− down = "counter - 1"
311+ let increment_counter_twice = Migration::new("increment_counter_twice", None)
312+ .with_action(AlterColumn {
313+ table: "users".to_string(),
314+ column: "counter".to_string(),
315+ up: Some("counter + 1".to_string()),
316+ down: Some("counter - 1".to_string()),
317+ changes: ColumnChanges {
324+ .with_action(AlterColumn {
325+ table: "users".to_string(),
326+ column: "counter".to_string(),
327+ up: Some("counter + 1".to_string()),
328+ down: Some("counter - 1".to_string()),
329+ changes: ColumnChanges {
337+ let first_migrations = vec![create_users_table.clone()];
338+ let second_migrations = vec![create_users_table.clone(), increment_counter_twice.clone()];
340+ // Run first migration, should automatically finish
341+ reshape.migrate(first_migrations.clone()).unwrap();
343+ // Update search paths
345+ .simple_query(&reshape::schema_query_for_migration(
346+ &first_migrations.last().unwrap().name,
373− test.after_first(|db| {
374− // Insert some test data
350+ // Insert some test data
375− db.simple_query(
352+ .simple_query(
377 INSERT INTO users (id, counter) VALUES
354 INSERT INTO users (id, counter) VALUES
@@ -380,355 +357,239 @@ fn alter_column_multiple() {
382 .unwrap();
359 .unwrap();
385− test.intermediate(|old_db, new_db| {
361+ // Run second migration
386− // Check that the existing data has been updated
362+ reshape.migrate(second_migrations.clone()).unwrap();
387− let expected = vec![2, 102];
388− let results: Vec<i32> = new_db
389− .query("SELECT counter FROM users ORDER BY id", &[])
392− .map(|row| row.get::<_, i32>("counter"))
394− assert_eq!(expected, results);
396− // Update data using old schema and make sure it was updated for the new schema
398− .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
400− let result: i32 = new_db
363+ new_db
401− .query("SELECT counter FROM users WHERE id = 1", &[])
364+ .simple_query(&reshape::schema_query_for_migration(
402− .unwrap()
365+ &second_migrations.last().unwrap().name,
404− .map(|row| row.get("counter"))
407− assert_eq!(52, result);
409− // Update data using new schema and make sure it was updated for the old schema
411− .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
413− let result: i32 = old_db
414− .query("SELECT counter FROM users WHERE id = 1", &[])
417− .map(|row| row.get("counter"))
419− .unwrap();
367+ .unwrap();
420− assert_eq!(48, result);
423− test.run();
369+ // Check that the existing data has been updated
370+ let expected = vec![2, 102];
371+ let results: Vec<i32> = new_db
372+ .query("SELECT counter FROM users ORDER BY id", &[])
375+ .map(|row| row.get::<_, i32>("counter"))
377+ assert_eq!(expected, results);
379+ // Update data using old schema and make sure it was updated for the new schema
381+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
383+ let result: i32 = new_db
384+ .query("SELECT counter FROM users WHERE id = 1", &[])
387+ .map(|row| row.get("counter"))
390+ assert_eq!(52, result);
392+ // Update data using new schema and make sure it was updated for the old schema
394+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
396+ let result: i32 = old_db
397+ .query("SELECT counter FROM users WHERE id = 1", &[])
400+ .map(|row| row.get("counter"))
403+ assert_eq!(48, result);
405+ reshape.complete().unwrap();
406+ common::assert_cleaned_up(&mut new_db);
427fn alter_column_default() {
410fn alter_column_default() {
428− let mut test = Test::new("Change default value for column");
411+ let (mut reshape, mut old_db, mut new_db) = common::setup();
430− test.first_migration(
413+ let create_users_table = Migration::new("create_user_table", None).with_action(
431− r#"
414+ CreateTableBuilder::default()
432− name = "create_user_table"
435− type = "create_table"
436− name = "users"
415+ .name("users")
437− primary_key = ["id"]
416+ .primary_key(vec!["id".to_string()])
439− [[actions.columns]]
417+ .columns(vec![
418+ ColumnBuilder::default()
440− name = "id"
419+ .name("id")
441− type = "INTEGER"
420+ .data_type("INTEGER")
443− [[actions.columns]]
422+ .unwrap(),
423+ ColumnBuilder::default()
444− name = "name"
424+ .name("name")
445− type = "TEXT"
425+ .data_type("TEXT")
446− nullable = false
426+ .nullable(false)
447− default = "'DEFAULT'"
427+ .default_value("'DEFAULT'")
451− test.second_migration(
431+ .build()
453− name = "change_name_default"
456− type = "alter_column"
461− default = "'NEW DEFAULT'"
434+ let change_name_default =
435+ Migration::new("change_name_default", None).with_action(AlterColumn {
436+ table: "users".to_string(),
437+ column: "name".to_string(),
440+ changes: ColumnChanges {
444+ default: Some("'NEW DEFAULT'".to_string()),
448+ let first_migrations = vec![create_users_table.clone()];
449+ let second_migrations = vec![create_users_table.clone(), change_name_default.clone()];
451+ // Run first migration, should automatically finish
452+ reshape.migrate(first_migrations.clone()).unwrap();
454+ // Update search paths
456+ .simple_query(&reshape::schema_query_for_migration(
457+ &first_migrations.last().unwrap().name,
465− test.after_first(|db| {
466− // Insert a test user
461+ // Insert a test user
467− db.simple_query(
463+ .simple_query(
469 INSERT INTO users (id) VALUES (1)
465 INSERT INTO users (id) VALUES (1)
472 .unwrap();
468 .unwrap();
475− test.intermediate(|old_db, new_db| {
470+ // Run second migration
476− // Check that the existing users has the old default value
471+ reshape.migrate(second_migrations.clone()).unwrap();
477− let expected = vec!["DEFAULT"];
472+ new_db
478− assert!(new_db
473+ .simple_query(&reshape::schema_query_for_migration(
479− .query("SELECT name FROM users", &[],)
474+ &second_migrations.last().unwrap().name,
482− .map(|row| row.get::<_, String>("name"))
485− // Insert data using old schema and make those get the old default value
487− .simple_query("INSERT INTO users (id) VALUES (2)")
490− .query_one("SELECT name from users WHERE id = 2", &[])
492− assert_eq!("DEFAULT", result.get::<_, &str>("name"));
494− // Insert data using new schema and make sure it gets the new default value
496− .simple_query("INSERT INTO users (id) VALUES (3)")
499− .query_one("SELECT name from users WHERE id = 3", &[])
500− .unwrap();
476+ .unwrap();
501− assert_eq!("NEW DEFAULT", result.get::<_, &str>("name"));
504− test.run();
478+ // Check that the existing users has the old default value
479+ let expected = vec!["DEFAULT"];
481+ .query("SELECT name FROM users", &[],)
484+ .map(|row| row.get::<_, String>("name"))
487+ // Insert data using old schema and make those get the old default value
489+ .simple_query("INSERT INTO users (id) VALUES (2)")
492+ .query_one("SELECT name from users WHERE id = 2", &[])
494+ assert_eq!("DEFAULT", result.get::<_, &str>("name"));
496+ // Insert data using new schema and make sure it gets the new default value
498+ .simple_query("INSERT INTO users (id) VALUES (3)")
501+ .query_one("SELECT name from users WHERE id = 3", &[])
503+ assert_eq!("NEW DEFAULT", result.get::<_, &str>("name"));
505+ reshape.complete().unwrap();
506+ common::assert_cleaned_up(&mut new_db);
508fn alter_column_with_index() {
510fn alter_column_with_index() {
509− let mut test = Test::new("Alter column with index");
511+ let (mut reshape, mut db, _) = common::setup();
511− test.first_migration(
513− name = "create_user_table"
513+ let create_users_table = Migration::new("create_user_table", None)
515− [[actions]]
515+ CreateTableBuilder::default()
516− type = "create_table"
517− name = "users"
516+ .name("users")
518− primary_key = ["id"]
517+ .primary_key(vec!["id".to_string()])
520− [[actions.columns]]
518+ .columns(vec![
519+ ColumnBuilder::default()
521− name = "id"
520+ .name("id")
522− type = "INTEGER"
521+ .data_type("INTEGER")
524− [[actions.columns]]
523+ .unwrap(),
525− name = "first_name"
524+ ColumnBuilder::default()
526− type = "TEXT"
525+ .name("first_name")
529+ ColumnBuilder::default()
538+ .with_action(AddIndex {
539+ table: "users".to_string(),
541+ name: "users_name_idx".to_string(),
542+ columns: vec!["first_name".to_string(), "last_name".to_string()],
547+ let uppercase_name = Migration::new("uppercase_name", None).with_action(AlterColumn {
548+ table: "users".to_string(),
549+ column: "last_name".to_string(),
550+ up: Some("UPPER(last_name)".to_string()),
551+ down: Some("LOWER(last_name)".to_string()),
552+ changes: ColumnChanges {
528− [[actions.columns]]
560+ let first_migrations = vec![create_users_table.clone()];
529− name = "last_name"
561+ let second_migrations = vec![create_users_table.clone(), uppercase_name.clone()];
532− [[actions]]
563+ // Run first migration, should automatically finish
533− type = "add_index"
564+ reshape.migrate(first_migrations.clone()).unwrap();
536− [actions.index]
566+ // Run second migration
537− name = "users_name_idx"
567+ reshape.migrate(second_migrations.clone()).unwrap();
538− columns = ["first_name", "last_name"]
568+ db.simple_query(&reshape::schema_query_for_migration(
539− "#,
569+ &second_migrations.last().unwrap().name,
542− test.second_migration(
573+ // Complete the second migration which should replace the existing column
543− r#"
574+ // with the temporary one
544− name = "uppercase_last_name"
575+ reshape.complete().unwrap();
547− type = "alter_column"
549− column = "last_name"
550− up = "UPPER(last_name)"
551− down = "LOWER(last_name)"
555− test.after_completion(|db| {
556− // Make sure index still exists
577+ // Make sure index still exists
557− let result: i64 = db
578+ let result: i64 = db
560 SELECT COUNT(*)
581 SELECT COUNT(*)
561 FROM pg_catalog.pg_index
582 FROM pg_catalog.pg_index
562 JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
583 JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
563 WHERE pg_class.relname = 'users_name_idx'
584 WHERE pg_class.relname = 'users_name_idx'
567− .unwrap()
588+ .unwrap()
568− .first()
589+ .first()
569− .map(|row| row.get(0))
590+ .map(|row| row.get(0))
570− .unwrap();
591+ .unwrap();
571− assert_eq!(1, result, "expected index to still exist");
592+ assert_eq!(1, result, "expected index to still exist");
578−fn alter_column_with_unique_index() {
579− let mut test = Test::new("Alter column with unique index");
581− test.first_migration(
583− name = "create_user_table"
586− type = "create_table"
588− primary_key = ["id"]
609− test.second_migration(
611− name = "uppercase_name"
614− type = "alter_column"
618− down = "LOWER(name)"
622− test.after_first(|db| {
623− db.simple_query("INSERT INTO users (id, name) VALUES (1, 'Test')")
627− test.intermediate(|old_db, new_db| {
628− // Try inserting a value which duplicates the uppercase value of an existing row
629− let result = new_db.simple_query("INSERT INTO users (id, name) VALUES (2, 'TEST')");
632− "expected duplicate insert to new schema to fail"
635− // Try inserting a value which duplicates the lowercase value of an existing row
637− .simple_query("INSERT INTO users (id, name) VALUES (2, 'JOHN')")
639− let result = old_db.simple_query("INSERT INTO users (id, name) VALUES (3, 'john')");
642− "expected duplicate insert to old schema to fail"
646− test.after_completion(|db| {
647− // Make sure index still exists
648− let is_unique: bool = db
651− SELECT pg_index.indisunique
652− FROM pg_catalog.pg_index
653− JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
654− WHERE pg_class.relname = 'name_idx'
660− .map(|row| row.get("indisunique"))
662− assert!(is_unique, "expected index to still be unique");
669−fn alter_column_with_hash_index() {
670− let mut test = Test::new("Alter column with custom index type");
672− test.first_migration(
674− name = "create_user_table"
677− type = "create_table"
679− primary_key = ["id"]
700− test.second_migration(
702− name = "uppercase_name"
705− type = "alter_column"
709− down = "LOWER(name)"
713− test.after_completion(|db| {
714− // Make sure index still has type GIN
715− let index_type: String = db
719− FROM pg_catalog.pg_index
720− JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
721− JOIN pg_catalog.pg_am ON pg_class.relam = pg_am.oid
722− WHERE pg_class.relname = 'name_idx'
728− .map(|row| row.get("amname"))
730− assert_eq!("hash", index_type);
733− test.run();
594+ common::assert_cleaned_up(&mut db);