@@ -1,61 +1,45 @@
1−use reshape::migrations::{
2− AddIndex, AlterColumn, ColumnBuilder, ColumnChanges, CreateTableBuilder, Index, Migration,
8fn alter_column_data() {
5fn alter_column_data() {
9− let (mut reshape, mut old_db, mut new_db) = common::setup();
6+ let mut test = Test::new("Alter column");
11− let create_users_table = Migration::new("create_user_table", None).with_action(
12− CreateTableBuilder::default()
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 {
43− let first_migrations = vec![create_users_table.clone()];
8+ test.first_migration(
44− let second_migrations = vec![create_users_table.clone(), uppercase_name.clone()];
9+ r#"
10+ name = "create_user_table"
46− // Run first migration, should automatically finish
12+ [[actions]]
47− reshape.migrate(first_migrations.clone()).unwrap();
13+ type = "create_table"
49− // Update search paths
17+ [[actions.columns]]
50− old_db
18+ name = "id"
51− .simple_query(&reshape::schema_query_for_migration(
19+ type = "INTEGER"
52− &first_migrations.last().unwrap().name,
20+
53− ))
21+ [[actions.columns]]
54− .unwrap();
22+ name = "name"
27+ test.second_migration(
29+ name = "uppercase_name"
32+ type = "alter_column"
40+ test.after_first(|db| {
56− // Insert some test users
41+ // Insert some test users
58− .simple_query(
42+ db.simple_query(
60 INSERT INTO users (id, name) VALUES
44 INSERT INTO users (id, name) VALUES
61 (1, 'john Doe'),
45 (1, 'john Doe'),
@@ -63,98 +47,81 @@ fn alter_column_data() {
65 .unwrap();
49 .unwrap();
67− // Run second migration
52+ test.intermediate(|old_db, new_db| {
68− reshape.migrate(second_migrations.clone()).unwrap();
70− .simple_query(&reshape::schema_query_for_migration(
71− &second_migrations.last().unwrap().name,
75− // Check that the existing users has the altered data
53+ // Check that the existing users has the altered data
76− let expected = vec!["JOHN DOE", "JANE DOE"];
54+ let expected = vec!["JOHN DOE", "JANE DOE"];
77− assert!(new_db
55+ assert!(new_db
78− .query("SELECT name FROM users ORDER BY id", &[],)
56+ .query("SELECT name FROM users ORDER BY id", &[],)
79− .unwrap()
57+ .unwrap()
81− .map(|row| row.get::<_, String>("name"))
59+ .map(|row| row.get::<_, String>("name"))
82− .eq(expected));
60+ .eq(expected));
84− // Insert data using old schema and make sure the new schema gets correct values
62+ // Insert data using old schema and make sure the new schema gets correct values
86− .simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
64+ .simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
87− .unwrap();
65+ .unwrap();
88− let result = new_db
66+ let result = new_db
89− .query_one("SELECT name from users WHERE id = 3", &[])
67+ .query_one("SELECT name from users WHERE id = 3", &[])
90− .unwrap();
68+ .unwrap();
91− assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
69+ assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
93− // Insert data using new schema and make sure the old schema gets correct values
71+ // Insert data using new schema and make sure the old schema gets correct values
95− .simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
73+ .simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
96− .unwrap();
74+ .unwrap();
97− let result = old_db
75+ let result = old_db
98− .query_one("SELECT name from users WHERE id = 4", &[])
76+ .query_one("SELECT name from users WHERE id = 4", &[])
99− .unwrap();
77+ .unwrap();
100− assert_eq!("test testsson", result.get::<_, &str>("name"));
78+ assert_eq!("test testsson", result.get::<_, &str>("name"));
102− reshape.complete().unwrap();
81+ test.run();
103− common::assert_cleaned_up(&mut new_db);
107fn alter_column_set_not_null() {
85fn alter_column_set_not_null() {
108− let (mut reshape, mut old_db, mut new_db) = common::setup();
86+ let mut test = Test::new("Set column not null");
110− let create_users_table = Migration::new("create_user_table", None).with_action(
88+ test.first_migration(
111− CreateTableBuilder::default()
89+ r#"
90+ name = "create_user_table"
93+ type = "create_table"
112− .name("users")
94+ name = "users"
113− .primary_key(vec!["id".to_string()])
95+ primary_key = ["id"]
114− .columns(vec![
97+ [[actions.columns]]
115− ColumnBuilder::default()
116− .name("id")
98+ name = "id"
117− .data_type("INTEGER")
99+ type = "INTEGER"
119− .unwrap(),
101+ [[actions.columns]]
120− ColumnBuilder::default()
121− .name("name")
102+ name = "name"
122− .data_type("TEXT")
103+ 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),
142− let first_migrations = vec![create_users_table.clone()];
107+ test.second_migration(
143− let second_migrations = vec![create_users_table.clone(), set_name_not_null.clone()];
108+ r#"
109+ name = "set_name_not_null"
145− // Run first migration, should automatically finish
111+ [[actions]]
146− reshape.migrate(first_migrations.clone()).unwrap();
112+ type = "alter_column"
115+ up = "COALESCE(name, 'TEST_DEFAULT_VALUE')"
148− // Update search paths
117+ [actions.changes]
149− old_db
118+ nullable = false
150− .simple_query(&reshape::schema_query_for_migration(
119+ "#,
151− &first_migrations.last().unwrap().name,
120+ );
122+ test.after_first(|db| {
155− // Insert some test users
123+ // Insert some test users
157− .simple_query(
124+ db.simple_query(
159 INSERT INTO users (id, name) VALUES
126 INSERT INTO users (id, name) VALUES
160 (1, 'John Doe'),
127 (1, 'John Doe'),
@@ -162,99 +129,180 @@ fn alter_column_set_not_null() {
164 .unwrap();
131 .unwrap();
166− // Run second migration
134+ test.intermediate(|old_db, new_db| {
167− reshape.migrate(second_migrations.clone()).unwrap();
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)")
168− new_db
148+ let result = new_db
169− .simple_query(&reshape::schema_query_for_migration(
149+ .query_one("SELECT name from users WHERE id = 3", &[])
170− &second_migrations.last().unwrap().name,
150+ .unwrap();
171− ))
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");
174− // Check that existing users got the correct values
167+ test.after_completion(|db| {
175− let expected = vec!["John Doe", "TEST_DEFAULT_VALUE"];
168+ // Ensure NULL can't be inserted
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
185− .simple_query("INSERT INTO users (id, name) VALUES (3, NULL)")
169+ let result = db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
186− .unwrap();
170+ assert!(result.is_err(), "expected insert to fail");
187− let result = new_db
171+ });
188− .query_one("SELECT name from users WHERE id = 3", &[])
190− assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
192− // Insert data using new schema and make sure the old schema gets correct values
173+ test.after_abort(|db| {
193− new_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");
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
194− .simple_query("INSERT INTO users (id, name) VALUES (4, 'Jane Doe')")
225+ INSERT INTO users (id, name) VALUES
195− .unwrap();
226+ (1, 'John Doe')
196− let result = old_db
227+ ",
197− .query_one("SELECT name from users WHERE id = 4", &[])
228+ )
198 .unwrap();
229 .unwrap();
199− assert_eq!("Jane Doe", result.get::<_, &str>("name"));
230+ });
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)")
201− reshape.complete().unwrap();
236+ .unwrap();
202− common::assert_cleaned_up(&mut new_db);
237+ let result = old_db
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| {
252+ // Ensure NULL can be inserted
253+ let result = db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
254+ assert!(result.is_ok(), "expected insert to succeed");
257+ test.after_abort(|db| {
258+ // Ensure NULL can't be inserted
259+ let result = db.simple_query("INSERT INTO users (id, name) VALUES (5, NULL)");
260+ assert!(result.is_err(), "expected insert to fail");
206fn alter_column_rename() {
267fn alter_column_rename() {
207− let (mut reshape, mut old_db, mut new_db) = common::setup();
268+ let mut test = Test::new("Rename column");
209− let create_users_table = Migration::new("create_user_table", None).with_action(
270+ test.first_migration(
210− CreateTableBuilder::default()
271+ r#"
272+ name = "create_user_table"
275+ type = "create_table"
211− .name("users")
276+ name = "users"
212− .primary_key(vec!["id".to_string()])
277+ primary_key = ["id"]
213− .columns(vec![
279+ [[actions.columns]]
214− ColumnBuilder::default()
215− .name("id")
280+ name = "id"
216− .data_type("INTEGER")
281+ type = "INTEGER"
218− .unwrap(),
283+ [[actions.columns]]
219− ColumnBuilder::default()
220− .name("name")
284+ name = "name"
221− .data_type("TEXT")
285+ type = "TEXT"
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,
289+ test.second_migration(
291+ name = "set_name_not_null"
294+ type = "alter_column"
303+ test.after_first(|db| {
255− // Insert some test data
304+ // Insert some test data
257− .simple_query(
305+ db.simple_query(
259 INSERT INTO users (id, name) VALUES
307 INSERT INTO users (id, name) VALUES
260 (1, 'John Doe'),
308 (1, 'John Doe'),
@@ -262,94 +310,69 @@ fn alter_column_rename() {
264 .unwrap();
312 .unwrap();
266− // Run second migration
315+ test.intermediate(|_, new_db| {
267− reshape.migrate(second_migrations.clone()).unwrap();
316+ // Check that existing values can be queried using new column name
268− new_db
317+ let expected = vec!["John Doe", "Jane Doe"];
269− .simple_query(&reshape::schema_query_for_migration(
318+ assert!(new_db
270− &second_migrations.last().unwrap().name,
319+ .query("SELECT full_name FROM users ORDER BY id", &[],)
272− .unwrap();
321+ .iter()
322+ .map(|row| row.get::<_, String>("full_name"))
274− // Check that existing values can be queried using new column name
326+ test.run();
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);
288fn alter_column_multiple() {
330fn alter_column_multiple() {
289− let (mut reshape, mut old_db, mut new_db) = common::setup();
331+ let mut test = Test::new("Alter column value multiple times");
291− let create_users_table = Migration::new("create_user_table", None).with_action(
333+ test.first_migration(
292− CreateTableBuilder::default()
334+ r#"
335+ name = "create_user_table"
338+ type = "create_table"
293− .name("users")
339+ name = "users"
294− .primary_key(vec!["id".to_string()])
340+ primary_key = ["id"]
295− .columns(vec![
342+ [[actions.columns]]
296− ColumnBuilder::default()
297− .name("id")
343+ name = "id"
298− .data_type("INTEGER")
344+ type = "INTEGER"
300− .unwrap(),
346+ [[actions.columns]]
301− ColumnBuilder::default()
302− .name("counter")
347+ name = "counter"
303− .data_type("INTEGER")
348+ type = "INTEGER"
304− .nullable(false)
349+ nullable = false
308− .build()
353+ test.second_migration(
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| {
350− // Insert some test data
374+ // Insert some test data
352− .simple_query(
375+ db.simple_query(
354 INSERT INTO users (id, counter) VALUES
377 INSERT INTO users (id, counter) VALUES
@@ -357,239 +380,355 @@ fn alter_column_multiple() {
359 .unwrap();
382 .unwrap();
361− // Run second migration
385+ test.intermediate(|old_db, new_db| {
362− reshape.migrate(second_migrations.clone()).unwrap();
364− .simple_query(&reshape::schema_query_for_migration(
365− &second_migrations.last().unwrap().name,
369− // Check that the existing data has been updated
386+ // Check that the existing data has been updated
370− let expected = vec![2, 102];
387+ let expected = vec![2, 102];
371− let results: Vec<i32> = new_db
388+ let results: Vec<i32> = new_db
372− .query("SELECT counter FROM users ORDER BY id", &[])
389+ .query("SELECT counter FROM users ORDER BY id", &[])
373− .unwrap()
390+ .unwrap()
375− .map(|row| row.get::<_, i32>("counter"))
392+ .map(|row| row.get::<_, i32>("counter"))
376− .collect();
393+ .collect();
377− assert_eq!(expected, results);
394+ assert_eq!(expected, results);
379− // Update data using old schema and make sure it was updated for the new schema
396+ // 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", &[])
398+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
382− .unwrap();
399+ .unwrap();
383− let result: i32 = new_db
400+ let result: i32 = new_db
384− .query("SELECT counter FROM users WHERE id = 1", &[])
401+ .query("SELECT counter FROM users WHERE id = 1", &[])
385− .unwrap()
402+ .unwrap()
387− .map(|row| row.get("counter"))
404+ .map(|row| row.get("counter"))
389− .unwrap();
406+ .unwrap();
390− assert_eq!(52, result);
407+ assert_eq!(52, result);
392− // Update data using new schema and make sure it was updated for the old schema
409+ // 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", &[])
411+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
395− .unwrap();
412+ .unwrap();
396− let result: i32 = old_db
413+ let result: i32 = old_db
397− .query("SELECT counter FROM users WHERE id = 1", &[])
414+ .query("SELECT counter FROM users WHERE id = 1", &[])
398− .unwrap()
415+ .unwrap()
400− .map(|row| row.get("counter"))
417+ .map(|row| row.get("counter"))
402− .unwrap();
419+ .unwrap();
403− assert_eq!(48, result);
420+ assert_eq!(48, result);
405− reshape.complete().unwrap();
423+ test.run();
406− common::assert_cleaned_up(&mut new_db);
410fn alter_column_default() {
427fn alter_column_default() {
411− let (mut reshape, mut old_db, mut new_db) = common::setup();
428+ let mut test = Test::new("Change default value for column");
413− let create_users_table = Migration::new("create_user_table", None).with_action(
430+ test.first_migration(
414− CreateTableBuilder::default()
431+ r#"
432+ name = "create_user_table"
435+ type = "create_table"
415− .name("users")
436+ name = "users"
416− .primary_key(vec!["id".to_string()])
437+ primary_key = ["id"]
417− .columns(vec![
439+ [[actions.columns]]
418− ColumnBuilder::default()
419− .name("id")
440+ name = "id"
420− .data_type("INTEGER")
441+ type = "INTEGER"
422− .unwrap(),
443+ [[actions.columns]]
423− ColumnBuilder::default()
424− .name("name")
444+ name = "name"
425− .data_type("TEXT")
445+ type = "TEXT"
426− .nullable(false)
446+ nullable = false
427− .default_value("'DEFAULT'")
447+ default = "'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,
451+ test.second_migration(
453+ name = "change_name_default"
456+ type = "alter_column"
461+ default = "'NEW DEFAULT'"
465+ test.after_first(|db| {
461− // Insert a test user
466+ // Insert a test user
463− .simple_query(
467+ db.simple_query(
465 INSERT INTO users (id) VALUES (1)
469 INSERT INTO users (id) VALUES (1)
468 .unwrap();
472 .unwrap();
470− // Run second migration
475+ test.intermediate(|old_db, new_db| {
471− reshape.migrate(second_migrations.clone()).unwrap();
473− .simple_query(&reshape::schema_query_for_migration(
474− &second_migrations.last().unwrap().name,
478− // Check that the existing users has the old default value
476+ // Check that the existing users has the old default value
479− let expected = vec!["DEFAULT"];
477+ let expected = vec!["DEFAULT"];
480− assert!(new_db
478+ assert!(new_db
481− .query("SELECT name FROM users", &[],)
479+ .query("SELECT name FROM users", &[],)
482− .unwrap()
480+ .unwrap()
484− .map(|row| row.get::<_, String>("name"))
482+ .map(|row| row.get::<_, String>("name"))
485− .eq(expected));
483+ .eq(expected));
487− // Insert data using old schema and make those get the old default value
485+ // Insert data using old schema and make those get the old default value
489− .simple_query("INSERT INTO users (id) VALUES (2)")
487+ .simple_query("INSERT INTO users (id) VALUES (2)")
490− .unwrap();
488+ .unwrap();
491− let result = new_db
489+ let result = new_db
492− .query_one("SELECT name from users WHERE id = 2", &[])
490+ .query_one("SELECT name from users WHERE id = 2", &[])
493− .unwrap();
491+ .unwrap();
494− assert_eq!("DEFAULT", result.get::<_, &str>("name"));
492+ assert_eq!("DEFAULT", result.get::<_, &str>("name"));
496− // Insert data using new schema and make sure it gets the new default value
494+ // Insert data using new schema and make sure it gets the new default value
498− .simple_query("INSERT INTO users (id) VALUES (3)")
496+ .simple_query("INSERT INTO users (id) VALUES (3)")
499− .unwrap();
497+ .unwrap();
500− let result = old_db
498+ let result = old_db
501− .query_one("SELECT name from users WHERE id = 3", &[])
499+ .query_one("SELECT name from users WHERE id = 3", &[])
502− .unwrap();
500+ .unwrap();
503− assert_eq!("NEW DEFAULT", result.get::<_, &str>("name"));
501+ assert_eq!("NEW DEFAULT", result.get::<_, &str>("name"));
505− reshape.complete().unwrap();
504+ test.run();
506− common::assert_cleaned_up(&mut new_db);
510fn alter_column_with_index() {
508fn alter_column_with_index() {
511− let (mut reshape, mut db, _) = common::setup();
509+ let mut test = Test::new("Alter column with index");
513− let create_users_table = Migration::new("create_user_table", None)
515− CreateTableBuilder::default()
517− .primary_key(vec!["id".to_string()])
519− ColumnBuilder::default()
521− .data_type("INTEGER")
524− ColumnBuilder::default()
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 {
560− let first_migrations = vec![create_users_table.clone()];
511+ test.first_migration(
561− let second_migrations = vec![create_users_table.clone(), uppercase_name.clone()];
512+ r#"
513+ name = "create_user_table"
563− // Run first migration, should automatically finish
515+ [[actions]]
564− reshape.migrate(first_migrations.clone()).unwrap();
516+ type = "create_table"
518+ primary_key = ["id"]
566− // Run second migration
520+ [[actions.columns]]
567− reshape.migrate(second_migrations.clone()).unwrap();
521+ name = "id"
568− db.simple_query(&reshape::schema_query_for_migration(
522+ type = "INTEGER"
569− &second_migrations.last().unwrap().name,
573− // Complete the second migration which should replace the existing column
524+ [[actions.columns]]
574− // with the temporary one
525+ name = "first_name"
575− reshape.complete().unwrap();
526+ type = "TEXT"
537+ name = "users_name_idx"
538+ columns = ["first_name", "last_name"]
542+ test.second_migration(
544+ name = "uppercase_last_name"
547+ type = "alter_column"
549+ column = "last_name"
550+ up = "UPPER(last_name)"
551+ down = "LOWER(last_name)"
555+ test.after_completion(|db| {
577− // Make sure index still exists
556+ // Make sure index still exists
578− let result: i64 = db
557+ let result: i64 = db
581 SELECT COUNT(*)
560 SELECT COUNT(*)
582 FROM pg_catalog.pg_index
561 FROM pg_catalog.pg_index
583 JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
562 JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
584 WHERE pg_class.relname = 'users_name_idx'
563 WHERE pg_class.relname = 'users_name_idx'
588− .unwrap()
567+ .unwrap()
589− .first()
568+ .first()
590− .map(|row| row.get(0))
569+ .map(|row| row.get(0))
591− .unwrap();
570+ .unwrap();
592− assert_eq!(1, result, "expected index to still exist");
571+ 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);
594− common::assert_cleaned_up(&mut db);
733+ test.run();