@@ -1,45 +1,61 @@
1+use reshape::migrations::{
2+ AddIndex, AlterColumn, ColumnBuilder, ColumnChanges, CreateTableBuilder, Index, Migration,
3+};
4+
15mod common;
2−use common::Test;
36
47#[test]
58fn alter_column_data() {
6− let mut test = Test::new("Alter column");
7−
8− test.first_migration(
9− r#"
10− name = "create_user_table"
11−
12− [[actions]]
13− type = "create_table"
14− name = "users"
15− primary_key = ["id"]
9+ let (mut reshape, mut old_db, mut new_db) = common::setup();
10+
11+ let create_users_table = Migration::new("create_user_table", None).with_action(
12+ CreateTableBuilder::default()
13+ .name("users")
14+ .primary_key(vec!["id".to_string()])
15+ .columns(vec![
16+ ColumnBuilder::default()
17+ .name("id")
18+ .data_type("INTEGER")
19+ .build()
20+ .unwrap(),
21+ ColumnBuilder::default()
22+ .name("name")
23+ .data_type("TEXT")
24+ .build()
25+ .unwrap(),
26+ ])
27+ .build()
28+ .unwrap(),
29+ );
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 {
36+ data_type: None,
37+ nullable: None,
38+ name: None,
39+ default: None,
40+ },
41+ });
1642
17− [[actions.columns]]
18− name = "id"
19− type = "INTEGER"
43+ let first_migrations = vec![create_users_table.clone()];
44+ let second_migrations = vec![create_users_table.clone(), uppercase_name.clone()];
2045
21− [[actions.columns]]
22− name = "name"
23− type = "TEXT"
24− "#,
25− );
46+ // Run first migration, should automatically finish
47+ reshape.migrate(first_migrations.clone()).unwrap();
2648
27− test.second_migration(
28− r#"
29− name = "uppercase_name"
30−
31− [[actions]]
32− type = "alter_column"
33− table = "users"
34− column = "name"
35− up = "UPPER(name)"
36− down = "LOWER(name)"
37− "#,
38− );
49+ // Update search paths
50+ old_db
51+ .simple_query(&reshape::schema_query_for_migration(
52+ &first_migrations.last().unwrap().name,
53+ ))
54+ .unwrap();
3955
40− test.after_first(|db| {
41− // Insert some test users
42− db.simple_query(
56+ // Insert some test users
57+ old_db
58+ .simple_query(
4359 "
4460 INSERT INTO users (id, name) VALUES
4561 (1, 'john Doe'),
@@ -47,81 +63,98 @@ fn alter_column_data() {
4763 ",
4864 )
4965 .unwrap();
50− });
5166
52− test.intermediate(|old_db, new_db| {
53− // Check that the existing users has the altered data
54− let expected = vec!["JOHN DOE", "JANE DOE"];
55− assert!(new_db
56− .query("SELECT name FROM users ORDER BY id", &[],)
57− .unwrap()
58− .iter()
59− .map(|row| row.get::<_, String>("name"))
60− .eq(expected));
61−
62− // Insert data using old schema and make sure the new schema gets correct values
63− old_db
64− .simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
65− .unwrap();
66− let result = new_db
67− .query_one("SELECT name from users WHERE id = 3", &[])
68− .unwrap();
69− assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
70−
71− // Insert data using new schema and make sure the old schema gets correct values
72− new_db
73− .simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
74− .unwrap();
75− let result = old_db
76− .query_one("SELECT name from users WHERE id = 4", &[])
77− .unwrap();
78− assert_eq!("test testsson", result.get::<_, &str>("name"));
79− });
67+ // Run second migration
68+ reshape.migrate(second_migrations.clone()).unwrap();
69+ new_db
70+ .simple_query(&reshape::schema_query_for_migration(
71+ &second_migrations.last().unwrap().name,
72+ ))
73+ .unwrap();
74+
75+ // Check that the existing users has the altered data
76+ let expected = vec!["JOHN DOE", "JANE DOE"];
77+ assert!(new_db
78+ .query("SELECT name FROM users ORDER BY id", &[],)
79+ .unwrap()
80+ .iter()
81+ .map(|row| row.get::<_, String>("name"))
82+ .eq(expected));
83+
84+ // Insert data using old schema and make sure the new schema gets correct values
85+ old_db
86+ .simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
87+ .unwrap();
88+ let result = new_db
89+ .query_one("SELECT name from users WHERE id = 3", &[])
90+ .unwrap();
91+ assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
92+
93+ // Insert data using new schema and make sure the old schema gets correct values
94+ new_db
95+ .simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
96+ .unwrap();
97+ let result = old_db
98+ .query_one("SELECT name from users WHERE id = 4", &[])
99+ .unwrap();
100+ assert_eq!("test testsson", result.get::<_, &str>("name"));
80101
81− test.run();
102+ reshape.complete().unwrap();
103+ common::assert_cleaned_up(&mut new_db);
82104}
83105
84106#[test]
85107fn alter_column_set_not_null() {
86− let mut test = Test::new("Set column not null");
87−
88− test.first_migration(
89− r#"
90− name = "create_user_table"
91−
92− [[actions]]
93− type = "create_table"
94− name = "users"
95− primary_key = ["id"]
96−
97− [[actions.columns]]
98− name = "id"
99− type = "INTEGER"
100−
101− [[actions.columns]]
102− name = "name"
103− type = "TEXT"
104− "#,
108+ let (mut reshape, mut old_db, mut new_db) = common::setup();
109+
110+ let create_users_table = Migration::new("create_user_table", None).with_action(
111+ CreateTableBuilder::default()
112+ .name("users")
113+ .primary_key(vec!["id".to_string()])
114+ .columns(vec![
115+ ColumnBuilder::default()
116+ .name("id")
117+ .data_type("INTEGER")
118+ .build()
119+ .unwrap(),
120+ ColumnBuilder::default()
121+ .name("name")
122+ .data_type("TEXT")
123+ .build()
124+ .unwrap(),
125+ ])
126+ .build()
127+ .unwrap(),
105128 );
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 {
135+ data_type: None,
136+ nullable: Some(false),
137+ name: None,
138+ default: None,
139+ },
140+ });
106141
107− test.second_migration(
108− r#"
109− name = "set_name_not_null"
142+ let first_migrations = vec![create_users_table.clone()];
143+ let second_migrations = vec![create_users_table.clone(), set_name_not_null.clone()];
110144
111− [[actions]]
112− type = "alter_column"
113− table = "users"
114− column = "name"
115− up = "COALESCE(name, 'TEST_DEFAULT_VALUE')"
145+ // Run first migration, should automatically finish
146+ reshape.migrate(first_migrations.clone()).unwrap();
116147
117− [actions.changes]
118− nullable = false
119− "#,
120− );
148+ // Update search paths
149+ old_db
150+ .simple_query(&reshape::schema_query_for_migration(
151+ &first_migrations.last().unwrap().name,
152+ ))
153+ .unwrap();
121154
122− test.after_first(|db| {
123− // Insert some test users
124− db.simple_query(
155+ // Insert some test users
156+ old_db
157+ .simple_query(
125158 "
126159 INSERT INTO users (id, name) VALUES
127160 (1, 'John Doe'),
@@ -129,180 +162,99 @@ fn alter_column_set_not_null() {
129162 ",
130163 )
131164 .unwrap();
132− });
133−
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"];
137− assert!(new_db
138− .query("SELECT name FROM users ORDER BY id", &[],)
139− .unwrap()
140− .iter()
141− .map(|row| row.get::<_, String>("name"))
142− .eq(expected));
143−
144− // Insert data using old schema and make sure the new schema gets correct values
145− old_db
146− .simple_query("INSERT INTO users (id, name) VALUES (3, NULL)")
147− .unwrap();
148− let result = new_db
149− .query_one("SELECT name from users WHERE id = 3", &[])
150− .unwrap();
151− assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
152−
153− // Insert data using new schema and make sure the old schema gets correct values
154− new_db
155− .simple_query("INSERT INTO users (id, name) VALUES (4, 'Jane Doe')")
156− .unwrap();
157− let result = old_db
158− .query_one("SELECT name from users WHERE id = 4", &[])
159− .unwrap();
160− assert_eq!("Jane Doe", result.get::<_, &str>("name"));
161−
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");
165− });
166−
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");
171− });
172−
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");
177− });
178165
179− test.run();
180−}
181−
182−#[test]
183−fn alter_column_set_nullable() {
184− let mut test = Test::new("Set column nullable");
185−
186− test.first_migration(
187− r#"
188− name = "create_user_table"
189−
190− [[actions]]
191− type = "create_table"
192− name = "users"
193− primary_key = ["id"]
194−
195− [[actions.columns]]
196− name = "id"
197− type = "INTEGER"
198−
199− [[actions.columns]]
200− name = "name"
201− type = "TEXT"
202− nullable = false
203− "#,
204− );
205−
206− test.second_migration(
207− r#"
208− name = "set_name_nullable"
209−
210− [[actions]]
211− type = "alter_column"
212− table = "users"
213− column = "name"
214− down = "COALESCE(name, 'TEST_DEFAULT_VALUE')"
215−
216− [actions.changes]
217− nullable = true
218− "#,
219− );
220−
221− test.after_first(|db| {
222− // Insert a test user
223− db.simple_query(
224− "
225− INSERT INTO users (id, name) VALUES
226− (1, 'John Doe')
227− ",
228− )
166+ // Run second migration
167+ reshape.migrate(second_migrations.clone()).unwrap();
168+ new_db
169+ .simple_query(&reshape::schema_query_for_migration(
170+ &second_migrations.last().unwrap().name,
171+ ))
229172 .unwrap();
230− });
231−
232− test.intermediate(|old_db, new_db| {
233− // Insert data using new schema and make sure the old schema gets correct values
234− new_db
235− .simple_query("INSERT INTO users (id, name) VALUES (2, NULL)")
236− .unwrap();
237− let result = old_db
238− .query_one("SELECT name from users WHERE id = 2", &[])
239− .unwrap();
240− assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
241−
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");
245−
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");
249− });
250173
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");
255− });
174+ // Check that existing users got the correct values
175+ let expected = vec!["John Doe", "TEST_DEFAULT_VALUE"];
176+ assert!(new_db
177+ .query("SELECT name FROM users ORDER BY id", &[],)
178+ .unwrap()
179+ .iter()
180+ .map(|row| row.get::<_, String>("name"))
181+ .eq(expected));
182+
183+ // Insert data using old schema and make sure the new schema gets correct values
184+ old_db
185+ .simple_query("INSERT INTO users (id, name) VALUES (3, NULL)")
186+ .unwrap();
187+ let result = new_db
188+ .query_one("SELECT name from users WHERE id = 3", &[])
189+ .unwrap();
190+ assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
256191
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");
261− });
192+ // Insert data using new schema and make sure the old schema gets correct values
193+ new_db
194+ .simple_query("INSERT INTO users (id, name) VALUES (4, 'Jane Doe')")
195+ .unwrap();
196+ let result = old_db
197+ .query_one("SELECT name from users WHERE id = 4", &[])
198+ .unwrap();
199+ assert_eq!("Jane Doe", result.get::<_, &str>("name"));
262200
263− test.run();
201+ reshape.complete().unwrap();
202+ common::assert_cleaned_up(&mut new_db);
264203}
265204
266205#[test]
267206fn alter_column_rename() {
268− let mut test = Test::new("Rename column");
269−
270− test.first_migration(
271− r#"
272− name = "create_user_table"
273−
274− [[actions]]
275− type = "create_table"
276− name = "users"
277− primary_key = ["id"]
278−
279− [[actions.columns]]
280− name = "id"
281− type = "INTEGER"
282−
283− [[actions.columns]]
284− name = "name"
285− type = "TEXT"
286− "#,
287− );
288−
289− test.second_migration(
290− r#"
291− name = "set_name_not_null"
292−
293− [[actions]]
294− type = "alter_column"
295− table = "users"
296− column = "name"
297−
298− [actions.changes]
299− name = "full_name"
300− "#,
207+ let (mut reshape, mut old_db, mut new_db) = common::setup();
208+
209+ let create_users_table = Migration::new("create_user_table", None).with_action(
210+ CreateTableBuilder::default()
211+ .name("users")
212+ .primary_key(vec!["id".to_string()])
213+ .columns(vec![
214+ ColumnBuilder::default()
215+ .name("id")
216+ .data_type("INTEGER")
217+ .build()
218+ .unwrap(),
219+ ColumnBuilder::default()
220+ .name("name")
221+ .data_type("TEXT")
222+ .build()
223+ .unwrap(),
224+ ])
225+ .build()
226+ .unwrap(),
301227 );
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
233+ down: None,
234+ changes: ColumnChanges {
235+ data_type: None,
236+ nullable: None,
237+ name: Some("full_name".to_string()),
238+ default: None,
239+ },
240+ });
241+
242+ let first_migrations = vec![create_users_table.clone()];
243+ let second_migrations = vec![create_users_table.clone(), rename_to_full_name.clone()];
244+
245+ // Run first migration, should automatically finish
246+ reshape.migrate(first_migrations.clone()).unwrap();
247+
248+ // Update search paths
249+ old_db
250+ .simple_query(&reshape::schema_query_for_migration(
251+ &first_migrations.last().unwrap().name,
252+ ))
253+ .unwrap();
302254
303− test.after_first(|db| {
304− // Insert some test data
305− db.simple_query(
255+ // Insert some test data
256+ old_db
257+ .simple_query(
306258 "
307259 INSERT INTO users (id, name) VALUES
308260 (1, 'John Doe'),
@@ -310,69 +262,94 @@ fn alter_column_rename() {
310262 ",
311263 )
312264 .unwrap();
313− });
314265
315− test.intermediate(|_, new_db| {
316− // Check that existing values can be queried using new column name
317− let expected = vec!["John Doe", "Jane Doe"];
318− assert!(new_db
319− .query("SELECT full_name FROM users ORDER BY id", &[],)
320− .unwrap()
321− .iter()
322− .map(|row| row.get::<_, String>("full_name"))
323− .eq(expected));
324− });
266+ // Run second migration
267+ reshape.migrate(second_migrations.clone()).unwrap();
268+ new_db
269+ .simple_query(&reshape::schema_query_for_migration(
270+ &second_migrations.last().unwrap().name,
271+ ))
272+ .unwrap();
325273
326− test.run();
274+ // Check that existing values can be queried using new column name
275+ let expected = vec!["John Doe", "Jane Doe"];
276+ assert!(new_db
277+ .query("SELECT full_name FROM users ORDER BY id", &[],)
278+ .unwrap()
279+ .iter()
280+ .map(|row| row.get::<_, String>("full_name"))
281+ .eq(expected));
282+
283+ reshape.complete().unwrap();
284+ common::assert_cleaned_up(&mut new_db);
327285}
328286
329287#[test]
330288fn alter_column_multiple() {
331− let mut test = Test::new("Alter column value multiple times");
332−
333− test.first_migration(
334− r#"
335− name = "create_user_table"
336−
337− [[actions]]
338− type = "create_table"
339− name = "users"
340− primary_key = ["id"]
341−
342− [[actions.columns]]
343− name = "id"
344− type = "INTEGER"
345−
346− [[actions.columns]]
347− name = "counter"
348− type = "INTEGER"
349− nullable = false
350− "#,
351− );
352−
353− test.second_migration(
354− r#"
355− name = "increment_counter_twice"
356−
357− [[actions]]
358− type = "alter_column"
359− table = "users"
360− column = "counter"
361− up = "counter + 1"
362− down = "counter - 1"
363−
364− [[actions]]
365− type = "alter_column"
366− table = "users"
367− column = "counter"
368− up = "counter + 1"
369− down = "counter - 1"
370− "#,
289+ let (mut reshape, mut old_db, mut new_db) = common::setup();
290+
291+ let create_users_table = Migration::new("create_user_table", None).with_action(
292+ CreateTableBuilder::default()
293+ .name("users")
294+ .primary_key(vec!["id".to_string()])
295+ .columns(vec![
296+ ColumnBuilder::default()
297+ .name("id")
298+ .data_type("INTEGER")
299+ .build()
300+ .unwrap(),
301+ ColumnBuilder::default()
302+ .name("counter")
303+ .data_type("INTEGER")
304+ .nullable(false)
305+ .build()
306+ .unwrap(),
307+ ])
308+ .build()
309+ .unwrap(),
371310 );
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 {
318+ data_type: None,
319+ nullable: None,
320+ name: None,
321+ default: None,
322+ },
323+ })
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 {
330+ data_type: None,
331+ nullable: None,
332+ name: None,
333+ default: None,
334+ },
335+ });
336+
337+ let first_migrations = vec![create_users_table.clone()];
338+ let second_migrations = vec![create_users_table.clone(), increment_counter_twice.clone()];
339+
340+ // Run first migration, should automatically finish
341+ reshape.migrate(first_migrations.clone()).unwrap();
342+
343+ // Update search paths
344+ old_db
345+ .simple_query(&reshape::schema_query_for_migration(
346+ &first_migrations.last().unwrap().name,
347+ ))
348+ .unwrap();
372349
373− test.after_first(|db| {
374− // Insert some test data
375− db.simple_query(
350+ // Insert some test data
351+ old_db
352+ .simple_query(
376353 "
377354 INSERT INTO users (id, counter) VALUES
378355 (1, 0),
@@ -380,355 +357,239 @@ fn alter_column_multiple() {
380357 ",
381358 )
382359 .unwrap();
383− });
384360
385− test.intermediate(|old_db, new_db| {
386− // Check that the existing data has been updated
387− let expected = vec![2, 102];
388− let results: Vec<i32> = new_db
389− .query("SELECT counter FROM users ORDER BY id", &[])
390− .unwrap()
391− .iter()
392− .map(|row| row.get::<_, i32>("counter"))
393− .collect();
394− assert_eq!(expected, results);
395−
396− // Update data using old schema and make sure it was updated for the new schema
397− old_db
398− .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
399− .unwrap();
400− let result: i32 = new_db
401− .query("SELECT counter FROM users WHERE id = 1", &[])
402− .unwrap()
403− .iter()
404− .map(|row| row.get("counter"))
405− .nth(0)
406− .unwrap();
407− assert_eq!(52, result);
408−
409− // Update data using new schema and make sure it was updated for the old schema
410− new_db
411− .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
412− .unwrap();
413− let result: i32 = old_db
414− .query("SELECT counter FROM users WHERE id = 1", &[])
415− .unwrap()
416− .iter()
417− .map(|row| row.get("counter"))
418− .nth(0)
419− .unwrap();
420− assert_eq!(48, result);
421− });
361+ // Run second migration
362+ reshape.migrate(second_migrations.clone()).unwrap();
363+ new_db
364+ .simple_query(&reshape::schema_query_for_migration(
365+ &second_migrations.last().unwrap().name,
366+ ))
367+ .unwrap();
422368
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", &[])
373+ .unwrap()
374+ .iter()
375+ .map(|row| row.get::<_, i32>("counter"))
376+ .collect();
377+ assert_eq!(expected, results);
378+
379+ // Update data using old schema and make sure it was updated for the new schema
380+ old_db
381+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
382+ .unwrap();
383+ let result: i32 = new_db
384+ .query("SELECT counter FROM users WHERE id = 1", &[])
385+ .unwrap()
386+ .iter()
387+ .map(|row| row.get("counter"))
388+ .nth(0)
389+ .unwrap();
390+ assert_eq!(52, result);
391+
392+ // Update data using new schema and make sure it was updated for the old schema
393+ new_db
394+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
395+ .unwrap();
396+ let result: i32 = old_db
397+ .query("SELECT counter FROM users WHERE id = 1", &[])
398+ .unwrap()
399+ .iter()
400+ .map(|row| row.get("counter"))
401+ .nth(0)
402+ .unwrap();
403+ assert_eq!(48, result);
404+
405+ reshape.complete().unwrap();
406+ common::assert_cleaned_up(&mut new_db);
424407}
425408
426409#[test]
427410fn alter_column_default() {
428− let mut test = Test::new("Change default value for column");
429−
430− test.first_migration(
431− r#"
432− name = "create_user_table"
433−
434− [[actions]]
435− type = "create_table"
436− name = "users"
437− primary_key = ["id"]
438−
439− [[actions.columns]]
440− name = "id"
441− type = "INTEGER"
442−
443− [[actions.columns]]
444− name = "name"
445− type = "TEXT"
446− nullable = false
447− default = "'DEFAULT'"
448− "#,
449− );
450−
451− test.second_migration(
452− r#"
453− name = "change_name_default"
454−
455− [[actions]]
456− type = "alter_column"
457− table = "users"
458− column = "name"
459−
460− [actions.changes]
461− default = "'NEW DEFAULT'"
462− "#,
411+ let (mut reshape, mut old_db, mut new_db) = common::setup();
412+
413+ let create_users_table = Migration::new("create_user_table", None).with_action(
414+ CreateTableBuilder::default()
415+ .name("users")
416+ .primary_key(vec!["id".to_string()])
417+ .columns(vec![
418+ ColumnBuilder::default()
419+ .name("id")
420+ .data_type("INTEGER")
421+ .build()
422+ .unwrap(),
423+ ColumnBuilder::default()
424+ .name("name")
425+ .data_type("TEXT")
426+ .nullable(false)
427+ .default_value("'DEFAULT'")
428+ .build()
429+ .unwrap(),
430+ ])
431+ .build()
432+ .unwrap(),
463433 );
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(),
438+ up: None,
439+ down: None,
440+ changes: ColumnChanges {
441+ data_type: None,
442+ nullable: None,
443+ name: None,
444+ default: Some("'NEW DEFAULT'".to_string()),
445+ },
446+ });
447+
448+ let first_migrations = vec![create_users_table.clone()];
449+ let second_migrations = vec![create_users_table.clone(), change_name_default.clone()];
450+
451+ // Run first migration, should automatically finish
452+ reshape.migrate(first_migrations.clone()).unwrap();
453+
454+ // Update search paths
455+ old_db
456+ .simple_query(&reshape::schema_query_for_migration(
457+ &first_migrations.last().unwrap().name,
458+ ))
459+ .unwrap();
464460
465− test.after_first(|db| {
466− // Insert a test user
467− db.simple_query(
461+ // Insert a test user
462+ old_db
463+ .simple_query(
468464 "
469465 INSERT INTO users (id) VALUES (1)
470466 ",
471467 )
472468 .unwrap();
473− });
474469
475− test.intermediate(|old_db, new_db| {
476− // Check that the existing users has the old default value
477− let expected = vec!["DEFAULT"];
478− assert!(new_db
479− .query("SELECT name FROM users", &[],)
480− .unwrap()
481− .iter()
482− .map(|row| row.get::<_, String>("name"))
483− .eq(expected));
484−
485− // Insert data using old schema and make those get the old default value
486− old_db
487− .simple_query("INSERT INTO users (id) VALUES (2)")
488− .unwrap();
489− let result = new_db
490− .query_one("SELECT name from users WHERE id = 2", &[])
491− .unwrap();
492− assert_eq!("DEFAULT", result.get::<_, &str>("name"));
493−
494− // Insert data using new schema and make sure it gets the new default value
495− new_db
496− .simple_query("INSERT INTO users (id) VALUES (3)")
497− .unwrap();
498− let result = old_db
499− .query_one("SELECT name from users WHERE id = 3", &[])
500− .unwrap();
501− assert_eq!("NEW DEFAULT", result.get::<_, &str>("name"));
502− });
470+ // Run second migration
471+ reshape.migrate(second_migrations.clone()).unwrap();
472+ new_db
473+ .simple_query(&reshape::schema_query_for_migration(
474+ &second_migrations.last().unwrap().name,
475+ ))
476+ .unwrap();
503477
504− test.run();
478+ // Check that the existing users has the old default value
479+ let expected = vec!["DEFAULT"];
480+ assert!(new_db
481+ .query("SELECT name FROM users", &[],)
482+ .unwrap()
483+ .iter()
484+ .map(|row| row.get::<_, String>("name"))
485+ .eq(expected));
486+
487+ // Insert data using old schema and make those get the old default value
488+ old_db
489+ .simple_query("INSERT INTO users (id) VALUES (2)")
490+ .unwrap();
491+ let result = new_db
492+ .query_one("SELECT name from users WHERE id = 2", &[])
493+ .unwrap();
494+ assert_eq!("DEFAULT", result.get::<_, &str>("name"));
495+
496+ // Insert data using new schema and make sure it gets the new default value
497+ new_db
498+ .simple_query("INSERT INTO users (id) VALUES (3)")
499+ .unwrap();
500+ let result = old_db
501+ .query_one("SELECT name from users WHERE id = 3", &[])
502+ .unwrap();
503+ assert_eq!("NEW DEFAULT", result.get::<_, &str>("name"));
504+
505+ reshape.complete().unwrap();
506+ common::assert_cleaned_up(&mut new_db);
505507}
506508
507509#[test]
508510fn alter_column_with_index() {
509− let mut test = Test::new("Alter column with index");
510−
511− test.first_migration(
512− r#"
513− name = "create_user_table"
514−
515− [[actions]]
516− type = "create_table"
517− name = "users"
518− primary_key = ["id"]
519−
520− [[actions.columns]]
521− name = "id"
522− type = "INTEGER"
523−
524− [[actions.columns]]
525− name = "first_name"
526− type = "TEXT"
511+ let (mut reshape, mut db, _) = common::setup();
512+
513+ let create_users_table = Migration::new("create_user_table", None)
514+ .with_action(
515+ CreateTableBuilder::default()
516+ .name("users")
517+ .primary_key(vec!["id".to_string()])
518+ .columns(vec![
519+ ColumnBuilder::default()
520+ .name("id")
521+ .data_type("INTEGER")
522+ .build()
523+ .unwrap(),
524+ ColumnBuilder::default()
525+ .name("first_name")
526+ .data_type("TEXT")
527+ .build()
528+ .unwrap(),
529+ ColumnBuilder::default()
530+ .name("last_name")
531+ .data_type("TEXT")
532+ .build()
533+ .unwrap(),
534+ ])
535+ .build()
536+ .unwrap(),
537+ )
538+ .with_action(AddIndex {
539+ table: "users".to_string(),
540+ index: Index {
541+ name: "users_name_idx".to_string(),
542+ columns: vec!["first_name".to_string(), "last_name".to_string()],
543+ unique: false,
544+ index_type: None,
545+ },
546+ });
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 {
553+ data_type: None,
554+ nullable: None,
555+ name: None,
556+ default: None,
557+ },
558+ });
527559
528− [[actions.columns]]
529− name = "last_name"
530− type = "TEXT"
560+ let first_migrations = vec![create_users_table.clone()];
561+ let second_migrations = vec![create_users_table.clone(), uppercase_name.clone()];
531562
532− [[actions]]
533− type = "add_index"
534− table = "users"
563+ // Run first migration, should automatically finish
564+ reshape.migrate(first_migrations.clone()).unwrap();
535565
536− [actions.index]
537− name = "users_name_idx"
538− columns = ["first_name", "last_name"]
539− "#,
540− );
566+ // Run second migration
567+ reshape.migrate(second_migrations.clone()).unwrap();
568+ db.simple_query(&reshape::schema_query_for_migration(
569+ &second_migrations.last().unwrap().name,
570+ ))
571+ .unwrap();
541572
542− test.second_migration(
543− r#"
544− name = "uppercase_last_name"
545−
546− [[actions]]
547− type = "alter_column"
548− table = "users"
549− column = "last_name"
550− up = "UPPER(last_name)"
551− down = "LOWER(last_name)"
552− "#,
553− );
573+ // Complete the second migration which should replace the existing column
574+ // with the temporary one
575+ reshape.complete().unwrap();
554576
555− test.after_completion(|db| {
556− // Make sure index still exists
557− let result: i64 = db
558− .query(
559− "
577+ // Make sure index still exists
578+ let result: i64 = db
579+ .query(
580+ "
560581 SELECT COUNT(*)
561582 FROM pg_catalog.pg_index
562583 JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
563584 WHERE pg_class.relname = 'users_name_idx'
564585 ",
565− &[],
566− )
567− .unwrap()
568− .first()
569− .map(|row| row.get(0))
570− .unwrap();
571− assert_eq!(1, result, "expected index to still exist");
572− });
573−
574− test.run();
575−}
576−
577−#[test]
578−fn alter_column_with_unique_index() {
579− let mut test = Test::new("Alter column with unique index");
580−
581− test.first_migration(
582− r#"
583− name = "create_user_table"
584−
585− [[actions]]
586− type = "create_table"
587− name = "users"
588− primary_key = ["id"]
589−
590− [[actions.columns]]
591− name = "id"
592− type = "INTEGER"
593−
594− [[actions.columns]]
595− name = "name"
596− type = "TEXT"
597−
598− [[actions]]
599− type = "add_index"
600− table = "users"
601−
602− [actions.index]
603− name = "name_idx"
604− columns = ["name"]
605− unique = true
606− "#,
607− );
608−
609− test.second_migration(
610− r#"
611− name = "uppercase_name"
612−
613− [[actions]]
614− type = "alter_column"
615− table = "users"
616− column = "name"
617− up = "UPPER(name)"
618− down = "LOWER(name)"
619− "#,
620− );
621−
622− test.after_first(|db| {
623− db.simple_query("INSERT INTO users (id, name) VALUES (1, 'Test')")
624− .unwrap();
625− });
626−
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')");
630− assert!(
631− result.is_err(),
632− "expected duplicate insert to new schema to fail"
633− );
634−
635− // Try inserting a value which duplicates the lowercase value of an existing row
636− new_db
637− .simple_query("INSERT INTO users (id, name) VALUES (2, 'JOHN')")
638− .unwrap();
639− let result = old_db.simple_query("INSERT INTO users (id, name) VALUES (3, 'john')");
640− assert!(
641− result.is_err(),
642− "expected duplicate insert to old schema to fail"
643− );
644− });
645−
646− test.after_completion(|db| {
647− // Make sure index still exists
648− let is_unique: bool = db
649− .query(
650− "
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'
655− ",
656− &[],
657− )
658− .unwrap()
659− .first()
660− .map(|row| row.get("indisunique"))
661− .unwrap();
662− assert!(is_unique, "expected index to still be unique");
663− });
664−
665− test.run();
666−}
667−
668−#[test]
669−fn alter_column_with_hash_index() {
670− let mut test = Test::new("Alter column with custom index type");
671−
672− test.first_migration(
673− r#"
674− name = "create_user_table"
675−
676− [[actions]]
677− type = "create_table"
678− name = "users"
679− primary_key = ["id"]
680−
681− [[actions.columns]]
682− name = "id"
683− type = "INTEGER"
684−
685− [[actions.columns]]
686− name = "name"
687− type = "TEXT"
688−
689− [[actions]]
690− type = "add_index"
691− table = "users"
692−
693− [actions.index]
694− name = "name_idx"
695− columns = ["name"]
696− type = "hash"
697− "#,
698− );
699−
700− test.second_migration(
701− r#"
702− name = "uppercase_name"
703−
704− [[actions]]
705− type = "alter_column"
706− table = "users"
707− column = "name"
708− up = "UPPER(name)"
709− down = "LOWER(name)"
710− "#,
711− );
712−
713− test.after_completion(|db| {
714− // Make sure index still has type GIN
715− let index_type: String = db
716− .query(
717− "
718− SELECT pg_am.amname
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'
723− ",
724− &[],
725− )
726− .unwrap()
727− .first()
728− .map(|row| row.get("amname"))
729− .unwrap();
730− assert_eq!("hash", index_type);
731− });
586+ &[],
587+ )
588+ .unwrap()
589+ .first()
590+ .map(|row| row.get(0))
591+ .unwrap();
592+ assert_eq!(1, result, "expected index to still exist");
732593
733− test.run();
594+ common::assert_cleaned_up(&mut db);
734595}