db_migrate/commands/
up.rs

1use crate::{migration::MigrationManager, CommandOutput};
2use anyhow::Result;
3use clap::Args;
4use colored::*;
5
6#[derive(Args)]
7pub struct UpCommand {
8    /// Number of migrations to apply (default: all)
9    #[arg(short, long)]
10    count: Option<usize>,
11
12    /// Dry run mode - show what would be applied without executing
13    #[arg(long)]
14    dry_run: bool,
15}
16
17impl UpCommand {
18    pub async fn execute(&self, manager: &mut MigrationManager) -> Result<CommandOutput> {
19        let pending_migrations = manager.get_pending_migrations().await?;
20
21        if pending_migrations.is_empty() {
22            return Ok(CommandOutput::success(format!(
23                "{} No pending migrations found",
24                "✅".green()
25            )));
26        }
27
28        // Determine how many migrations to apply
29        let migrations_to_apply = if let Some(count) = self.count {
30            pending_migrations.into_iter().take(count).collect()
31        } else {
32            pending_migrations
33        };
34
35        if self.dry_run {
36            return self.show_dry_run(&migrations_to_apply);
37        }
38
39        let mut applied_count = 0;
40        let mut applied_migrations = Vec::new();
41
42        for migration in &migrations_to_apply {
43            match manager.apply_migration(migration).await {
44                Ok(_) => {
45                    applied_count += 1;
46                    applied_migrations.push(&migration.version);
47                    println!(
48                        "{} Applied migration: {}",
49                        "✅".green(),
50                        migration.version.bright_cyan()
51                    );
52                }
53                Err(e) => {
54                    return Ok(CommandOutput::success_with_data(
55                        format!(
56                            "{} Applied {} migration(s), failed on: {}",
57                            if applied_count > 0 { "⚠️ " } else { "❌" },
58                            applied_count,
59                            migration.version
60                        ),
61                        serde_json::json!({
62                            "applied_count": applied_count,
63                            "applied_migrations": applied_migrations,
64                            "failed_migration": migration.version,
65                            "error": e.to_string()
66                        })
67                    ));
68                }
69            }
70        }
71
72        let message = if applied_count == 1 {
73            format!("{} Applied 1 migration successfully", "🎉".green())
74        } else {
75            format!("{} Applied {} migrations successfully", "🎉".green(), applied_count)
76        };
77
78        Ok(CommandOutput::success_with_data(
79            message,
80            serde_json::json!({
81                "applied_count": applied_count,
82                "applied_migrations": applied_migrations
83            })
84        ))
85    }
86
87    fn show_dry_run(&self, migrations: &[crate::MigrationFile]) -> Result<CommandOutput> {
88        let mut output = vec![
89            format!("{} Dry run mode - showing migrations that would be applied:", "🔍".cyan()),
90            String::new(),
91        ];
92
93        for (i, migration) in migrations.iter().enumerate() {
94            output.push(format!(
95                "{}. {} - {}",
96                i + 1,
97                migration.version.bright_cyan(),
98                migration.description
99            ));
100        }
101
102        if migrations.is_empty() {
103            output.push("No migrations would be applied.".to_string());
104        } else {
105            output.push(String::new());
106            output.push(format!(
107                "Total: {} migration(s) would be applied",
108                migrations.len()
109            ));
110        }
111
112        Ok(CommandOutput::success_with_data(
113            output.join("\n"),
114            serde_json::json!({
115                "dry_run": true,
116                "migrations_count": migrations.len(),
117                "migrations": migrations.iter().map(|m| {
118                    serde_json::json!({
119                        "version": m.version,
120                        "description": m.description
121                    })
122                }).collect::<Vec<_>>()
123            })
124        ))
125    }
126}