httk.data.db.store¶
The SQL store: save and fetch storable frozen dataclasses through a Database.
SqlStore is the object-level storage API on top of the schema IR
(httk.data.db.schema), the value codecs (httk.data.db.codecs),
the content identity (httk.data.db.identity), and the SQLAlchemy table
mapping (httk.data.db.mapping):
SqlStore.save()writes an instance (recursing into referenced and child-element storables) and returns its integersid, deduplicating per the class’sdeduppolicy;SqlStore.fetch()reconstructs the instance stored under asid— exactly, via the*_exactcompanion columns for rationals — with an identity guarantee: while an instance is alive, fetching its sid again returns the very same object;SqlStore.transaction()scopes several operations into one database transaction (commit on exit, roll back on exception); outside of it every operation autocommits;SqlStore.referring()finds join-objects (tags, references) pointing at a stored instance, replacing v1’s implicit codependent-data machinery;SqlStore.searcher()starts a query through the search DSL (httk.data.db.searcher), implementing thehttk.data.queryprotocols.
Deduplication semantics (ported from v1): under "content_id" an equal
instance maps to the existing row (children are not re-inserted); under
"by_value" a row matching all parent-table columns is reused — child
table contents are not part of the match, mirroring v1 which matched key
columns only; under "none" every save inserts a new row.
Two small, documented liberties: an optional child-table field saved as
None comes back as an empty container (the relational layout cannot tell
the two apart), and the identity/sid caches are best-effort — instances that
cannot be weak-referenced or hashed (e.g. records holding lists) are simply
not cached, which affects only SqlStore.sid_of() and the same-object
guarantee, never storage correctness.
Classes¶
Module Contents¶
- class httk.data.db.store.SqlStore(database: httk.data.db.engine.Database, *, create_tables: bool = True)[source]¶
Object storage for storable frozen dataclasses in a relational
Database.Tables are created on demand (first save/fetch of a class, or explicitly via
ensure_tables()) unlesscreate_tables=False, in which case the schema is expected to exist already.- ensure_tables(*classes: type) None[source]¶
Resolve each class’s schema and create its tables (and those it references, transitively).
Existing tables are left alone. Saving or fetching calls this implicitly, but calling it up front is useful to separate DDL from a data transaction (SQLite rolls back tables created inside a rolled-back transaction along with the data).
- transaction() contextlib.AbstractContextManager[None][source]¶
Scope the operations of a
withblock into one database transaction.Every
save()/fetch()(on this thread) inside the block runs on the same open connection; the transaction commits when the block exits normally and rolls back if it raises. On a rollback the identity caches are flushed, since they may name rows that no longer exist. Nesting is flat: an innertransaction()block simply joins the outer transaction. Outside any transaction block, each operation runs (and autocommits) on its own.
- save(obj: Any) int[source]¶
Store
obj(deduplicating per its class’s policy) and return its integer sid.Referenced storables and storable child elements are saved recursively first; when deduplication finds an existing row, that row’s sid is returned and no children are re-inserted.
- fetch[T](cls: type[T], sid: int) T[source]¶
Reconstruct the
clsinstance stored undersid.While a previously fetched (or saved) instance for this
(class, sid)is alive, the very same object is returned. RaisesKeyError(carrying the class and sid) when no such row exists.
- fetch_by_content_id[T](cls: type[T], key: str) T | None[source]¶
The
clsinstance whose content identity iskey, or None if not stored.Only classes with the
"content_id"dedup policy carry a content identity column;SchemaErroris raised for any other class.
- sid_of(obj: Any) int | None[source]¶
The sid under which
objwas saved or fetched through this store, else None.This consults the in-memory reverse cache only — it never probes the database — so it knows exactly the instances that passed through
save()orfetch(). Instances that cannot be hashed (a storable class holding alistfield is unhashable) are tracked by identity instead, so they resolve too; only instances that cannot be weak-referenced at all go untracked.
- searcher() httk.data.db.searcher.SqlSearcher[source]¶
A new
SqlSearcherquerying this store.The searcher runs on this store’s read path — inside an open
transaction()block it sees uncommitted writes — and reconstructs matched objects throughfetch(), so the identity cache applies.
- referring(cls: type, *, field: str, to: Any) list[Any][source]¶
All stored
clsinstances whose reference fieldfieldpoints atto.fieldmust be a reference field ofclstargetingto’s class (SchemaErrorotherwise), andtomust be known to this store — saved or fetched through it — elseValueErroris raised. Results are ordered by sid.