toasty_cli/migration/
drop.rs1use 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 #[arg(short, long)]
14 name: Option<String>,
15
16 #[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 let migration_index = if self.latest {
33 history.migrations().len() - 1
35 } else if let Some(name) = &self.name {
36 history
38 .migrations()
39 .iter()
40 .position(|m| m.name == *name)
41 .ok_or_else(|| anyhow::anyhow!("Migration '{}' not found", name))?
42 } else {
43 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 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 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 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}