httk.data.db.schema

Schema IR: resolve a storable dataclass into the relational schema that drives storage.

A storable class is a plain frozen dataclass declared with the stdlib-only marker vocabulary from httk-core (Indexed, Unique, Skip, Shape, StorageInfo, stored_property). resolve_schema() reads the class once — dataclass fields, Annotated markers, stored properties, and the optional class-level or externally registered StorageInfo — and produces a TableSchema, the single source of truth from which the SQL layer derives DDL, inserts, selects, and reconstruction alike.

Resolution rules (field annotation, then the resulting relational shape):

  • int/float/str/bool/bytes — one scalar column named after the field (bool is its own column kind, never folded into int).

  • X | None — the field is optional; all of its columns become nullable.

  • a type with a registered ValueCodec (fractions.Fraction, FracScalar, SurdScalar, datetime.datetime, …) — the codec’s columns, named by appending each suffix to the field name.

  • Annotated[FracVector, Shape(r, c)] with r >= 1 — a fixed-shape tensor stored inline: r*c float columns name_0 .. name_{r*c-1} plus one name_exact text column holding the canonical exact tensor text.

  • Annotated[FracVector, Shape(0, c)] — variable rows in a child table <parent>_<name>, each row c float columns plus a name_exact text column with the same exact encoding per row.

  • list[T] / homogeneous tuple[T, ...] — a child table: scalar or codec-typed elements store their columns per row; storable-dataclass elements store one name_sid foreign-key column per row.

  • another storable frozen dataclass (optionally | None) — a reference: one name_sid foreign-key column.

  • Annotated[..., Skip()] — omitted from storage (the field must have a default so instances can be reconstructed without it).

  • Annotated[..., Related(...)] — relationship metadata carried on the resolved FieldSpec; valid only on reference fields and on lists/tuples of storable classes.

  • a stored_property — resolved like a field from its return annotation, flagged derived: stored and queryable, recomputed (not passed to __init__) on reconstruction.

The store layer additionally manages a sid integer primary key and a content_id text column on every table (and <parent>_sid / <name>_index columns on child tables); those never appear in TableSchema.fields, and declaring a field named sid or content_id is an error.

Attributes

ScalarKind

The five scalar column kinds a storage backend must provide.

FieldRole

How a stored field maps onto the relational model.

Exceptions

SchemaError

A class or field cannot be resolved into a storage schema; the message names both.

Classes

ColumnSpec

One scalar column of a table.

ChildTableSpec

The out-of-line child table backing a variable-length field.

FieldSpec

The resolved storage shape of one stored field (or stored property).

TableSchema

The resolved relational schema of one storable class.

Functions

snake_case(→ str)

The default table name for a class name: CamelCase to camel_case (acronym-aware).

register_schema_override(→ None)

Register an external StorageInfo for a class that cannot declare one.

resolve_schema(→ TableSchema)

Resolve (and cache) the TableSchema of a storable dataclass.

Module Contents

type httk.data.db.schema.ScalarKind = Literal['int', 'float', 'str', 'bool', 'bytes'][source]

The five scalar column kinds a storage backend must provide.

type httk.data.db.schema.FieldRole = Literal['scalar', 'encoded', 'fixed_array', 'child', 'reference'][source]

How a stored field maps onto the relational model.

exception httk.data.db.schema.SchemaError[source]

Bases: Exception

A class or field cannot be resolved into a storage schema; the message names both.

class httk.data.db.schema.ColumnSpec[source]

One scalar column of a table.

name: str[source]

The column name.

kind: httk.data.db.codecs.ScalarKind[source]

The scalar kind of the column.

nullable: bool = False[source]

Whether the column accepts NULL (all columns of an optional field do).

indexed: bool = False[source]

Whether a single-column index is requested (Indexed).

unique: bool = False[source]

Whether a unique index is requested (Unique).

class httk.data.db.schema.ChildTableSpec[source]

The out-of-line child table backing a variable-length field.

Only the per-element value columns are listed; the store layer adds the <parent>_sid foreign key and <name>_index ordering columns.

table_name: str[source]

The child table name, <parent table>_<field>.

element_columns: tuple[ColumnSpec, Ellipsis][source]

The value column(s) of one element row.

target: type | None = None[source]

The storable element class when rows are foreign keys, else None.

class httk.data.db.schema.FieldSpec[source]

The resolved storage shape of one stored field (or stored property).

field: str[source]

The dataclass field (or stored property) name.

python_type: Any[source]

The field’s value type with markers and optionality stripped.

role: FieldRole[source]

How the field maps onto the relational model.

columns: tuple[ColumnSpec, Ellipsis] = ()[source]

The field’s columns in the parent table (empty for the child role).

codec_name: str | None = None[source]

The value codec encoding this field (or its child elements), if any.

shape: httk.core.Shape | None = None[source]

The Shape marker for tensor-valued fields, if any.

child: ChildTableSpec | None = None[source]

The child table specification for the child role, else None.

target: type | None = None[source]

The referenced storable class for reference (and child-of-storable) fields.

related: httk.core.Related | None = None[source]

The Related relationship marker of the field, if any.

Only reference fields and child fields of storable elements can carry one; the marker’s metadata flows into the relationships an entry provider emits for the field.

derived: bool = False[source]

stored and queryable, recomputed rather than passed to __init__ on reconstruction.

Type:

True for stored_property values

optional: bool = False[source]

True when the annotation was X | None; all columns are then nullable.

class httk.data.db.schema.TableSchema[source]

The resolved relational schema of one storable class.

cls: type[source]

The storable dataclass this schema was resolved from.

table_name: str[source]

The table name (storage_name or the snake-cased class name).

fields: tuple[FieldSpec, Ellipsis][source]

The stored fields, dataclass fields first (in declaration order), then stored properties.

The store-managed sid and content_id columns are not fields and do not appear here.

composite_indexes: tuple[tuple[str, Ellipsis], Ellipsis][source]

The indexes declarations, resolved to column names.

dedup: httk.core.DedupPolicy[source]

The deduplication policy applied when instances are saved.

The class’s links relationship declarations.

Each link is validated: every non-None endpoint names an existing reference field of the class (child fields are not valid endpoints — a link row expresses exactly one FROM→TO pair).

field(name: str) FieldSpec[source]

Return the FieldSpec named name; raise SchemaError if absent.

referenced_classes() tuple[type, Ellipsis][source]

The distinct storable classes this schema references (field order, no duplicates).

httk.data.db.schema.snake_case(name: str) str[source]

The default table name for a class name: CamelCase to camel_case (acronym-aware).

httk.data.db.schema.register_schema_override(cls: type, info: httk.core.StorageInfo) None[source]

Register an external StorageInfo for a class that cannot declare one.

The registered info is used by resolve_schema() whenever no explicit override argument is passed, and takes precedence over a __httk_storage__ declaration on the class itself.

httk.data.db.schema.resolve_schema(cls: type, *, override: httk.core.StorageInfo | None = None) TableSchema[source]

Resolve (and cache) the TableSchema of a storable dataclass.

The effective StorageInfo is, in order of precedence: the explicit override argument, an info registered via register_schema_override(), the class’s own __httk_storage__ attribute, or defaults. Results are cached per (class, effective override), so repeated calls return the same TableSchema object. Reference cycles (a class referencing itself, or mutually referencing classes) are allowed and resolve without recursion loops.

Raises:

SchemaError – If the class is not a frozen dataclass or any field cannot be resolved; the message names the class and field.