use anyhow::Context; use clap::Command; use migrate::MigratorTrait; use sea_orm::{Database, DatabaseConnection}; #[tokio::main] async fn main() -> anyhow::Result<()> { dotenvy::dotenv().ok(); config::AppConfig::load(); let cmd = Command::new("migrate") .about("Database migration CLI") .arg( clap::Arg::new("steps") .help("Number of migrations (for up/down)") .required(false) .index(1), ) .subcommand(Command::new("up").about("Apply pending migrations")) .subcommand(Command::new("down").about("Revert applied migrations")) .subcommand(Command::new("fresh").about("Drop all tables and re-apply")) .subcommand(Command::new("refresh").about("Revert all then re-apply")) .subcommand(Command::new("reset").about("Revert all applied migrations")) .subcommand(Command::new("status").about("Show migration status")) .try_get_matches() .map_err(|e| anyhow::anyhow!("{}", e))?; let db_url = config::AppConfig::load().database_url()?; let db: DatabaseConnection = Database::connect(&db_url).await?; match cmd.subcommand_name() { Some("up") => { let steps = cmd .get_one::("steps") .and_then(|s| s.parse().ok()) .unwrap_or(0); run_up(&db, steps).await?; } Some("down") => { let steps = cmd .get_one::("steps") .and_then(|s| s.parse().ok()) .unwrap_or(1); run_down(&db, steps).await?; } Some("fresh") => run_fresh(&db).await?, Some("refresh") => run_refresh(&db).await?, Some("reset") => run_reset(&db).await?, Some("status") => run_status(&db).await?, _ => { eprintln!( "Usage: migrate \nCommands: up, down, fresh, refresh, reset, status" ); std::process::exit(1); } } Ok(()) } async fn run_up(db: &DatabaseConnection, steps: u32) -> anyhow::Result<()> { migrate::Migrator::up(db, if steps == 0 { None } else { Some(steps) }) .await .context("failed to run migrations up")?; Ok(()) } async fn run_down(db: &DatabaseConnection, steps: u32) -> anyhow::Result<()> { migrate::Migrator::down(db, Some(steps)) .await .context("failed to run migrations down")?; Ok(()) } async fn run_fresh(db: &DatabaseConnection) -> anyhow::Result<()> { migrate::Migrator::fresh(db) .await .context("failed to run migrations fresh")?; Ok(()) } async fn run_refresh(db: &DatabaseConnection) -> anyhow::Result<()> { migrate::Migrator::refresh(db) .await .context("failed to run migrations refresh")?; Ok(()) } async fn run_reset(db: &DatabaseConnection) -> anyhow::Result<()> { migrate::Migrator::reset(db) .await .context("failed to run migrations reset")?; Ok(()) } async fn run_status(db: &DatabaseConnection) -> anyhow::Result<()> { migrate::Migrator::status(db) .await .context("failed to get migration status")?; Ok(()) }