Skip to main content

codlet_sqlx/
migration.rs

1//! Migration runner for codlet SQLite tables (RFC-011 §10.4).
2//!
3//! The SQL is embedded at compile time via `include_str!`. Host applications
4//! own the migration *application order* — this function is idempotent and
5//! safe to call on startup, but the host decides when and how to run it
6//! relative to its own migrations (RFC-011 §10.4).
7
8use sqlx::SqlitePool;
9
10/// Run codlet's embedded SQLite migrations against `pool`.
11///
12/// Uses `IF NOT EXISTS` semantics; safe to call on every startup.
13///
14/// # Errors
15/// Returns a [`sqlx::Error`] if the SQL execution fails.
16pub async fn run_migrations(pool: &SqlitePool) -> Result<(), sqlx::Error> {
17    // WAL mode gives better concurrent read/write performance and is
18    // recommended for codlet's workload.
19    sqlx::query("PRAGMA journal_mode = WAL")
20        .execute(pool)
21        .await?;
22    // Enforce foreign key constraints if the host schema uses them.
23    sqlx::query("PRAGMA foreign_keys = ON")
24        .execute(pool)
25        .await?;
26
27    let migration_sql = include_str!("../migrations/0001_initial.sql");
28
29    // Split on statement boundaries and execute each statement separately,
30    // since SQLx's `execute` does not support multiple statements in one call.
31    for stmt in migration_sql.split(';') {
32        // Strip leading comment lines and whitespace from each segment, then
33        // execute only non-empty segments. A segment that is entirely comments
34        // (e.g. the preamble before the first real statement) is silently
35        // skipped; a segment that starts with comments but contains SQL is
36        // executed with the comments stripped.
37        let code_lines: String = stmt
38            .lines()
39            .filter(|l| !l.trim_start().starts_with("--"))
40            .collect::<Vec<_>>()
41            .join("\n");
42        let trimmed = code_lines.trim();
43        if trimmed.is_empty() {
44            continue;
45        }
46        sqlx::query(trimmed).execute(pool).await?;
47    }
48
49    Ok(())
50}