use std::path::{Path, PathBuf};
use std::process;
use clap::Parser;
use typedpg::migrate::MigrationSource;
use typedpg_cli::{MigrateAction, connect, create_migration, run_migrate_action};
use typedpg_core::config::Config;
use typedpg_lint::report::Format;
#[derive(Parser)]
#[command(name = "cargo", bin_name = "cargo", about = "typedpg database tools")]
struct Cli {
#[command(subcommand)]
command: CargoSubcommand,
}
#[derive(clap::Subcommand)]
enum CargoSubcommand {
Typedpg {
#[command(subcommand)]
command: Commands,
},
}
#[derive(clap::Subcommand)]
enum Commands {
Migrate {
#[command(subcommand)]
action: MigrateAction,
},
Lint {
#[arg(long, default_value = "./Cargo.toml")]
manifest_path: PathBuf,
#[arg(long, default_value = "human")]
format: Format,
#[arg(long)]
ignore_migrations_from: Option<String>,
},
}
#[tokio::main]
async fn main() {
let _ = dotenvy::dotenv_override();
let cli = Cli::parse();
match run(cli).await {
Ok(true) => {}
Ok(false) => process::exit(1),
Err(e) => {
eprintln!("Error: {e}");
process::exit(1);
}
}
}
async fn run(cli: Cli) -> Result<bool, Box<dyn std::error::Error>> {
let CargoSubcommand::Typedpg { command } = cli.command;
match command {
Commands::Migrate { action } => {
handle_migrate(action).await?;
Ok(true)
}
Commands::Lint {
manifest_path,
format,
ignore_migrations_from,
} => {
match typedpg_cli::lint::run(&manifest_path, format, ignore_migrations_from.as_deref())
{
Ok(ok) => Ok(ok),
Err(e) => {
eprintln!("error: {e}");
Ok(false)
}
}
}
}
}
async fn handle_migrate(action: MigrateAction) -> Result<(), Box<dyn std::error::Error>> {
let config = Config::from_cargo_toml(Path::new("./Cargo.toml"))?;
let migrations_dir = config.migrations_dir(Path::new(""));
if let MigrateAction::Create { name } = &action {
let (up_file, down_file) = create_migration(&migrations_dir, name)?;
println!("Created {}", up_file.display());
println!("Created {}", down_file.display());
return Ok(());
}
let database_url = std::env::var("DATABASE_URL")
.map_err(|_| "DATABASE_URL environment variable must be set")?;
let source = MigrationSource::from_dir(&migrations_dir)?;
let mut client = connect(&database_url).await?;
run_migrate_action(action, &mut client, &source, &config.migrations).await
}