claw_core/schema/validators.rs
1//! Schema validation helpers for claw-core.
2//!
3//! This module exposes lightweight runtime checks that verify the claw-core
4//! schema is in an expected state after migrations have been applied. Checks
5//! are run on engine startup (when `auto_migrate` is enabled) to guard
6//! against partial migrations or external schema corruption.
7
8use sqlx::SqlitePool;
9
10use crate::error::{ClawError, ClawResult};
11
12/// Verify that all expected claw-core tables are present in the database.
13///
14/// Returns `Ok(())` if every required table exists, or a [`ClawError::Config`]
15/// listing the missing tables.
16///
17/// # Errors
18///
19/// Returns a [`ClawError`] if the introspection query fails or a table is
20/// missing.
21pub async fn validate_schema(pool: &SqlitePool) -> ClawResult<()> {
22 let required_tables = [
23 "active_memory",
24 "session_state",
25 "tool_output",
26 "context",
27 "memories",
28 "sessions",
29 ];
30
31 let rows: Vec<(String,)> =
32 sqlx::query_as("SELECT name FROM sqlite_master WHERE type = 'table'")
33 .fetch_all(pool)
34 .await?;
35
36 let existing: std::collections::HashSet<&str> =
37 rows.iter().map(|(name,)| name.as_str()).collect();
38
39 let missing: Vec<&str> = required_tables
40 .iter()
41 .copied()
42 .filter(|t| !existing.contains(t))
43 .collect();
44
45 if missing.is_empty() {
46 Ok(())
47 } else {
48 Err(ClawError::Config(format!(
49 "schema validation failed — missing tables: {}",
50 missing.join(", ")
51 )))
52 }
53}