Add builder for create_table migration

The builder will help simplify the tests and avoid boilerplate updates
when need fields are added to the create_table migration. We might want
to add builders all migrations later.
This commit is contained in:
fabianlindfors 2022-01-10 21:59:20 +01:00
parent 435a40695a
commit c76ea1fba6
11 changed files with 197 additions and 192 deletions

View File

@ -19,4 +19,5 @@ anyhow = { version = "1.0.44", features = ["backtrace"] }
clap = { version = "3.0.0", features = ["derive"] } clap = { version = "3.0.0", features = ["derive"] }
toml = "0.5" toml = "0.5"
version = "3.0.0" version = "3.0.0"
colored = "2" colored = "2"
"derive_builder" = "0.10.2"

View File

@ -1,9 +1,11 @@
use derive_builder::Builder;
use postgres::types::{FromSql, ToSql}; use postgres::types::{FromSql, ToSql};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::db::Conn; use crate::db::Conn;
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Builder, Clone, Debug)]
#[builder(setter(into))]
pub struct Column { pub struct Column {
pub name: String, pub name: String,
@ -11,10 +13,13 @@ pub struct Column {
pub data_type: String, pub data_type: String,
#[serde(default = "nullable_default")] #[serde(default = "nullable_default")]
#[builder(default = "true")]
pub nullable: bool, pub nullable: bool,
#[builder(setter(name = "default_value", strip_option), default)]
pub default: Option<String>, pub default: Option<String>,
#[builder(setter(strip_option), default)]
pub generated: Option<String>, pub generated: Option<String>,
} }

View File

@ -1,18 +1,22 @@
use super::{Action, Column, MigrationContext}; use super::{Action, Column, MigrationContext};
use crate::{db::Conn, schema::Schema}; use crate::{db::Conn, schema::Schema};
use anyhow::Context; use anyhow::Context;
use derive_builder::Builder;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Builder, Debug)]
#[builder(setter(into))]
pub struct CreateTable { pub struct CreateTable {
pub name: String, pub name: String,
pub columns: Vec<Column>, pub columns: Vec<Column>,
pub primary_key: Vec<String>, pub primary_key: Vec<String>,
#[serde(default)] #[serde(default)]
#[builder(default)]
pub foreign_keys: Vec<ForeignKey>, pub foreign_keys: Vec<ForeignKey>,
} }
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct ForeignKey { pub struct ForeignKey {
pub columns: Vec<String>, pub columns: Vec<String>,
pub referenced_table: String, pub referenced_table: String,

View File

@ -4,10 +4,10 @@ use serde::{Deserialize, Serialize};
// Re-export migration types // Re-export migration types
mod common; mod common;
pub use common::Column; pub use common::{Column, ColumnBuilder};
mod create_table; mod create_table;
pub use create_table::{CreateTable, ForeignKey}; pub use create_table::{CreateTable, CreateTableBuilder, ForeignKey};
mod alter_column; mod alter_column;
pub use alter_column::{AlterColumn, ColumnChanges}; pub use alter_column::{AlterColumn, ColumnChanges};

View File

@ -1,4 +1,4 @@
use reshape::migrations::{AddColumn, Column, CreateTable, Migration}; use reshape::migrations::{AddColumn, Column, ColumnBuilder, CreateTableBuilder, Migration};
use reshape::Status; use reshape::Status;
mod common; mod common;
@ -7,27 +7,26 @@ mod common;
fn add_column() { fn add_column() {
let (mut reshape, mut old_db, mut new_db) = common::setup(); let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable { let create_users_table = Migration::new("create_user_table", None).with_action(
name: "users".to_string(), CreateTableBuilder::default()
primary_key: vec!["id".to_string()], .name("users")
foreign_keys: vec![], .primary_key(vec!["id".to_string()])
columns: vec![ .columns(vec![
Column { ColumnBuilder::default()
name: "id".to_string(), .name("id")
data_type: "SERIAL".to_string(), .data_type("INTEGER")
nullable: true, .build()
default: None, .unwrap(),
generated: None, ColumnBuilder::default()
}, .name("name")
Column { .data_type("TEXT")
name: "name".to_string(), .build()
data_type: "TEXT".to_string(), .unwrap(),
nullable: false, ])
default: None, .build()
generated: None, .unwrap(),
}, );
],
});
let add_first_last_name_columns = Migration::new("add_first_and_last_name_columns", None) let add_first_last_name_columns = Migration::new("add_first_and_last_name_columns", None)
.with_action(AddColumn { .with_action(AddColumn {
table: "users".to_string(), table: "users".to_string(),
@ -127,18 +126,18 @@ fn add_column() {
fn add_column_nullable() { fn add_column_nullable() {
let (mut reshape, mut old_db, mut new_db) = common::setup(); let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable { let create_users_table = Migration::new("create_user_table", None).with_action(
name: "users".to_string(), CreateTableBuilder::default()
primary_key: vec!["id".to_string()], .name("users")
foreign_keys: vec![], .primary_key(vec!["id".to_string()])
columns: vec![Column { .columns(vec![ColumnBuilder::default()
name: "id".to_string(), .name("id")
data_type: "INTEGER".to_string(), .data_type("INTEGER")
nullable: true, .build()
default: None, .unwrap()])
generated: None, .build()
}], .unwrap(),
}); );
let add_name_column = Migration::new("add_nullable_name_column", None).with_action(AddColumn { let add_name_column = Migration::new("add_nullable_name_column", None).with_action(AddColumn {
table: "users".to_string(), table: "users".to_string(),
column: Column { column: Column {
@ -225,18 +224,18 @@ fn add_column_nullable() {
fn add_column_with_default() { fn add_column_with_default() {
let (mut reshape, mut old_db, mut new_db) = common::setup(); let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_users_table = Migration::new("create_users_table", None).with_action(CreateTable { let create_users_table = Migration::new("create_user_table", None).with_action(
name: "users".to_string(), CreateTableBuilder::default()
primary_key: vec!["id".to_string()], .name("users")
foreign_keys: vec![], .primary_key(vec!["id".to_string()])
columns: vec![Column { .columns(vec![ColumnBuilder::default()
name: "id".to_string(), .name("id")
data_type: "INTEGER".to_string(), .data_type("INTEGER")
nullable: true, .build()
default: None, .unwrap()])
generated: None, .build()
}], .unwrap(),
}); );
let add_name_column = let add_name_column =
Migration::new("add_name_column_with_default", None).with_action(AddColumn { Migration::new("add_name_column_with_default", None).with_action(AddColumn {
table: "users".to_string(), table: "users".to_string(),

View File

@ -1,4 +1,4 @@
use reshape::migrations::{AddIndex, Column, CreateTable, Migration}; use reshape::migrations::{AddIndex, ColumnBuilder, CreateTableBuilder, Migration};
mod common; mod common;
@ -6,28 +6,25 @@ mod common;
fn add_index() { fn add_index() {
let (mut reshape, mut old_db, mut new_db) = common::setup(); let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_table_migration = let create_table_migration = Migration::new("create_user_table", None).with_action(
Migration::new("create_users_table", None).with_action(CreateTable { CreateTableBuilder::default()
name: "users".to_string(), .name("users")
primary_key: vec!["id".to_string()], .primary_key(vec!["id".to_string()])
foreign_keys: vec![], .columns(vec![
columns: vec![ ColumnBuilder::default()
Column { .name("id")
name: "id".to_string(), .data_type("INTEGER")
data_type: "INTEGER".to_string(), .build()
nullable: true, .unwrap(),
default: None, ColumnBuilder::default()
generated: None, .name("name")
}, .data_type("TEXT")
Column { .build()
name: "name".to_string(), .unwrap(),
data_type: "TEXT".to_string(), ])
nullable: false, .build()
default: None, .unwrap(),
generated: None, );
},
],
});
let add_index_migration = Migration::new("add_name_index", None).with_action(AddIndex { let add_index_migration = Migration::new("add_name_index", None).with_action(AddIndex {
table: "users".to_string(), table: "users".to_string(),
name: "name_idx".to_string(), name: "name_idx".to_string(),

View File

@ -37,6 +37,7 @@ fn alter_column_data() {
data_type: None, data_type: None,
nullable: None, nullable: None,
name: None, name: None,
default: None,
}, },
}); });
@ -142,6 +143,7 @@ fn alter_column_set_not_null() {
data_type: None, data_type: None,
nullable: Some(false), nullable: Some(false),
name: None, name: None,
default: None,
}, },
}); });
@ -248,6 +250,7 @@ fn alter_column_rename() {
data_type: None, data_type: None,
nullable: None, nullable: None,
name: Some("full_name".to_string()), name: Some("full_name".to_string()),
default: None,
}, },
}); });
@ -336,6 +339,7 @@ fn alter_column_multiple() {
data_type: None, data_type: None,
nullable: None, nullable: None,
name: None, name: None,
default: None,
}, },
}) })
.with_action(AlterColumn { .with_action(AlterColumn {
@ -347,6 +351,7 @@ fn alter_column_multiple() {
data_type: None, data_type: None,
nullable: None, nullable: None,
name: None, name: None,
default: None,
}, },
}); });

View File

@ -1,5 +1,5 @@
use reshape::{ use reshape::{
migrations::{Column, CreateTable, ForeignKey, Migration}, migrations::{ColumnBuilder, CreateTableBuilder, ForeignKey, Migration},
Status, Status,
}; };
@ -9,35 +9,33 @@ mod common;
fn create_table() { fn create_table() {
let (mut reshape, mut db, _) = common::setup(); let (mut reshape, mut db, _) = common::setup();
let create_table_migration = let create_table_migration = Migration::new("create_users_table", None).with_action(
Migration::new("create_users_table", None).with_action(CreateTable { CreateTableBuilder::default()
name: "users".to_string(), .name("users")
primary_key: vec!["id".to_string()], .primary_key(vec!["id".to_string()])
foreign_keys: vec![], .columns(vec![
columns: vec![ ColumnBuilder::default()
Column { .name("id")
name: "id".to_string(), .data_type("INTEGER")
data_type: "INTEGER".to_string(), .generated("ALWAYS AS IDENTITY")
nullable: true, .build()
default: None, .unwrap(),
generated: Some("ALWAYS AS IDENTITY".to_string()), ColumnBuilder::default()
}, .name("name")
Column { .data_type("TEXT")
name: "name".to_string(), .build()
data_type: "TEXT".to_string(), .unwrap(),
nullable: true, ColumnBuilder::default()
default: None, .name("created_at")
generated: None, .data_type("TIMESTAMP")
}, .nullable(false)
Column { .default_value("NOW()")
name: "created_at".to_string(), .build()
data_type: "TIMESTAMP".to_string(), .unwrap(),
nullable: false, ])
default: Some("NOW()".to_string()), .build()
generated: None, .unwrap(),
}, );
],
});
reshape reshape
.migrate(vec![create_table_migration.clone()]) .migrate(vec![create_table_migration.clone()])
@ -127,46 +125,46 @@ fn create_table() {
fn create_table_with_foreign_keys() { fn create_table_with_foreign_keys() {
let (mut reshape, mut db, _) = common::setup(); let (mut reshape, mut db, _) = common::setup();
let create_table_migration = let create_table_migration = Migration::new("create_users_table", None).with_action(
Migration::new("create_users_table", None).with_action(CreateTable { CreateTableBuilder::default()
name: "users".to_string(), .name("users")
primary_key: vec!["id".to_string()], .primary_key(vec!["id".to_string()])
foreign_keys: vec![], .columns(vec![ColumnBuilder::default()
columns: vec![Column { .name("id")
name: "id".to_string(), .data_type("INTEGER")
data_type: "SERIAL".to_string(), .generated("ALWAYS AS IDENTITY")
nullable: true, // Will be ignored by Postgres as the column is a SERIAL .build()
default: None, .unwrap()])
generated: None, .build()
}], .unwrap(),
}); );
let create_second_table_migration = let create_second_table_migration = Migration::new("create_items_table", None).with_action(
Migration::new("create_items_table", None).with_action(CreateTable { CreateTableBuilder::default()
name: "items".to_string(), .name("items")
primary_key: vec!["id".to_string()], .primary_key(vec!["id".to_string()])
foreign_keys: vec![ForeignKey { .foreign_keys(vec![ForeignKey {
columns: vec!["user_id".to_string()], columns: vec!["user_id".to_string()],
referenced_table: "users".to_string(), referenced_table: "users".to_string(),
referenced_columns: vec!["id".to_string()], referenced_columns: vec!["id".to_string()],
}], }])
columns: vec![ .columns(vec![
Column { ColumnBuilder::default()
name: "id".to_string(), .name("id")
data_type: "SERIAL".to_string(), .data_type("INTEGER")
nullable: true, .generated("ALWAYS AS IDENTITY")
default: None, .build()
generated: None, .unwrap(),
}, ColumnBuilder::default()
Column { .name("user_id")
name: "user_id".to_string(), .data_type("INTEGER")
data_type: "INTEGER".to_string(), .nullable(false)
nullable: false, .build()
default: None, .unwrap(),
generated: None, ])
}, .build()
], .unwrap(),
}); );
reshape reshape
.migrate(vec![ .migrate(vec![

View File

@ -1,4 +1,4 @@
use reshape::migrations::{Column, CreateTable, Migration, RemoveColumn}; use reshape::migrations::{ColumnBuilder, CreateTableBuilder, Migration, RemoveColumn};
mod common; mod common;
@ -6,28 +6,26 @@ mod common;
fn remove_column() { fn remove_column() {
let (mut reshape, mut old_db, mut new_db) = common::setup(); let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_table_migration = let create_table_migration = Migration::new("create_user_table", None).with_action(
Migration::new("create_users_table", None).with_action(CreateTable { CreateTableBuilder::default()
name: "users".to_string(), .name("users")
primary_key: vec!["id".to_string()], .primary_key(vec!["id".to_string()])
foreign_keys: vec![], .columns(vec![
columns: vec![ ColumnBuilder::default()
Column { .name("id")
name: "id".to_string(), .data_type("INTEGER")
data_type: "INTEGER".to_string(), .build()
nullable: true, .unwrap(),
default: None, ColumnBuilder::default()
generated: None, .name("name")
}, .data_type("TEXT")
Column { .nullable(false)
name: "name".to_string(), .build()
data_type: "TEXT".to_string(), .unwrap(),
nullable: false, ])
default: None, .build()
generated: None, .unwrap(),
}, );
],
});
let remove_column_migration = let remove_column_migration =
Migration::new("remove_name_column", None).with_action(RemoveColumn { Migration::new("remove_name_column", None).with_action(RemoveColumn {
table: "users".to_string(), table: "users".to_string(),

View File

@ -1,4 +1,4 @@
use reshape::migrations::{Column, CreateTable, Migration, RemoveTable}; use reshape::migrations::{ColumnBuilder, CreateTableBuilder, Migration, RemoveTable};
mod common; mod common;
@ -6,19 +6,18 @@ mod common;
fn remove_table() { fn remove_table() {
let (mut reshape, mut old_db, mut new_db) = common::setup(); let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_table_migration = let create_table_migration = Migration::new("create_user_table", None).with_action(
Migration::new("create_users_table", None).with_action(CreateTable { CreateTableBuilder::default()
name: "users".to_string(), .name("users")
primary_key: vec!["id".to_string()], .primary_key(vec!["id".to_string()])
foreign_keys: vec![], .columns(vec![ColumnBuilder::default()
columns: vec![Column { .name("id")
name: "id".to_string(), .data_type("INTEGER")
data_type: "INTEGER".to_string(), .build()
nullable: false, .unwrap()])
default: None, .build()
generated: None, .unwrap(),
}], );
});
let remove_table_migration = let remove_table_migration =
Migration::new("remove_users_table", None).with_action(RemoveTable { Migration::new("remove_users_table", None).with_action(RemoveTable {
table: "users".to_string(), table: "users".to_string(),

View File

@ -1,4 +1,4 @@
use reshape::migrations::{Column, CreateTable, Migration, RenameTable}; use reshape::migrations::{ColumnBuilder, CreateTableBuilder, Migration, RenameTable};
mod common; mod common;
@ -6,19 +6,18 @@ mod common;
fn rename_table() { fn rename_table() {
let (mut reshape, mut old_db, mut new_db) = common::setup(); let (mut reshape, mut old_db, mut new_db) = common::setup();
let create_table_migration = let create_table_migration = Migration::new("create_user_table", None).with_action(
Migration::new("create_users_table", None).with_action(CreateTable { CreateTableBuilder::default()
name: "users".to_string(), .name("users")
primary_key: vec!["id".to_string()], .primary_key(vec!["id".to_string()])
foreign_keys: vec![], .columns(vec![ColumnBuilder::default()
columns: vec![Column { .name("id")
name: "id".to_string(), .data_type("INTEGER")
data_type: "INTEGER".to_string(), .build()
nullable: false, .unwrap()])
default: None, .build()
generated: None, .unwrap(),
}], );
});
let rename_table_migration = Migration::new("rename_users_table_to_customers", None) let rename_table_migration = Migration::new("rename_users_table_to_customers", None)
.with_action(RenameTable { .with_action(RenameTable {
table: "users".to_string(), table: "users".to_string(),