spawn_db/commands/migration/
status.rs1use crate::commands::migration::get_combined_migration_status;
2use crate::commands::{Command, Outcome, TelemetryDescribe, TelemetryInfo};
3use crate::config::Config;
4use crate::engine::MigrationStatus as EngineStatus;
5use anyhow::Result;
6use console::style;
7use tabled::settings::Style;
8use tabled::{Table, Tabled};
9
10#[derive(Tabled)]
11struct MigrationStatusDisplay {
12 #[tabled(rename = "Migration")]
13 name: String,
14 #[tabled(rename = "Filesystem")]
15 on_filesystem: String,
16 #[tabled(rename = "Pinned")]
17 pinned: String,
18 #[tabled(rename = "Database")]
19 in_database: String,
20 #[tabled(rename = "Status")]
21 status: String,
22}
23
24pub struct MigrationStatus;
25
26impl TelemetryDescribe for MigrationStatus {
27 fn telemetry(&self) -> TelemetryInfo {
28 TelemetryInfo::new("migration status")
29 }
30}
31
32impl Command for MigrationStatus {
33 async fn execute(&self, config: &Config) -> Result<Outcome> {
34 let status_rows =
35 get_combined_migration_status(config, Some(super::DEFAULT_NAMESPACE)).await?;
36
37 if status_rows.is_empty() {
38 println!("No migrations found");
39 return Ok(Outcome::Success);
40 }
41
42 let display_rows: Vec<MigrationStatusDisplay> = status_rows
43 .into_iter()
44 .map(|row| {
45 let on_filesystem = if row.exists_in_filesystem {
46 style("✓").green().to_string()
47 } else {
48 style("✗").red().to_string()
49 };
50
51 let pinned = if row.is_pinned {
52 style("✓").green().to_string()
53 } else {
54 style("✗").red().to_string()
55 };
56
57 let in_database = if row.exists_in_db {
58 style("✓").green().to_string()
59 } else {
60 style("✗").red().to_string()
61 };
62
63 let status = match (
65 row.exists_in_db,
66 row.last_status,
67 row.last_activity.as_deref(),
68 ) {
69 (true, Some(EngineStatus::Success), Some("APPLY")) => {
70 style("✓ Applied").green().to_string()
71 }
72 (true, Some(EngineStatus::Success), Some("ADOPT")) => {
73 style("⊙ Adopted").cyan().to_string()
74 }
75 (true, Some(EngineStatus::Attempted), _) => {
76 style("⚠ Attempted").yellow().to_string()
77 }
78 (true, Some(EngineStatus::Failure), _) => style("✗ Failed").red().to_string(),
79 (false, _, _) => style("○ Pending").dim().to_string(),
80 _ => style("-").dim().to_string(),
81 };
82
83 MigrationStatusDisplay {
84 name: row.migration_name,
85 on_filesystem,
86 pinned,
87 in_database,
88 status,
89 }
90 })
91 .collect();
92
93 let mut table = Table::new(display_rows);
94 table.with(Style::sharp());
95 println!("\n{}\n", table);
96
97 Ok(Outcome::Success)
98 }
99}