Skip to main content

agent_orchestrator/persistence/
schema.rs

1use crate::persistence::migration as schema_migration;
2pub use crate::persistence::migration::SchemaStatus;
3use crate::persistence::sqlite::open_conn;
4use anyhow::{Context, Result};
5use std::path::Path;
6
7/// Bootstraps the persistence schema and exposes status helpers.
8pub struct PersistenceBootstrap;
9
10impl PersistenceBootstrap {
11    /// Opens the database, applies pending migrations, and returns the resulting schema status.
12    pub fn ensure_current(db_path: &Path) -> Result<SchemaStatus> {
13        let conn = open_conn(db_path)?;
14        conn.execute_batch(
15            r#"
16            PRAGMA journal_mode = WAL;
17            PRAGMA synchronous = NORMAL;
18            "#,
19        )
20        .context("failed to configure sqlite wal mode")?;
21
22        let migrations = schema_migration::registered_migrations();
23        let applied = schema_migration::run_pending(&conn, &migrations)?;
24        if !applied.is_empty() {
25            tracing::info!(
26                applied = applied.count(),
27                versions = ?applied.applied.iter().map(|migration| migration.version).collect::<Vec<_>>(),
28                "schema migrations applied"
29            );
30        }
31
32        schema_migration::status(&conn, &migrations)
33    }
34
35    /// Returns the current schema status without applying migrations.
36    pub fn status(db_path: &Path) -> Result<SchemaStatus> {
37        let conn = open_conn(db_path)?;
38        schema_migration::registered_status(&conn)
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    fn bootstrap_creates_latest_schema_and_reports_current_status() {
48        let temp = tempfile::tempdir().expect("temp dir");
49        let db_path = temp.path().join("schema.db");
50
51        let status = PersistenceBootstrap::ensure_current(&db_path).expect("bootstrap schema");
52
53        assert_eq!(status.current_version, status.target_version);
54        assert!(status.is_current());
55
56        let status_after = PersistenceBootstrap::status(&db_path).expect("status");
57        assert_eq!(status_after.current_version, status_after.target_version);
58        assert!(status_after.pending_versions.is_empty());
59    }
60}