Coverage for node / src / stigmem_node / storage / base.py: 77%
22 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-25 01:49 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-05-25 01:49 +0000
1"""StorageBackend abstract base — the seam between node logic and persistence."""
3from __future__ import annotations
5from abc import ABC, abstractmethod
6from collections.abc import Generator
7from contextlib import contextmanager
8from pathlib import Path
9from typing import Any
12class StorageBackend(ABC):
13 """Pluggable storage seam.
15 Implement this class to add a new persistence backend. The interface covers:
16 - Connection lifecycle (``connection``)
17 - Transaction semantics (commit on clean exit, rollback on exception)
18 - Migration runner (``apply_migrations``)
19 - Snapshot hooks (``export_snapshot`` / ``import_snapshot``)
21 Fact CRUD and query primitives are expressed as raw SQL through the
22 SQLite-API-compatible connection object yielded by ``connection()``.
23 """
25 @property
26 @abstractmethod
27 def backend_name(self) -> str:
28 """Short identifier returned in ``/.well-known/stigmem`` and logs, e.g. ``'sqlite'``."""
29 raise NotImplementedError
31 @abstractmethod
32 @contextmanager
33 def connection(self) -> Generator[Any, None, None]:
34 """Yield a SQLite-API-compatible connection.
36 Contract:
37 * Commits on clean exit.
38 * Rolls back and re-raises on any exception.
39 * Always closes the underlying connection.
40 * Rows must support column access by name (``row["column"]``).
41 """
42 raise NotImplementedError
44 @abstractmethod
45 def apply_migrations(self, migrations_dir: Path) -> None:
46 """Run all un-applied numbered ``.sql`` files found in *migrations_dir*.
48 Implementations must be idempotent — already-applied versions (tracked in
49 ``schema_migrations``) must be silently skipped.
50 """
51 raise NotImplementedError
53 def export_snapshot(self, dest: Path) -> None:
54 """Export a point-in-time snapshot to *dest*.
56 Optional hook for backup/DR workflows (e.g. Fly.io volume snapshots).
57 Raise ``NotImplementedError`` if the backend does not support it.
58 """
59 raise NotImplementedError(f"{type(self).__name__} does not support snapshot export")
61 def import_snapshot(self, src: Path) -> None:
62 """Restore from a snapshot at *src*.
64 Optional hook. Raise ``NotImplementedError`` if unsupported.
65 """
66 raise NotImplementedError(f"{type(self).__name__} does not support snapshot import")