use anyhow::{Result, bail};
use crate::{cargo, generator, naming, project, templates, timestamp};
pub const DIR: &str = "database/migrations";
#[derive(Debug, Clone, Copy)]
pub enum Action<'a> {
Generate { name: &'a str },
Apply,
Status,
Reset { force: bool },
}
pub fn run(action: Action) -> Result<()> {
let root = project::find_root()?;
if let Action::Generate { name } = action {
naming::validate_migration_name(name)?;
let file = format!(
"{DIR}/{}_{name}.surql",
timestamp::next_migration_prefix(&root.join(DIR))?
);
let contents = templates::render(templates::MIGRATION, &[("name", name)]);
generator::write_file(&root.join(&file), &contents, false)?;
println!(" created {file}");
println!("\nWrite the SurrealQL, then apply it with `slave migrate`.");
return Ok(());
}
if !root.join("src/bin/migrate.rs").is_file() {
bail!("src/bin/migrate.rs not found; migrations need the layout created by `slave new`");
}
let mut args = vec!["run", "--quiet", "--bin", "migrate", "--"];
let command_name = match action {
Action::Apply => {
args.push("apply");
"slave migrate"
}
Action::Status => {
args.push("status");
"slave migrate:status"
}
Action::Reset { force } => {
args.push("fresh");
if force {
args.push("--force");
}
"slave migrate:fresh"
}
Action::Generate { .. } => unreachable!("handled above"),
};
let status = cargo::run(&root, &args, &[])?;
if !status.success() {
bail!("`{command_name}` did not complete successfully");
}
Ok(())
}