"""Clean db factory (stdlib sqlite3 only). get_connection opens a FRESH connection on every call (row_factory + pragmas applied). The P0.1 cached-singleton was NOT safe: FastAPI runs sync endpoints in anyio worker threads and async endpoints on the portal loop, and a cached connection bound on the main thread got silently re-opened against the default path once the app's event loop ran — tests passed only because a stale `slab_demo.db` in the repo masked the misdirection. A per-call connection makes the path binding explicit and thread-local by construction. Callers own the connection's lifetime (close when done; endpoints close via context). init_db applies schema.sql + upserts schema_version (v=1). """ from __future__ import annotations import os import sqlite3 from pathlib import Path def get_connection(db_path: str | None = None) -> sqlite3.Connection: if db_path is None: db_path = os.environ.get("SLAB_DB_PATH") or "slab_demo.db" db_path = str(Path(db_path).resolve()) # isolation_level=None -> autocommit mode. The P0.1 default (deferred # transactions) left a read-transaction open for the whole life of an # endpoint connection, which (a) blocked other writers with "database is # locked" and (b) made conn.commit() inside an open txn a no-op for # multi-statement units. Autocommit + explicit BEGIN for the few # multi-statement units (taxonomy sync) is the honest model for a # per-call-connection factory. conn = sqlite3.connect(db_path, check_same_thread=False, isolation_level=None) conn.row_factory = sqlite3.Row conn.execute("PRAGMA journal_mode=WAL") conn.execute("PRAGMA foreign_keys=ON") conn.execute("PRAGMA busy_timeout=5000") conn.execute("PRAGMA synchronous=NORMAL") return conn def init_db(db_path: str | None = None) -> None: """Apply schema.sql (CREATE IF NOT EXISTS) and ensure schema_version row=1.""" schema_path = Path(__file__).parent / "schema.sql" if not schema_path.exists(): raise FileNotFoundError(f"Schema not found: {schema_path}") conn = get_connection(db_path) try: with open(schema_path, "r", encoding="utf-8") as f: schema = f.read() conn.executescript(schema) conn.execute("INSERT OR REPLACE INTO schema_version (version) VALUES (1)") conn.commit() finally: conn.close()