feat: add schema drift handling and rebuild

This commit is contained in:
2026-09-19 16:02:04 -07:00
parent 7074b82ced
commit 60bc2fb9d0
5 changed files with 125 additions and 24 deletions
+25
View File
@@ -4,6 +4,7 @@ from __future__ import annotations
import os
import sqlite3
import threading
import logging
from pathlib import Path
from typing import Any
@@ -42,6 +43,21 @@ def get_connection(db_path: str | None = None) -> sqlite3.Connection:
_current_path = db_path
return _conn
def _has_schema_version(conn: sqlite3.Connection) -> bool:
try:
conn.execute("SELECT 1 FROM schema_version").fetchone()
return True
except sqlite3.OperationalError:
return False
def _has_settings_value_column(conn: sqlite3.Connection) -> bool:
try:
info = conn.execute("PRAGMA table_info(settings)").fetchall()
columns = {row[1]: row[2] for row in info}
return 'value' in columns
except sqlite3.OperationalError:
return False
def init_db(db_path: str | None = None) -> sqlite3.Connection:
conn = get_connection(db_path)
@@ -53,6 +69,15 @@ def init_db(db_path: str | None = None) -> sqlite3.Connection:
with _lock:
conn.executescript(schema)
conn.commit()
if not _has_schema_version(conn):
if not _has_settings_value_column(conn):
logger = logging.getLogger("slab.db")
logger.info("Detected pre-M3 DB, rebuilding schema")
conn.executescript("DROP TABLE IF EXISTS settings")
conn.executescript(schema)
conn.commit()
conn.execute("INSERT OR REPLACE INTO schema_version (version) VALUES (1)")
return conn
+2
View File
@@ -111,6 +111,8 @@ CREATE TABLE IF NOT EXISTS settings (
value_enc TEXT
);
CREATE TABLE IF NOT EXISTS schema_version (version INTEGER PRIMARY KEY);
-- 7. prompts + prompt_revisions (append-only revisions)
CREATE TABLE IF NOT EXISTS prompts (
id INTEGER PRIMARY KEY,
+37
View File
@@ -0,0 +1,37 @@
import os
import tempfile
import sqlite3
import backend.db as db_mod
def _setup_temp_db_with_m2_schema(tmp_dir: str) -> str:
db_path = os.path.join(tmp_dir, "test.db")
conn = sqlite3.connect(db_path)
# create old settings table
conn.execute("CREATE TABLE settings (key TEXT PRIMARY KEY, value TEXT, value_enc TEXT)")
conn.commit()
conn.close()
return db_path
def test_drift_detection_and_rebuild(monkeypatch):
with tempfile.TemporaryDirectory() as tmp:
db_path = _setup_temp_db_with_m2_schema(tmp)
monkeypatch.setenv("SLAB_DB_PATH", db_path)
# init_db should rebuild
conn = db_mod.init_db()
# check schema_version exists
cur = conn.execute("SELECT version FROM schema_version").fetchone()
assert cur is not None
assert cur[0] == 1
# check settings has columns value and value_enc
info = conn.execute("PRAGMA table_info(settings)").fetchall()
cols = {row[1] for row in info}
assert "value" in cols
assert "value_enc" in cols
# also ensure old settings table dropped and recreated
# no other data
rows = conn.execute("SELECT key FROM settings").fetchall()
assert rows == []