use crate::catalog::Catalog;
use crate::commands::diff_output::{DiffContext, DiffFormat, has_differences, output_diff};
use crate::config::{Config, ObjectFilter};
use crate::diff::{cascade, diff_all, diff_order};
use crate::schema_ops::apply_current_schema_to_shadow;
use anyhow::{Result, anyhow};
use std::path::Path;
#[derive(Debug)]
pub struct MigrateDiffArgs {
pub format: DiffFormat,
pub output_sql: Option<String>,
}
impl Default for MigrateDiffArgs {
fn default() -> Self {
Self {
format: DiffFormat::Detailed,
output_sql: None,
}
}
}
pub async fn cmd_migrate_diff(
config: &Config,
root_dir: &Path,
args: MigrateDiffArgs,
) -> Result<()> {
let target_url = config.databases.target.as_ref().ok_or_else(|| {
anyhow!(
"Target database URL not configured.\n\
Set TARGET_DATABASE_URL environment variable or databases.target_url in pgmt.yaml"
)
})?;
eprintln!("Checking target database for drift...\n");
eprintln!("Loading schema files...");
let schema_catalog = apply_current_schema_to_shadow(config, root_dir).await?;
eprintln!("Loading target database...");
let target_pool =
crate::db::connection::connect_to_database(target_url, "target database").await?;
let target_catalog = Catalog::load(&target_pool).await?;
let filter = ObjectFilter::new(&config.objects, &config.migration.tracking_table);
let filtered_target_catalog = filter.filter_catalog(target_catalog);
let filtered_schema_catalog = filter.filter_catalog(schema_catalog);
eprintln!("Computing differences...\n");
let steps = diff_all(&filtered_target_catalog, &filtered_schema_catalog);
let expanded_steps = cascade::expand(steps, &filtered_target_catalog, &filtered_schema_catalog);
let ordered_steps = diff_order(
expanded_steps,
&filtered_target_catalog,
&filtered_schema_catalog,
)?;
let context = DiffContext::new("target database", "schema files");
output_diff(
&ordered_steps,
&args.format,
&context,
&filtered_target_catalog,
&filtered_schema_catalog,
args.output_sql.as_deref(),
)?;
if has_differences(&ordered_steps) {
eprintln!("\nDrift detected! Target database differs from schema files.");
std::process::exit(1);
} else {
eprintln!("No drift detected. Target database matches schema files.");
}
Ok(())
}