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 integer sid, deduplicating per the class’s dedup policy;

  • SqlStore.fetch() reconstructs the instance stored under a sid — exactly, via the *_exact companion 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 the httk.data.query protocols.

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

SqlStore

Object storage for storable frozen dataclasses in a relational Database.

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()) unless create_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 with block 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 inner transaction() 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 cls instance stored under sid.

While a previously fetched (or saved) instance for this (class, sid) is alive, the very same object is returned. Raises KeyError (carrying the class and sid) when no such row exists.

fetch_by_content_id[T](cls: type[T], key: str) T | None[source]

The cls instance whose content identity is key, or None if not stored.

Only classes with the "content_id" dedup policy carry a content identity column; SchemaError is raised for any other class.

sid_of(obj: Any) int | None[source]

The sid under which obj was 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() or fetch(). Instances that cannot be hashed (a storable class holding a list field 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 SqlSearcher querying this store.

The searcher runs on this store’s read path — inside an open transaction() block it sees uncommitted writes — and reconstructs matched objects through fetch(), so the identity cache applies.

referring(cls: type, *, field: str, to: Any) list[Any][source]

All stored cls instances whose reference field field points at to.

field must be a reference field of cls targeting to’s class (SchemaError otherwise), and to must be known to this store — saved or fetched through it — else ValueError is raised. Results are ordered by sid.