@@ -1,45 +1,66 @@
1+use reshape::migrations::{AlterColumn, Column, ColumnChanges, CreateTable, Migration};
2+use reshape::Status;
3+
14mod common;
2−use common::Test;
35
46#[test]
57fn 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"]
8+ let (mut reshape, mut old_db, mut new_db) = common::setup();
9+
10+ let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
11+ name: "users".to_string(),
12+ primary_key: vec!["id".to_string()],
13+ foreign_keys: vec![],
14+ columns: vec![
15+ Column {
16+ name: "id".to_string(),
17+ data_type: "INTEGER".to_string(),
18+ nullable: true,
19+ default: None,
20+ generated: None,
21+ },
22+ Column {
23+ name: "name".to_string(),
24+ data_type: "TEXT".to_string(),
25+ nullable: false,
26+ default: None,
27+ generated: None,
28+ },
29+ ],
30+ });
31+ let uppercase_name = Migration::new("uppercase_name", None).with_action(AlterColumn {
32+ table: "users".to_string(),
33+ column: "name".to_string(),
34+ up: Some("UPPER(name)".to_string()),
35+ down: Some("LOWER(name)".to_string()),
36+ changes: ColumnChanges {
37+ data_type: None,
38+ nullable: None,
39+ name: 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− "#,
46+ // Run first migration, should automatically finish
47+ reshape.migrate(first_migrations.clone()).unwrap();
48+ assert!(matches!(reshape.state.status, Status::Idle));
49+ assert_eq!(
50+ Some(&create_users_table.name),
51+ reshape.state.current_migration.as_ref()
2552 );
2653
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− );
54+ // Update search paths
55+ old_db
56+ .simple_query(&reshape::schema_query_for_migration(
57+ &first_migrations.last().unwrap().name,
58+ ))
59+ .unwrap();
3960
40− test.after_first(|db| {
41− // Insert some test users
42− db.simple_query(
61+ // Insert some test users
62+ old_db
63+ .simple_query(
4364 "
4465 INSERT INTO users (id, name) VALUES
4566 (1, 'john Doe'),
@@ -47,81 +68,103 @@ fn alter_column_data() {
4768 ",
4869 )
4970 .unwrap();
50− });
5171
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− });
72+ // Run second migration
73+ reshape.migrate(second_migrations.clone()).unwrap();
74+ new_db
75+ .simple_query(&reshape::schema_query_for_migration(
76+ &second_migrations.last().unwrap().name,
77+ ))
78+ .unwrap();
79+
80+ // Check that the existing users has the altered data
81+ let expected = vec!["JOHN DOE", "JANE DOE"];
82+ assert!(new_db
83+ .query("SELECT name FROM users ORDER BY id", &[],)
84+ .unwrap()
85+ .iter()
86+ .map(|row| row.get::<_, String>("name"))
87+ .eq(expected));
88+
89+ // Insert data using old schema and make sure the new schema gets correct values
90+ old_db
91+ .simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
92+ .unwrap();
93+ let result = new_db
94+ .query_one("SELECT name from users WHERE id = 3", &[])
95+ .unwrap();
96+ assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
97+
98+ // Insert data using new schema and make sure the old schema gets correct values
99+ new_db
100+ .simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
101+ .unwrap();
102+ let result = old_db
103+ .query_one("SELECT name from users WHERE id = 4", &[])
104+ .unwrap();
105+ assert_eq!("test testsson", result.get::<_, &str>("name"));
80106
81− test.run();
107+ reshape.complete_migration().unwrap();
82108}
83109
84110#[test]
85111fn 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"]
112+ let (mut reshape, mut old_db, mut new_db) = common::setup();
113+
114+ let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
115+ name: "users".to_string(),
116+ primary_key: vec!["id".to_string()],
117+ foreign_keys: vec![],
118+ columns: vec![
119+ Column {
120+ name: "id".to_string(),
121+ data_type: "INTEGER".to_string(),
122+ nullable: true,
123+ default: None,
124+ generated: None,
125+ },
126+ Column {
127+ name: "name".to_string(),
128+ data_type: "TEXT".to_string(),
129+ nullable: true,
130+ default: None,
131+ generated: None,
132+ },
133+ ],
134+ });
135+ let set_name_not_null = Migration::new("set_name_not_null", None).with_action(AlterColumn {
136+ table: "users".to_string(),
137+ column: "name".to_string(),
138+ up: Some("COALESCE(name, 'TEST_DEFAULT_VALUE')".to_string()),
139+ down: Some("name".to_string()),
140+ changes: ColumnChanges {
141+ data_type: None,
142+ nullable: Some(false),
143+ name: None,
144+ },
145+ });
96146
97− [[actions.columns]]
98− name = "id"
99− type = "INTEGER"
147+ let first_migrations = vec![create_users_table.clone()];
148+ let second_migrations = vec![create_users_table.clone(), set_name_not_null.clone()];
100149
101− [[actions.columns]]
102− name = "name"
103− type = "TEXT"
104− "#,
150+ // Run first migration, should automatically finish
151+ reshape.migrate(first_migrations.clone()).unwrap();
152+ assert!(matches!(reshape.state.status, Status::Idle));
153+ assert_eq!(
154+ Some(&create_users_table.name),
155+ reshape.state.current_migration.as_ref()
105156 );
106157
107− test.second_migration(
108− r#"
109− name = "set_name_not_null"
110−
111− [[actions]]
112− type = "alter_column"
113− table = "users"
114− column = "name"
115− up = "COALESCE(name, 'TEST_DEFAULT_VALUE')"
116−
117− [actions.changes]
118− nullable = false
119− "#,
120− );
158+ // Update search paths
159+ old_db
160+ .simple_query(&reshape::schema_query_for_migration(
161+ &first_migrations.last().unwrap().name,
162+ ))
163+ .unwrap();
121164
122− test.after_first(|db| {
123− // Insert some test users
124− db.simple_query(
165+ // Insert some test users
166+ old_db
167+ .simple_query(
125168 "
126169 INSERT INTO users (id, name) VALUES
127170 (1, 'John Doe'),
@@ -129,180 +172,104 @@ fn alter_column_set_not_null() {
129172 ",
130173 )
131174 .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− });
178175
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− )
176+ // Run second migration
177+ reshape.migrate(second_migrations.clone()).unwrap();
178+ new_db
179+ .simple_query(&reshape::schema_query_for_migration(
180+ &second_migrations.last().unwrap().name,
181+ ))
229182 .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− });
250183
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− });
184+ // Check that existing users got the correct values
185+ let expected = vec!["John Doe", "TEST_DEFAULT_VALUE"];
186+ assert!(new_db
187+ .query("SELECT name FROM users ORDER BY id", &[],)
188+ .unwrap()
189+ .iter()
190+ .map(|row| row.get::<_, String>("name"))
191+ .eq(expected));
192+
193+ // Insert data using old schema and make sure the new schema gets correct values
194+ old_db
195+ .simple_query("INSERT INTO users (id, name) VALUES (3, NULL)")
196+ .unwrap();
197+ let result = new_db
198+ .query_one("SELECT name from users WHERE id = 3", &[])
199+ .unwrap();
200+ assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
256201
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− });
202+ // Insert data using new schema and make sure the old schema gets correct values
203+ new_db
204+ .simple_query("INSERT INTO users (id, name) VALUES (4, 'Jane Doe')")
205+ .unwrap();
206+ let result = old_db
207+ .query_one("SELECT name from users WHERE id = 4", &[])
208+ .unwrap();
209+ assert_eq!("Jane Doe", result.get::<_, &str>("name"));
262210
263− test.run();
211+ reshape.complete_migration().unwrap();
264212}
265213
266214#[test]
267215fn 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− "#,
216+ let (mut reshape, mut old_db, mut new_db) = common::setup();
217+
218+ let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
219+ name: "users".to_string(),
220+ primary_key: vec!["id".to_string()],
221+ foreign_keys: vec![],
222+ columns: vec![
223+ Column {
224+ name: "id".to_string(),
225+ data_type: "INTEGER".to_string(),
226+ nullable: true,
227+ default: None,
228+ generated: None,
229+ },
230+ Column {
231+ name: "name".to_string(),
232+ data_type: "TEXT".to_string(),
233+ nullable: true,
234+ default: None,
235+ generated: None,
236+ },
237+ ],
238+ });
239+ let rename_to_full_name =
240+ Migration::new("rename_to_full_name", None).with_action(AlterColumn {
241+ table: "users".to_string(),
242+ column: "name".to_string(),
243+ up: None, // up and down are not required when only renaming a column
244+ down: None,
245+ changes: ColumnChanges {
246+ data_type: None,
247+ nullable: None,
248+ name: Some("full_name".to_string()),
249+ },
250+ });
251+
252+ let first_migrations = vec![create_users_table.clone()];
253+ let second_migrations = vec![create_users_table.clone(), rename_to_full_name.clone()];
254+
255+ // Run first migration, should automatically finish
256+ reshape.migrate(first_migrations.clone()).unwrap();
257+ assert!(matches!(reshape.state.status, Status::Idle));
258+ assert_eq!(
259+ Some(&create_users_table.name),
260+ reshape.state.current_migration.as_ref()
287261 );
288262
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− "#,
301− );
263+ // Update search paths
264+ old_db
265+ .simple_query(&reshape::schema_query_for_migration(
266+ &first_migrations.last().unwrap().name,
267+ ))
268+ .unwrap();
302269
303− test.after_first(|db| {
304− // Insert some test data
305− db.simple_query(
270+ // Insert some test data
271+ old_db
272+ .simple_query(
306273 "
307274 INSERT INTO users (id, name) VALUES
308275 (1, 'John Doe'),
@@ -310,69 +277,97 @@ fn alter_column_rename() {
310277 ",
311278 )
312279 .unwrap();
313− });
314280
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− });
281+ // Run second migration
282+ reshape.migrate(second_migrations.clone()).unwrap();
283+ new_db
284+ .simple_query(&reshape::schema_query_for_migration(
285+ &second_migrations.last().unwrap().name,
286+ ))
287+ .unwrap();
325288
326− test.run();
289+ // Check that existing values can be queried using new column name
290+ let expected = vec!["John Doe", "Jane Doe"];
291+ assert!(new_db
292+ .query("SELECT full_name FROM users ORDER BY id", &[],)
293+ .unwrap()
294+ .iter()
295+ .map(|row| row.get::<_, String>("full_name"))
296+ .eq(expected));
297+
298+ reshape.complete_migration().unwrap();
327299}
328300
329301#[test]
330302fn 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− "#,
303+ let (mut reshape, mut old_db, mut new_db) = common::setup();
304+
305+ let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
306+ name: "users".to_string(),
307+ primary_key: vec!["id".to_string()],
308+ foreign_keys: vec![],
309+ columns: vec![
310+ Column {
311+ name: "id".to_string(),
312+ data_type: "INTEGER".to_string(),
313+ nullable: true,
314+ default: None,
315+ generated: None,
316+ },
317+ Column {
318+ name: "counter".to_string(),
319+ data_type: "INTEGER".to_string(),
320+ nullable: false,
321+ default: None,
322+ generated: None,
323+ },
324+ ],
325+ });
326+ let increment_counter_twice = Migration::new("increment_counter_twice", None)
327+ .with_action(AlterColumn {
328+ table: "users".to_string(),
329+ column: "counter".to_string(),
330+ up: Some("counter + 1".to_string()),
331+ down: Some("counter - 1".to_string()),
332+ changes: ColumnChanges {
333+ data_type: None,
334+ nullable: None,
335+ name: None,
336+ },
337+ })
338+ .with_action(AlterColumn {
339+ table: "users".to_string(),
340+ column: "counter".to_string(),
341+ up: Some("counter + 1".to_string()),
342+ down: Some("counter - 1".to_string()),
343+ changes: ColumnChanges {
344+ data_type: None,
345+ nullable: None,
346+ name: None,
347+ },
348+ });
349+
350+ let first_migrations = vec![create_users_table.clone()];
351+ let second_migrations = vec![create_users_table.clone(), increment_counter_twice.clone()];
352+
353+ // Run first migration, should automatically finish
354+ reshape.migrate(first_migrations.clone()).unwrap();
355+ assert!(matches!(reshape.state.status, Status::Idle));
356+ assert_eq!(
357+ Some(&create_users_table.name),
358+ reshape.state.current_migration.as_ref()
351359 );
352360
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− "#,
371− );
361+ // Update search paths
362+ old_db
363+ .simple_query(&reshape::schema_query_for_migration(
364+ &first_migrations.last().unwrap().name,
365+ ))
366+ .unwrap();
372367
373− test.after_first(|db| {
374− // Insert some test data
375− db.simple_query(
368+ // Insert some test data
369+ old_db
370+ .simple_query(
376371 "
377372 INSERT INTO users (id, counter) VALUES
378373 (1, 0),
@@ -380,355 +375,48 @@ fn alter_column_multiple() {
380375 ",
381376 )
382377 .unwrap();
383− });
384−
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− });
422−
423− test.run();
424−}
425−
426−#[test]
427−fn 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− "#,
463− );
464378
465− test.after_first(|db| {
466− // Insert a test user
467− db.simple_query(
468− "
469− INSERT INTO users (id) VALUES (1)
470− ",
471− )
379+ // Run second migration
380+ reshape.migrate(second_migrations.clone()).unwrap();
381+ new_db
382+ .simple_query(&reshape::schema_query_for_migration(
383+ &second_migrations.last().unwrap().name,
384+ ))
472385 .unwrap();
473− });
474−
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− });
503−
504− test.run();
505−}
506−
507−#[test]
508−fn 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"
527−
528− [[actions.columns]]
529− name = "last_name"
530− type = "TEXT"
531−
532− [[actions]]
533− type = "add_index"
534− table = "users"
535−
536− [actions.index]
537− name = "users_name_idx"
538− columns = ["first_name", "last_name"]
539− "#,
540− );
541−
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− );
554−
555− test.after_completion(|db| {
556− // Make sure index still exists
557− let result: i64 = db
558− .query(
559− "
560− SELECT COUNT(*)
561− FROM pg_catalog.pg_index
562− JOIN pg_catalog.pg_class ON pg_index.indexrelid = pg_class.oid
563− WHERE pg_class.relname = 'users_name_idx'
564− ",
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− );
699386
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− });
387+ // Check that the existing data has been updated
388+ let expected = vec![2, 102];
389+ let results: Vec<i32> = new_db
390+ .query("SELECT counter FROM users ORDER BY id", &[])
391+ .unwrap()
392+ .iter()
393+ .map(|row| row.get::<_, i32>("counter"))
394+ .collect();
395+ assert_eq!(expected, results);
396+
397+ // Update data using old schema and make sure it was updated for the new schema
398+ old_db
399+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
400+ .unwrap();
401+ let result: i32 = new_db
402+ .query("SELECT counter FROM users WHERE id = 1", &[])
403+ .unwrap()
404+ .iter()
405+ .map(|row| row.get("counter"))
406+ .nth(0)
407+ .unwrap();
408+ assert_eq!(52, result);
732409
733− test.run();
410+ // Update data using new schema and make sure it was updated for the old schema
411+ new_db
412+ .query("UPDATE users SET counter = 50 WHERE id = 1", &[])
413+ .unwrap();
414+ let result: i32 = old_db
415+ .query("SELECT counter FROM users WHERE id = 1", &[])
416+ .unwrap()
417+ .iter()
418+ .map(|row| row.get("counter"))
419+ .nth(0)
420+ .unwrap();
421+ assert_eq!(48, result);
734422}