diff --git a/pyproject.toml b/pyproject.toml index 0b4b356..fef2bb1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "servicekit" -version = "0.5.4" +version = "0.6.0" description = "Async SQLAlchemy framework with FastAPI integration - reusable foundation for building data services" readme = "README.md" authors = [{ name = "Morten Hansen", email = "morten@winterop.com" }] diff --git a/src/servicekit/database.py b/src/servicekit/database.py index 1b115a2..2df6ee6 100644 --- a/src/servicekit/database.py +++ b/src/servicekit/database.py @@ -179,6 +179,16 @@ async def init(self) -> None: # For file-based databases, use Alembic migrations await super().init() + async def dispose(self) -> None: + """Dispose database with WAL checkpoint for file-based databases.""" + if not self.is_in_memory(): + try: + async with self.engine.begin() as conn: + await conn.exec_driver_sql("PRAGMA wal_checkpoint(TRUNCATE);") + except Exception: + pass # Don't fail dispose on checkpoint error + await super().dispose() + class SqliteDatabaseBuilder: """Builder for SQLite database configuration with fluent API.""" diff --git a/tests/test_database.py b/tests/test_database.py index 28f9aab..b55e112 100644 --- a/tests/test_database.py +++ b/tests/test_database.py @@ -346,3 +346,23 @@ def test_builder_without_url_raises_error(self) -> None: builder = SqliteDatabaseBuilder() with pytest.raises(ValueError, match="Database URL not configured"): builder.build() + + async def test_dispose_checkpoints_wal(self, tmp_path: Path) -> None: + """Test that dispose checkpoints WAL for file-based databases.""" + db_path = tmp_path / "test.db" + db = SqliteDatabaseBuilder.from_file(str(db_path)).build() + await db.init() + + # Write some data to create WAL entries + async with db.session() as session: + await session.execute(text("CREATE TABLE test_wal (id INTEGER)")) + await session.execute(text("INSERT INTO test_wal VALUES (1)")) + await session.commit() + + # WAL file path + wal_path = db_path.parent / f"{db_path.name}-wal" + + await db.dispose() + + # After dispose with TRUNCATE checkpoint, WAL should be empty or removed + assert not wal_path.exists() or wal_path.stat().st_size == 0 diff --git a/uv.lock b/uv.lock index d8567f2..dd8de44 100644 --- a/uv.lock +++ b/uv.lock @@ -1129,7 +1129,7 @@ wheels = [ [[package]] name = "servicekit" -version = "0.5.4" +version = "0.6.0" source = { editable = "." } dependencies = [ { name = "aiosqlite" },