rsclaw 0.0.1-alpha.1

rsclaw: High-performance AI agent (BETA). Optimized for M4 Max and 2GB VPS. 100% compatible with openclaw
Documentation
use super::database::Store;
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::sync::Arc;

/// Schema version metadata.
const SCHEMA_VERSION_KEY: &str = "schema_version";
const CURRENT_VERSION: u32 = 1;

/// Migration record.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Migration {
    pub version: u32,
    pub description: Arc<str>,
    pub applied_at: u64,
}

/// Migration manager.
pub struct MigrationManager {
    store: Arc<Store>,
}

impl MigrationManager {
    /// Create a new migration manager.
    pub fn new(store: Arc<Store>) -> Self {
        Self { store }
    }

    /// Get current schema version.
    pub fn get_version(&self) -> Result<u32> {
        match self.store.get_metadata(SCHEMA_VERSION_KEY)? {
            Some(data) => {
                let version = u32::from_le_bytes(data.try_into().unwrap_or([0; 4]));
                Ok(version)
            }
            None => Ok(0),
        }
    }

    /// Set schema version.
    pub fn set_version(&self, version: u32) -> Result<()> {
        self.store
            .set_metadata(SCHEMA_VERSION_KEY, &version.to_le_bytes())
    }

    /// Run migrations if needed.
    pub fn migrate(&self) -> Result<()> {
        let current = self.get_version()?;

        if current < CURRENT_VERSION {
            tracing::info!("Migrating schema from v{} to v{}", current, CURRENT_VERSION);

            for version in (current + 1)..=CURRENT_VERSION {
                self.run_migration(version)?;
            }

            self.set_version(CURRENT_VERSION)?;
            tracing::info!("Migration complete");
        }

        Ok(())
    }

    /// Run a specific migration.
    fn run_migration(&self, version: u32) -> Result<()> {
        match version {
            1 => self.migrate_v1(),
            _ => {
                tracing::warn!("Unknown migration version: {}", version);
                Ok(())
            }
        }
    }

    /// Migration v1: Initial schema.
    fn migrate_v1(&self) -> Result<()> {
        tracing::info!("Running migration v1: Initial schema");
        Ok(())
    }
}