use std::fmt;
use crate::error::Result;
use super::Schema;
#[super::async_trait]
pub trait Migration: Send + Sync {
fn version(&self) -> &str;
fn name(&self) -> &str;
async fn up(&self, schema: &mut Schema) -> Result<()>;
async fn down(&self, schema: &mut Schema) -> Result<()>;
}
#[derive(Debug, Clone)]
pub struct MigrationResult {
pub applied: Vec<MigrationInfo>,
pub skipped: Vec<MigrationInfo>,
pub rolled_back: Vec<MigrationInfo>,
}
impl MigrationResult {
pub(super) fn new() -> Self {
Self {
applied: Vec::new(),
skipped: Vec::new(),
rolled_back: Vec::new(),
}
}
pub fn has_applied(&self) -> bool {
!self.applied.is_empty()
}
pub fn has_rolled_back(&self) -> bool {
!self.rolled_back.is_empty()
}
}
impl fmt::Display for MigrationResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if !self.applied.is_empty() {
writeln!(f, "Applied migrations:")?;
for migration in &self.applied {
writeln!(f, " ✓ {} - {}", migration.version, migration.name)?;
}
}
if !self.skipped.is_empty() {
writeln!(f, "Skipped migrations (already applied):")?;
for migration in &self.skipped {
writeln!(f, " - {} - {}", migration.version, migration.name)?;
}
}
if !self.rolled_back.is_empty() {
writeln!(f, "Rolled back migrations:")?;
for migration in &self.rolled_back {
writeln!(f, " ↩ {} - {}", migration.version, migration.name)?;
}
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct MigrationInfo {
pub version: String,
pub name: String,
}
#[derive(Debug, Clone)]
pub struct MigrationStatus {
pub version: String,
pub name: String,
pub applied: bool,
}
impl fmt::Display for MigrationStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let status = if self.applied { "✓" } else { "○" };
write!(f, "[{}] {} - {}", status, self.version, self.name)
}
}