reshape/tests/alter_column.rs

397 lines
12 KiB
Rust
Raw Normal View History

2021-10-19 17:32:37 +03:00
use reshape::migrations::{AlterColumn, Column, ColumnChanges, CreateTable, Migration};
use reshape::Status;
mod common;
#[test]
fn alter_column_data() {
let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
name: "users".to_string(),
primary_key: vec!["id".to_string()],
foreign_keys: vec![],
2021-10-19 17:32:37 +03:00
columns: vec![
Column {
name: "id".to_string(),
data_type: "INTEGER".to_string(),
2021-10-19 17:32:37 +03:00
nullable: true,
default: None,
generated: None,
2021-10-19 17:32:37 +03:00
},
Column {
name: "name".to_string(),
data_type: "TEXT".to_string(),
nullable: false,
default: None,
generated: None,
2021-10-19 17:32:37 +03:00
},
],
});
let uppercase_name = Migration::new("uppercase_name", None).with_action(AlterColumn {
table: "users".to_string(),
column: "name".to_string(),
up: Some("UPPER(name)".to_string()),
down: Some("LOWER(name)".to_string()),
changes: ColumnChanges {
data_type: None,
nullable: None,
name: None,
},
});
let first_migrations = vec![create_users_table.clone()];
let second_migrations = vec![create_users_table.clone(), uppercase_name.clone()];
// Run first migration, should automatically finish
reshape.migrate(first_migrations.clone()).unwrap();
assert!(matches!(reshape.state.status, Status::Idle));
assert_eq!(
Some(&create_users_table.name),
reshape.state.current_migration.as_ref()
);
// Update search paths
old_db
2021-11-11 22:47:07 +03:00
.simple_query(&reshape::schema_query_for_migration(
2021-10-19 17:32:37 +03:00
&first_migrations.last().unwrap().name,
))
.unwrap();
// Insert some test users
old_db
.simple_query(
"
INSERT INTO users (id, name) VALUES
(1, 'john Doe'),
(2, 'jane Doe');
",
)
.unwrap();
// Run second migration
reshape.migrate(second_migrations.clone()).unwrap();
new_db
2021-11-11 22:47:07 +03:00
.simple_query(&reshape::schema_query_for_migration(
2021-10-19 17:32:37 +03:00
&second_migrations.last().unwrap().name,
))
.unwrap();
// Check that the existing users has the altered data
let expected = vec!["JOHN DOE", "JANE DOE"];
assert!(new_db
.query("SELECT name FROM users ORDER BY id", &[],)
.unwrap()
.iter()
.map(|row| row.get::<_, String>("name"))
.eq(expected));
// Insert data using old schema and make sure the new schema gets correct values
old_db
.simple_query("INSERT INTO users (id, name) VALUES (3, 'test testsson')")
.unwrap();
let result = new_db
.query_one("SELECT name from users WHERE id = 3", &[])
.unwrap();
assert_eq!("TEST TESTSSON", result.get::<_, &str>("name"));
// Insert data using new schema and make sure the old schema gets correct values
new_db
.simple_query("INSERT INTO users (id, name) VALUES (4, 'TEST TESTSSON')")
.unwrap();
let result = old_db
.query_one("SELECT name from users WHERE id = 4", &[])
.unwrap();
assert_eq!("test testsson", result.get::<_, &str>("name"));
reshape.complete_migration().unwrap();
}
#[test]
fn alter_column_set_not_null() {
let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
name: "users".to_string(),
primary_key: vec!["id".to_string()],
foreign_keys: vec![],
2021-10-19 17:32:37 +03:00
columns: vec![
Column {
name: "id".to_string(),
data_type: "INTEGER".to_string(),
2021-10-19 17:32:37 +03:00
nullable: true,
default: None,
generated: None,
2021-10-19 17:32:37 +03:00
},
Column {
name: "name".to_string(),
data_type: "TEXT".to_string(),
nullable: true,
default: None,
generated: None,
2021-10-19 17:32:37 +03:00
},
],
});
let set_name_not_null = Migration::new("set_name_not_null", None).with_action(AlterColumn {
table: "users".to_string(),
column: "name".to_string(),
up: Some("COALESCE(name, 'TEST_DEFAULT_VALUE')".to_string()),
down: Some("name".to_string()),
changes: ColumnChanges {
data_type: None,
nullable: Some(false),
name: None,
},
});
let first_migrations = vec![create_users_table.clone()];
let second_migrations = vec![create_users_table.clone(), set_name_not_null.clone()];
// Run first migration, should automatically finish
reshape.migrate(first_migrations.clone()).unwrap();
assert!(matches!(reshape.state.status, Status::Idle));
assert_eq!(
Some(&create_users_table.name),
reshape.state.current_migration.as_ref()
);
// Update search paths
old_db
2021-11-11 22:47:07 +03:00
.simple_query(&reshape::schema_query_for_migration(
2021-10-19 17:32:37 +03:00
&first_migrations.last().unwrap().name,
))
.unwrap();
// Insert some test users
old_db
.simple_query(
"
INSERT INTO users (id, name) VALUES
(1, 'John Doe'),
(2, NULL);
",
)
.unwrap();
// Run second migration
reshape.migrate(second_migrations.clone()).unwrap();
new_db
2021-11-11 22:47:07 +03:00
.simple_query(&reshape::schema_query_for_migration(
2021-10-19 17:32:37 +03:00
&second_migrations.last().unwrap().name,
))
.unwrap();
// Check that existing users got the correct values
let expected = vec!["John Doe", "TEST_DEFAULT_VALUE"];
assert!(new_db
.query("SELECT name FROM users ORDER BY id", &[],)
.unwrap()
.iter()
.map(|row| row.get::<_, String>("name"))
.eq(expected));
// Insert data using old schema and make sure the new schema gets correct values
old_db
.simple_query("INSERT INTO users (id, name) VALUES (3, NULL)")
.unwrap();
let result = new_db
.query_one("SELECT name from users WHERE id = 3", &[])
.unwrap();
assert_eq!("TEST_DEFAULT_VALUE", result.get::<_, &str>("name"));
// Insert data using new schema and make sure the old schema gets correct values
new_db
.simple_query("INSERT INTO users (id, name) VALUES (4, 'Jane Doe')")
.unwrap();
let result = old_db
.query_one("SELECT name from users WHERE id = 4", &[])
.unwrap();
assert_eq!("Jane Doe", result.get::<_, &str>("name"));
reshape.complete_migration().unwrap();
}
#[test]
fn alter_column_rename() {
let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
name: "users".to_string(),
primary_key: vec!["id".to_string()],
foreign_keys: vec![],
2021-10-19 17:32:37 +03:00
columns: vec![
Column {
name: "id".to_string(),
data_type: "INTEGER".to_string(),
2021-10-19 17:32:37 +03:00
nullable: true,
default: None,
generated: None,
2021-10-19 17:32:37 +03:00
},
Column {
name: "name".to_string(),
data_type: "TEXT".to_string(),
nullable: true,
default: None,
generated: None,
2021-10-19 17:32:37 +03:00
},
],
});
let rename_to_full_name =
Migration::new("rename_to_full_name", None).with_action(AlterColumn {
table: "users".to_string(),
column: "name".to_string(),
up: None, // up and down are not required when only renaming a column
down: None,
changes: ColumnChanges {
data_type: None,
nullable: None,
name: Some("full_name".to_string()),
},
});
let first_migrations = vec![create_users_table.clone()];
let second_migrations = vec![create_users_table.clone(), rename_to_full_name.clone()];
// Run first migration, should automatically finish
reshape.migrate(first_migrations.clone()).unwrap();
assert!(matches!(reshape.state.status, Status::Idle));
assert_eq!(
Some(&create_users_table.name),
reshape.state.current_migration.as_ref()
);
// Update search paths
old_db
2021-11-11 22:47:07 +03:00
.simple_query(&reshape::schema_query_for_migration(
2021-10-19 17:32:37 +03:00
&first_migrations.last().unwrap().name,
))
.unwrap();
// Insert some test data
old_db
.simple_query(
"
INSERT INTO users (id, name) VALUES
(1, 'John Doe'),
(2, 'Jane Doe');
",
)
.unwrap();
// Run second migration
reshape.migrate(second_migrations.clone()).unwrap();
new_db
2021-11-11 22:47:07 +03:00
.simple_query(&reshape::schema_query_for_migration(
2021-10-19 17:32:37 +03:00
&second_migrations.last().unwrap().name,
))
.unwrap();
// Check that existing values can be queried using new column name
let expected = vec!["John Doe", "Jane Doe"];
assert!(new_db
.query("SELECT full_name FROM users ORDER BY id", &[],)
.unwrap()
.iter()
.map(|row| row.get::<_, String>("full_name"))
.eq(expected));
reshape.complete_migration().unwrap();
}
#[test]
fn alter_column_multiple() {
let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable {
name: "users".to_string(),
primary_key: vec!["id".to_string()],
foreign_keys: vec![],
columns: vec![
Column {
name: "id".to_string(),
data_type: "INTEGER".to_string(),
nullable: true,
default: None,
generated: None,
},
Column {
name: "counter".to_string(),
data_type: "INTEGER".to_string(),
nullable: false,
default: None,
generated: None,
},
],
});
let increment_counter_twice = Migration::new("increment_counter_twice", None)
.with_action(AlterColumn {
table: "users".to_string(),
column: "counter".to_string(),
up: Some("counter + 1".to_string()),
down: Some("counter - 1".to_string()),
changes: ColumnChanges {
data_type: None,
nullable: None,
name: None,
},
})
.with_action(AlterColumn {
table: "users".to_string(),
column: "counter".to_string(),
up: Some("counter + 1".to_string()),
down: Some("counter - 1".to_string()),
changes: ColumnChanges {
data_type: None,
nullable: None,
name: None,
},
});
let first_migrations = vec![create_users_table.clone()];
let second_migrations = vec![create_users_table.clone(), increment_counter_twice.clone()];
// Run first migration, should automatically finish
reshape.migrate(first_migrations.clone()).unwrap();
assert!(matches!(reshape.state.status, Status::Idle));
assert_eq!(
Some(&create_users_table.name),
reshape.state.current_migration.as_ref()
);
// Update search paths
old_db
.simple_query(&reshape::schema_query_for_migration(
&first_migrations.last().unwrap().name,
))
.unwrap();
// Insert some test data
old_db
.simple_query(
"
INSERT INTO users (id, counter) VALUES
(1, 0),
(2, 100);
",
)
.unwrap();
// Run second migration
reshape.migrate(second_migrations.clone()).unwrap();
new_db
.simple_query(&reshape::schema_query_for_migration(
&second_migrations.last().unwrap().name,
))
.unwrap();
// Check that the existing data has been updated
let expected = vec![2, 102];
let results: Vec<i32> = new_db
.query("SELECT counter FROM users ORDER BY id", &[])
.unwrap()
.iter()
.map(|row| row.get::<_, i32>("counter"))
.collect();
assert_eq!(expected, results);
}