use super::*;
use std::fs;
use std::path::Path;
#[cfg(feature = "d-sqlite")]
use rusqlite::Connection;
use std::io::Read;
#[cfg(not(feature = "d-sqlite"))]
mod m {
use super::*;
pub fn create_file_if_missing(path: &Path) -> Result<bool> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
pub fn migration_table_exists(db_path: &str) -> Result<bool> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
pub fn migration_setup(db_path: &Path) -> Result<bool> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
pub fn select_migrations(db_path: &str) -> Result<Vec<String>> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
pub fn insert_migration_tag(db_path: &str, tag: &str) -> Result<()> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
pub fn remove_migration_tag(db_path: &str, tag: &str) -> Result<()> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
pub fn run_migration(db_path: &Path, filename: &Path) -> Result<()> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
pub fn run_migration_str(db_path: &Path, stmt: &str) -> Result<()> {
unimplemented!("migrant_lib: must enable d-sqlite feature");
}
}
#[cfg(feature = "d-sqlite")]
mod m {
use super::*;
pub fn create_file_if_missing(path: &Path) -> Result<bool> {
if path == Path::new(":memory:") || path.exists() {
Ok(false)
} else {
let db_dir = path.parent().ok_or_else(|| {
format_err!(
ErrorKind::PathError,
"Unable to determine parent path: {:?}",
path
)
})?;
fs::create_dir_all(db_dir)
.chain_err(|| format!("Failed creating database directory: {:?}", db_dir))?;
fs::File::create(path)
.chain_err(|| format!("Failed creating database file: {:?}", path))?;
Ok(true)
}
}
pub fn migration_table_exists(db_path: &str) -> Result<bool> {
let conn = Connection::open(db_path)?;
let exists: bool =
conn.query_row(sql::SQLITE_MIGRATION_TABLE_EXISTS, [], |row| row.get(0))?;
Ok(exists)
}
pub fn migration_setup(db_path: &Path) -> Result<bool> {
let db_path = db_path.to_str().unwrap();
if !migration_table_exists(db_path)? {
let conn = Connection::open(db_path)?;
conn.execute(sql::CREATE_TABLE, [])?;
return Ok(true);
}
Ok(false)
}
pub fn select_migrations(db_path: &str) -> Result<Vec<String>> {
let conn = Connection::open(db_path)?;
let mut stmt = conn.prepare(sql::GET_MIGRATIONS)?;
let mut rows = stmt.query([])?;
let mut migs = vec![];
while let Some(row) = rows.next()? {
migs.push(row.get(0)?);
}
Ok(migs)
}
pub fn insert_migration_tag(db_path: &str, tag: &str) -> Result<()> {
let conn = Connection::open(db_path)?;
conn.execute(
"insert into __migrant_migrations (tag) values ($1)",
&[&tag],
)?;
Ok(())
}
pub fn remove_migration_tag(db_path: &str, tag: &str) -> Result<()> {
let conn = Connection::open(db_path)?;
conn.execute("delete from __migrant_migrations where tag = $1", &[&tag])?;
Ok(())
}
pub fn run_migration(db_path: &Path, filename: &Path) -> Result<()> {
let mut file = fs::File::open(filename)?;
let mut buf = String::new();
file.read_to_string(&mut buf)?;
if buf.is_empty() {
return Ok(());
}
let conn =
Connection::open(db_path).map_err(|e| format_err!(ErrorKind::Migration, "{}", e))?;
conn.execute_batch(&buf)
.map_err(|e| format_err!(ErrorKind::Migration, "{}", e))?;
Ok(())
}
pub fn run_migration_str(db_path: &Path, stmt: &str) -> Result<()> {
if stmt.is_empty() {
return Ok(());
}
let conn =
Connection::open(db_path).map_err(|e| format_err!(ErrorKind::Migration, "{}", e))?;
conn.execute_batch(stmt)
.map_err(|e| format_err!(ErrorKind::Migration, "{}", e))?;
Ok(())
}
}
pub use self::m::*;
#[cfg(feature = "d-sqlite")]
#[cfg(test)]
mod test {
use super::*;
use std;
macro_rules! _try {
($exp:expr) => {
match $exp {
Ok(v) => v,
Err(e) => {
eprintln!("Caught: {}", e);
panic!("{}", e)
}
}
};
}
#[test]
fn sqlite() {
let conn_str =
std::env::var("SQLITE_TEST_CONN_STR").expect("SQLITE_TEST_CONN_STR env var required");
let path = std::path::Path::new(&conn_str);
let is_setup = _try!(migration_table_exists(&conn_str));
assert!(!is_setup, "Assert migration table does not exist");
let was_setup = _try!(migration_setup(path));
assert!(
was_setup,
"Assert `migration_setup` initializes migration table"
);
let was_setup = _try!(migration_setup(path));
assert!(!was_setup, "Assert `migration_setup` is idempotent");
let is_setup = _try!(migration_table_exists(&conn_str));
assert!(is_setup, "Assert migration table exists");
_try!(insert_migration_tag(&conn_str, "initial"));
_try!(insert_migration_tag(&conn_str, "alter1"));
_try!(insert_migration_tag(&conn_str, "alter2"));
let migs = _try!(select_migrations(&conn_str));
assert_eq!(3, migs.len(), "Assert 3 migrations applied");
_try!(remove_migration_tag(&conn_str, "alter2"));
let migs = _try!(select_migrations(&conn_str));
assert_eq!(2, migs.len(), "Assert 2 migrations applied");
_try!(remove_migration_tag(&conn_str, "alter1"));
_try!(remove_migration_tag(&conn_str, "initial"));
let migs = _try!(select_migrations(&conn_str));
assert_eq!(0, migs.len(), "Assert all migrations removed");
}
}