from __future__ import annotations import sqlite3 from dataclasses import dataclass from pathlib import Path class ManagedConnection(sqlite3.Connection): """Commit or roll back, then release the SQLite handle on context exit.""" def __exit__(self, exc_type, exc_value, traceback): try: return super().__exit__(exc_type, exc_value, traceback) finally: self.close() @dataclass(frozen=True) class SQLiteConnectionFactory: path: Path timeout_seconds: float = 20 def connect(self) -> sqlite3.Connection: connection = sqlite3.connect( self.path, timeout=self.timeout_seconds, factory=ManagedConnection, ) connection.row_factory = sqlite3.Row connection.execute("PRAGMA journal_mode=WAL") connection.execute("PRAGMA foreign_keys=ON") connection.execute("PRAGMA busy_timeout=20000") return connection