toasty_cli/migration/
drop.rs

1use super::HistoryFile;
2use crate::{Config, theme::dialoguer_theme};
3use anyhow::Result;
4use clap::Parser;
5use console::style;
6use dialoguer::Select;
7use std::fs;
8use toasty::Db;
9
10#[derive(Parser, Debug)]
11pub struct DropCommand {
12    /// Name of the migration to drop (if not provided, will prompt)
13    #[arg(short, long)]
14    name: Option<String>,
15
16    /// Drop the latest migration
17    #[arg(short, long)]
18    latest: bool,
19}
20
21impl DropCommand {
22    pub(crate) fn run(self, _db: &Db, config: &Config) -> Result<()> {
23        let history_path = config.migration.get_history_file_path();
24        let mut history = HistoryFile::load_or_default(&history_path)?;
25
26        if history.migrations().is_empty() {
27            eprintln!("{}", style("No migrations found in history").red().bold());
28            anyhow::bail!("No migrations found in history");
29        }
30
31        // Determine which migration to drop
32        let migration_index = if self.latest {
33            // Drop the latest migration
34            history.migrations().len() - 1
35        } else if let Some(name) = &self.name {
36            // Find migration by name
37            history
38                .migrations()
39                .iter()
40                .position(|m| m.name == *name)
41                .ok_or_else(|| anyhow::anyhow!("Migration '{}' not found", name))?
42        } else {
43            // Interactive picker with fancy theme
44            println!();
45            println!("  {}", style("Drop Migration").cyan().bold().underlined());
46            println!();
47
48            let migration_display: Vec<String> = history
49                .migrations()
50                .iter()
51                .map(|m| format!("  {}", m.name))
52                .collect();
53
54            Select::with_theme(&dialoguer_theme())
55                .with_prompt("  Select migration to drop")
56                .items(&migration_display)
57                .default(migration_display.len() - 1)
58                .interact()?
59        };
60
61        println!();
62
63        let migration = &history.migrations()[migration_index];
64        let migration_name = migration.name.clone();
65        let snapshot_name = migration.snapshot_name.clone();
66
67        // Delete migration file
68        let migration_path = config.migration.get_migrations_dir().join(&migration_name);
69        if migration_path.exists() {
70            fs::remove_file(&migration_path)?;
71            println!(
72                "  {} {}",
73                style("✓").green().bold(),
74                style(format!("Deleted migration: {}", migration_name)).dim()
75            );
76        } else {
77            println!(
78                "  {} {}",
79                style("⚠").yellow().bold(),
80                style(format!("Migration file not found: {}", migration_name))
81                    .yellow()
82                    .dim()
83            );
84        }
85
86        // Delete snapshot file
87        let snapshot_path = config.migration.get_snapshots_dir().join(&snapshot_name);
88        if snapshot_path.exists() {
89            fs::remove_file(&snapshot_path)?;
90            println!(
91                "  {} {}",
92                style("✓").green().bold(),
93                style(format!("Deleted snapshot: {}", snapshot_name)).dim()
94            );
95        } else {
96            println!(
97                "  {} {}",
98                style("⚠").yellow().bold(),
99                style(format!("Snapshot file not found: {}", snapshot_name))
100                    .yellow()
101                    .dim()
102            );
103        }
104
105        // Remove from history
106        history.remove_migration(migration_index);
107        history.save(&history_path)?;
108
109        println!(
110            "  {} {}",
111            style("✓").green().bold(),
112            style("Updated migration history").dim()
113        );
114        println!();
115        println!(
116            "  {} {}",
117            style("").magenta(),
118            style(format!(
119                "Migration '{}' successfully dropped",
120                migration_name
121            ))
122            .green()
123            .bold()
124        );
125        println!();
126
127        Ok(())
128    }
129}