feat: db migrations and store
This commit is contained in:
parent
dd7f19ccec
commit
c3e18e83e5
4 changed files with 70 additions and 0 deletions
5
app/db/migrations/001_chains.sql
Normal file
5
app/db/migrations/001_chains.sql
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
CREATE TABLE IF NOT EXISTS chains (
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
created_at REAL NOT NULL
|
||||
);
|
||||
19
app/db/migrations/002_nodes.sql
Normal file
19
app/db/migrations/002_nodes.sql
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
CREATE TABLE IF NOT EXISTS nodes (
|
||||
id TEXT PRIMARY KEY,
|
||||
chain_id TEXT NOT NULL REFERENCES chains(id) ON DELETE CASCADE,
|
||||
parent_id TEXT REFERENCES nodes(id) ON DELETE CASCADE,
|
||||
audio_path TEXT,
|
||||
duration_s REAL,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
is_committed INTEGER NOT NULL DEFAULT 0,
|
||||
prompt TEXT NOT NULL DEFAULT '',
|
||||
energy REAL,
|
||||
tempo_feel REAL,
|
||||
density REAL,
|
||||
cfg_coef REAL NOT NULL DEFAULT 3.0,
|
||||
prompt_duration_s REAL NOT NULL DEFAULT 10.0,
|
||||
error_msg TEXT,
|
||||
created_at REAL NOT NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_chain_id ON nodes(chain_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_nodes_parent_id ON nodes(parent_id);
|
||||
19
app/db/store.py
Normal file
19
app/db/store.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from __future__ import annotations
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
_MIGRATIONS_DIR = Path(__file__).parent / "migrations"
|
||||
|
||||
|
||||
def get_connection(db_path: str) -> sqlite3.Connection:
|
||||
conn = sqlite3.connect(db_path, check_same_thread=False)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute("PRAGMA journal_mode=WAL")
|
||||
conn.execute("PRAGMA foreign_keys=ON")
|
||||
return conn
|
||||
|
||||
|
||||
def run_migrations(conn: sqlite3.Connection) -> None:
|
||||
for migration in sorted(_MIGRATIONS_DIR.glob("*.sql")):
|
||||
conn.executescript(migration.read_text())
|
||||
conn.commit()
|
||||
27
tests/test_store.py
Normal file
27
tests/test_store.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import sqlite3
|
||||
import tempfile
|
||||
import pytest
|
||||
from app.db.store import get_connection, run_migrations
|
||||
|
||||
|
||||
def test_migrations_create_tables():
|
||||
with tempfile.NamedTemporaryFile(suffix=".db") as f:
|
||||
conn = get_connection(f.name)
|
||||
run_migrations(conn)
|
||||
tables = {r[0] for r in conn.execute(
|
||||
"SELECT name FROM sqlite_master WHERE type='table'"
|
||||
)}
|
||||
assert "chains" in tables
|
||||
assert "nodes" in tables
|
||||
|
||||
|
||||
def test_foreign_keys_enforced():
|
||||
with tempfile.NamedTemporaryFile(suffix=".db") as f:
|
||||
conn = get_connection(f.name)
|
||||
run_migrations(conn)
|
||||
with pytest.raises(sqlite3.IntegrityError):
|
||||
conn.execute(
|
||||
"INSERT INTO nodes (id, chain_id, status, created_at) "
|
||||
"VALUES ('n1', 'nonexistent', 'pending', 0.0)"
|
||||
)
|
||||
conn.commit()
|
||||
Loading…
Reference in a new issue