corvix.storage¶
Local persistence for polled notifications.
PostgreSQL is the only supported backend; PostgresStorage implements
the StorageBackend protocol used across the app.
Attributes¶
Exceptions¶
Raised when required storage configuration (a database URL) is missing. |
Classes¶
Protocol for notification persistence backends. |
|
PostgreSQL-backed notification persistence implementing StorageBackend. |
Functions¶
|
Return the configured PostgreSQL storage backend. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Parse the account_errors JSONB value into a tuple of AccountError. |
|
|
Module Contents¶
- exception corvix.storage.StorageConfigError[source][source]¶
Bases:
RuntimeErrorRaised when required storage configuration (a database URL) is missing.
- class corvix.storage.StorageBackend[source][source]¶
Bases:
ProtocolProtocol for notification persistence backends.
- save_records(records: list[corvix.domain.NotificationRecord], generated_at: datetime.datetime) None[source][source]¶
- load_records() tuple[datetime.datetime | None, list[corvix.domain.NotificationRecord]][source][source]¶
- save_status(status: corvix.domain.PollerStatus) None[source][source]¶
- load_status() corvix.domain.PollerStatus[source][source]¶
- __enter__() StorageBackend[source][source]¶
- corvix.storage.create_storage(config: corvix.config.AppConfig) PostgresStorage[source][source]¶
Return the configured PostgreSQL storage backend.
PostgreSQL is required in all deployments; the JSON cache is no longer used as the shared store between the poller and the web service. Raises
StorageConfigErrorwhen no database URL is configured.
- class corvix.storage.PostgresStorage[source][source]¶
PostgreSQL-backed notification persistence implementing StorageBackend.
Uses psycopg (sync) so it is safe to use from CLI commands and the synchronous Litestar route handlers (sync_to_thread=False is not used with this backend — callers should run in a thread pool if needed).
A
psycopg_pool.ConnectionPoolis created at construction time so that TCP connections are reused across method calls rather than being opened and torn down per operation. Callclose()when the storage is no longer needed, or use it as a context manager:with PostgresStorage(connection_string=url) as storage: storage.save_records(...)
- _pool: psycopg_pool.ConnectionPool[psycopg.Connection[tuple[object, Ellipsis]]] | None = None[source][source]¶
- __enter__() PostgresStorage[source][source]¶
- _connect() contextlib.AbstractContextManager[psycopg.Connection[tuple[object, Ellipsis]]][source][source]¶
Return a pooled connection context-manager.
Usage is identical to the previous
psycopg.connect()call:with self._connect() as conn: ...
- save_records(records: list[corvix.domain.NotificationRecord], generated_at: datetime.datetime) None[source][source]¶
Upsert records. Preserves dismissed flag on conflict.
- load_records() tuple[datetime.datetime | None, list[corvix.domain.NotificationRecord]][source][source]¶
Load all records ordered by snapshot_at descending.
- save_status(status: corvix.domain.PollerStatus) None[source][source]¶
Upsert the poller status row.
- load_status() corvix.domain.PollerStatus[source][source]¶
Load the poller status, defaulting to
unknown.
- dismiss_record(thread_id: str, account_id: str = 'primary') None[source][source]¶
Set dismissed=true for a specific account/thread id.
- mark_record_read(thread_id: str, account_id: str = 'primary') None[source][source]¶
Set unread=false for a specific account/thread id.
- prune_orphaned_records(account_ids: collections.abc.Sequence[str]) int[source][source]¶
Delete records whose
account_idis not in account_ids.Used to clear rows left behind when an account is removed or its
idis renamed in config: such records are un-actionable in the UI (their account no longer resolves) and otherwise linger forever. account_ids must be the full set of currently-configured account IDs; accounts that merely failed to poll this cycle are still configured, so their rows are preserved. Returns the number of rows deleted.Passing an empty sequence is a no-op (it never deletes every record), guarding against wiping the table if the configured account set is momentarily unavailable.
- corvix.storage._parse_account_errors(value: object) tuple[corvix.domain.AccountError, Ellipsis][source][source]¶
Parse the account_errors JSONB value into a tuple of AccountError.