diff --git a/migra-cli/src/commands/apply.rs b/migra-cli/src/commands/apply.rs index b71c314..538cc6d 100644 --- a/migra-cli/src/commands/apply.rs +++ b/migra-cli/src/commands/apply.rs @@ -12,17 +12,24 @@ pub(crate) fn apply_sql(app: &App, cmd_opts: ApplyCommandOpt) -> StdResult<()> { let migration_manager = MigrationManager::new(); - let file_path = { - let mut file_path = config.directory_path().join(cmd_opts.file_name); - if file_path.extension().is_none() { - file_path.set_extension("sql"); - } - file_path - }; + let file_contents = cmd_opts + .file_paths + .into_iter() + .map(|file_path| { + let mut file_path = config.directory_path().join(file_path); + if file_path.extension().is_none() { + file_path.set_extension("sql"); + } + file_path + }) + .map(std::fs::read_to_string) + .collect::, _>>()?; - let content = std::fs::read_to_string(file_path)?; with_transaction(conn, &mut |conn| { - migration_manager.apply_sql(conn, &content) + file_contents + .iter() + .try_for_each(|content| migration_manager.apply_sql(conn, content))?; + Ok(()) })?; Ok(()) diff --git a/migra-cli/src/config.rs b/migra-cli/src/config.rs index 2f3c609..c5e534d 100644 --- a/migra-cli/src/config.rs +++ b/migra-cli/src/config.rs @@ -176,7 +176,7 @@ impl Config { Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(Vec::new()), entries => entries? .map(|res| res.map(|e| e.path())) - .collect::, io::Error>>()?, + .collect::, _>>()?, }; if entries.is_empty() { diff --git a/migra-cli/src/opts.rs b/migra-cli/src/opts.rs index 8652099..53b13ed 100644 --- a/migra-cli/src/opts.rs +++ b/migra-cli/src/opts.rs @@ -34,8 +34,8 @@ pub(crate) enum Command { #[derive(Debug, StructOpt, Clone)] pub(crate) struct ApplyCommandOpt { - #[structopt(parse(from_str))] - pub file_name: String, + #[structopt(parse(from_os_str), required = true)] + pub file_paths: Vec, } #[derive(Debug, StructOpt, Clone)] diff --git a/migra-cli/tests/commands.rs b/migra-cli/tests/commands.rs index 4e39b23..b2d0399 100644 --- a/migra-cli/tests/commands.rs +++ b/migra-cli/tests/commands.rs @@ -448,3 +448,120 @@ mod upgrade { Ok(()) } } + +mod apply { + use super::*; + + #[test] + fn apply_files() -> TestResult { + fn inner( + database_name: &'static str, + file_paths: Vec<&'static str>, + validate: ValidateFn, + ) -> TestResult + where + ValidateFn: Fn() -> TestResult, + { + let manifest_path = database_manifest_path(database_name); + + Command::cargo_bin("migra")? + .arg("-c") + .arg(&manifest_path) + .arg("apply") + .args(file_paths) + .assert() + .success(); + + validate()?; + + Ok(()) + } + + cfg_if! { + if #[cfg(feature = "postgres")] { + inner( + "postgres", + vec![ + "migrations/210218232851_create_articles/up", + "migrations/210218233414_create_persons/up", + ], + || { + let mut conn = postgres::Client::connect(POSTGRES_URL, postgres::NoTls)?; + let res = conn.query("SELECT p.id, a.id FROM persons AS p, articles AS a", &[])?; + + assert_eq!( + res.into_iter() + .map(|row| (row.get(0), row.get(1))) + .collect::>(), + Vec::new() + ); + + Ok(()) + }, + )?; + + inner( + "postgres", + vec![ + "migrations/210218233414_create_persons/down", + "migrations/210218232851_create_articles/down", + ], + || { + let mut conn = postgres::Client::connect(POSTGRES_URL, postgres::NoTls)?; + let res = conn.query("SELECT p.id, a.id FROM persons AS p, articles AS a", &[]); + + assert!(res.is_err()); + + Ok(()) + }, + )?; + } + } + + cfg_if! { + if #[cfg(feature = "mysql")] { + inner( + "mysql", + vec![ + "migrations/210218232851_create_articles/up", + "migrations/210218233414_create_persons/up", + ], + || { + use mysql::prelude::*; + + let pool = mysql::Pool::new(MYSQL_URL)?; + let mut conn = pool.get_conn()?; + + let res = conn.query_drop("SELECT p.id, a.id FROM persons AS p, articles AS a")?; + + assert_eq!(res, ()); + + Ok(()) + }, + )?; + + inner( + "mysql", + vec![ + "migrations/210218233414_create_persons/down", + "migrations/210218232851_create_articles/down", + ], + || { + use mysql::prelude::*; + + let pool = mysql::Pool::new(MYSQL_URL)?; + let mut conn = pool.get_conn()?; + + let res = conn.query_drop("SELECT p.id, a.id FROM persons AS p, articles AS a"); + + assert!(res.is_err()); + + Ok(()) + } + )?; + } + } + + Ok(()) + } +}