linkrs-migration 0.1.0

Schema and data migration for Linkrs
Documentation
use std::sync::atomic::{AtomicU64, Ordering};

pub struct MigrationMetrics {
    pub total_migrations: AtomicU64,
    pub successful_migrations: AtomicU64,
    pub failed_migrations: AtomicU64,
    pub total_rows_migrated: AtomicU64,
    pub total_duration_ms: AtomicU64,
}

impl MigrationMetrics {
    pub fn new() -> Self {
        Self {
            total_migrations: AtomicU64::new(0),
            successful_migrations: AtomicU64::new(0),
            failed_migrations: AtomicU64::new(0),
            total_rows_migrated: AtomicU64::new(0),
            total_duration_ms: AtomicU64::new(0),
        }
    }

    pub fn record_success(&self, rows: u64, duration_ms: u64) {
        self.total_migrations.fetch_add(1, Ordering::Relaxed);
        self.successful_migrations.fetch_add(1, Ordering::Relaxed);
        self.total_rows_migrated.fetch_add(rows, Ordering::Relaxed);
        self.total_duration_ms
            .fetch_add(duration_ms, Ordering::Relaxed);
    }

    pub fn record_failure(&self, duration_ms: u64) {
        self.total_migrations.fetch_add(1, Ordering::Relaxed);
        self.failed_migrations.fetch_add(1, Ordering::Relaxed);
        self.total_duration_ms
            .fetch_add(duration_ms, Ordering::Relaxed);
    }

    pub fn snapshot(&self) -> MigrationMetricsSnapshot {
        MigrationMetricsSnapshot {
            total_migrations: self.total_migrations.load(Ordering::Relaxed),
            successful_migrations: self.successful_migrations.load(Ordering::Relaxed),
            failed_migrations: self.failed_migrations.load(Ordering::Relaxed),
            total_rows_migrated: self.total_rows_migrated.load(Ordering::Relaxed),
            total_duration_ms: self.total_duration_ms.load(Ordering::Relaxed),
        }
    }

    pub fn reset(&self) {
        self.total_migrations.store(0, Ordering::Relaxed);
        self.successful_migrations.store(0, Ordering::Relaxed);
        self.failed_migrations.store(0, Ordering::Relaxed);
        self.total_rows_migrated.store(0, Ordering::Relaxed);
        self.total_duration_ms.store(0, Ordering::Relaxed);
    }
}

impl Default for MigrationMetrics {
    fn default() -> Self {
        Self::new()
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MigrationMetricsSnapshot {
    pub total_migrations: u64,
    pub successful_migrations: u64,
    pub failed_migrations: u64,
    pub total_rows_migrated: u64,
    pub total_duration_ms: u64,
}

static GLOBAL_MIGRATION_METRICS: std::sync::OnceLock<MigrationMetrics> = std::sync::OnceLock::new();

pub fn global_migration_metrics() -> &'static MigrationMetrics {
    GLOBAL_MIGRATION_METRICS.get_or_init(MigrationMetrics::new)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_metrics_record_success() {
        let m = MigrationMetrics::new();
        m.record_success(10, 100);
        m.record_success(5, 50);
        let snap = m.snapshot();
        assert_eq!(snap.total_migrations, 2);
        assert_eq!(snap.successful_migrations, 2);
        assert_eq!(snap.total_rows_migrated, 15);
        assert_eq!(snap.total_duration_ms, 150);
    }

    #[test]
    fn test_metrics_record_failure() {
        let m = MigrationMetrics::new();
        m.record_success(10, 100);
        m.record_failure(20);
        let snap = m.snapshot();
        assert_eq!(snap.total_migrations, 2);
        assert_eq!(snap.failed_migrations, 1);
        assert_eq!(snap.successful_migrations, 1);
    }

    #[test]
    fn test_metrics_reset() {
        let m = MigrationMetrics::new();
        m.record_success(10, 100);
        m.reset();
        let snap = m.snapshot();
        assert_eq!(snap.total_migrations, 0);
    }
}