nw.graph_backend#
Config-driven backend selection for nw’s annotation graph stores.
Phase 4 of the storage migration (reelee#177). A nw project keeps its
annotations in lacing IntervalAnnotationStore``s — historically one
``SqliteStore file per scope (the project graph, the storyboard, the
lyrics alignment). This module is the single seam that decides whether a
given scope is backed by SQLite (the default — byte-for-byte the old
behaviour, one file per scope) or by a shared Postgres database
(lacing.store.PostgresStore, tenant-scoped).
The facade principle in action#
Every nw site that needs a graph store — nw.migrate.open_project_graph(),
the storyboard load/save, the lyrics-alignment read, and the provenance walk in
nw.graph — routes through open_graph_store() /
iter_scope_stores() here. None of them learns which backend answered;
nw.graph.ProjectGraph and every typed accessor are unchanged.
The environment contract#
Variable |
Meaning |
|---|---|
|
|
|
(postgres) psycopg conninfo URL for the shared DB. |
|
(postgres, optional) tenant owner; defaults to
lacing’s |
Safety first. The default (no env, or any unrecognized backend) is always
SQLite — identical to the behaviour before this module existed. A local run
never changes and never crashes because Postgres env happens to be unset; if
NW_GRAPH_BACKEND=postgres but NW_GRAPH_DB_URL is missing, we log a
warning and fall back to SQLite rather than failing.
Tenant scoping across scopes#
In SQLite mode each scope is a distinct file, so they never collide. In
Postgres mode they share tables, so each scope gets a distinct project_id
built from the project’s stable project_asset_id and the scope name:
"<asset_id>:<scope>". iter_scope_stores() enumerates exactly the same
scope set the SQLite walk did, so nw.graph.iter_all_annotations() yields
each annotation once under either backend.
Functions
|
Resolve the configured graph backend from the environment. |
|
Open the annotation store for one scope, backend chosen by env. |
|
Yield an iterator of open stores, one per scope, backend chosen by env. |
|
Map a legacy per-scope SQLite filename to its scope name. |
Classes
- nw.graph_backend.iter_scope_stores(scope_paths, *, asset_id, env=None)[source]#
Yield an iterator of open stores, one per scope, backend chosen by env.
The provenance walk in
nw.graph.iter_all_annotations()needs every store under a project. In SQLite mode that’s “every existing per-scope file”; in Postgres mode it’s “every scope’s tenant” — and this generator enumerates exactly the same scope set under both backends, so each annotation is yielded once either way.- Parameters:
scope_paths (
Mapping[str,Path]) –{scope_name: legacy_sqlite_path}— only paths that exist on disk are visited in SQLite mode; in Postgres mode every listed scope is visited (existence is a DB question, not a file one).asset_id (
str) – The project’sproject_asset_id(Postgres tenant anchor).env (
Mapping[str,str] |None) – Environment mapping. Defaults toos.environ.
- Yields:
A single iterator that produces each scope’s open store in turn. Each store is closed before the next is opened, so callers must consume annotations eagerly per store (which the walk does).
- Return type:
- nw.graph_backend.open_graph_store(db_path, *, asset_id, scope=None, rate=None, env=None)[source]#
Open the annotation store for one scope, backend chosen by env.
The single place that decides SQLite-vs-Postgres for a graph store. Callers pass the legacy SQLite path (still the source of truth for where the file lives in SQLite mode) plus the project’s
asset_id(the tenant anchor in Postgres mode).- Parameters:
db_path (
Path|str) – The per-scope SQLite path (used directly in SQLite mode; in Postgres mode only its filename is used to derive the scope).asset_id (
str) – The project’s stableproject_asset_id— the Postgres tenant anchor. Ignored in SQLite mode.scope (
Optional[str]) – The logical scope name ("graph"/"storyboard"/"alignment"/ …). Defaults to deriving it fromdb_path.rate (
Optional[int]) – Project-wide rate for the Postgres store. Defaults to lacing’sDEFAULT_RATE. Ignored in SQLite mode.env (
Mapping[str,str] |None) – Environment mapping. Defaults toos.environ.
- Return type:
IntervalAnnotationStore- Returns:
A live
IntervalAnnotationStore—SqliteStore(default) or a tenant-scopedPostgresStore. Caller closes it (or uses it as a context manager).
- nw.graph_backend.scope_name_for_db(db_path)[source]#
Map a legacy per-scope SQLite filename to its scope name.
project.annot.sqlite→"graph";storyboard.annot.sqlite→"storyboard";alignment.annot→"alignment". Anything else maps to the file’s stem so a new store kind gets a stable scope automatically.- Return type: