parent
155b2e6aa2
commit
8f06b69f5d
4 changed files with 137 additions and 12 deletions
|
@ -12,17 +12,25 @@ pub(crate) fn apply_sql(app: &App, cmd_opts: ApplyCommandOpt) -> StdResult<()> {
|
||||||
|
|
||||||
let migration_manager = MigrationManager::new();
|
let migration_manager = MigrationManager::new();
|
||||||
|
|
||||||
let file_path = {
|
let file_contents = cmd_opts
|
||||||
let mut file_path = config.directory_path().join(cmd_opts.file_name);
|
.file_paths
|
||||||
|
.into_iter()
|
||||||
|
.map(|file_path| {
|
||||||
|
let mut file_path = config.directory_path().join(file_path);
|
||||||
if file_path.extension().is_none() {
|
if file_path.extension().is_none() {
|
||||||
file_path.set_extension("sql");
|
file_path.set_extension("sql");
|
||||||
}
|
}
|
||||||
|
dbg!(&file_path);
|
||||||
file_path
|
file_path
|
||||||
};
|
})
|
||||||
|
.map(std::fs::read_to_string)
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let content = std::fs::read_to_string(file_path)?;
|
|
||||||
with_transaction(conn, &mut |conn| {
|
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(())
|
Ok(())
|
||||||
|
|
|
@ -176,7 +176,7 @@ impl Config {
|
||||||
Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(Vec::new()),
|
Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(Vec::new()),
|
||||||
entries => entries?
|
entries => entries?
|
||||||
.map(|res| res.map(|e| e.path()))
|
.map(|res| res.map(|e| e.path()))
|
||||||
.collect::<Result<Vec<_>, io::Error>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
if entries.is_empty() {
|
if entries.is_empty() {
|
||||||
|
|
|
@ -34,8 +34,8 @@ pub(crate) enum Command {
|
||||||
|
|
||||||
#[derive(Debug, StructOpt, Clone)]
|
#[derive(Debug, StructOpt, Clone)]
|
||||||
pub(crate) struct ApplyCommandOpt {
|
pub(crate) struct ApplyCommandOpt {
|
||||||
#[structopt(parse(from_str))]
|
#[structopt(parse(from_os_str), required = true)]
|
||||||
pub file_name: String,
|
pub file_paths: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, StructOpt, Clone)]
|
#[derive(Debug, StructOpt, Clone)]
|
||||||
|
|
|
@ -448,3 +448,120 @@ mod upgrade {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod apply {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn apply_files() -> TestResult {
|
||||||
|
fn inner<ValidateFn>(
|
||||||
|
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<(i32, i32)>>(),
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in a new issue