oxify_authz/
migration.rs

1//! Database migration utilities
2
3use crate::*;
4use sqlx::sqlite::SqlitePool;
5
6/// Migration manager for authorization database
7pub struct MigrationManager {
8    pool: SqlitePool,
9}
10
11impl MigrationManager {
12    pub fn new(pool: SqlitePool) -> Self {
13        Self { pool }
14    }
15
16    /// Run all pending migrations
17    pub async fn run_migrations(&self) -> Result<()> {
18        tracing::info!("Running authorization database migrations...");
19
20        // Run the initial schema
21        sqlx::query(include_str!("../migrations/001_init.sql"))
22            .execute(&self.pool)
23            .await
24            .map_err(|e| AuthzError::DatabaseError(format!("Migration 001 failed: {}", e)))?;
25
26        tracing::info!("Authorization migrations completed successfully");
27        Ok(())
28    }
29
30    /// Refresh the reachability index (Leopard Index)
31    /// For SQLite, this is a no-op as we don't have PostgreSQL stored procedures
32    pub async fn refresh_index(&self) -> Result<()> {
33        tracing::info!("Refreshing reachability index (no-op for SQLite)...");
34        // SQLite doesn't support stored procedures like PostgreSQL
35        // The index is maintained through application-level logic
36        tracing::info!("Reachability index refresh skipped (SQLite)");
37        Ok(())
38    }
39
40    /// Clean up old audit logs
41    pub async fn cleanup_audit_logs(&self) -> Result<u64> {
42        tracing::info!("Cleaning up old audit logs...");
43
44        // Delete audit logs older than 90 days
45        let result = sqlx::query(
46            r#"
47            DELETE FROM authz_audit_log
48            WHERE timestamp < datetime('now', '-90 days')
49            "#,
50        )
51        .execute(&self.pool)
52        .await
53        .map_err(|e| AuthzError::DatabaseError(format!("Cleanup failed: {}", e)))?;
54
55        Ok(result.rows_affected())
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[tokio::test]
64    #[ignore] // Requires database
65    async fn test_migrations() {
66        let database_url =
67            std::env::var("DATABASE_URL").unwrap_or_else(|_| "sqlite::memory:".to_string());
68
69        let pool = SqlitePool::connect(&database_url).await.unwrap();
70        let manager = MigrationManager::new(pool);
71
72        manager.run_migrations().await.unwrap();
73    }
74}