agent_orchestrator/persistence/
schema.rs1use 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
7pub struct PersistenceBootstrap;
9
10impl PersistenceBootstrap {
11 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 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}