qmd_py.db.models¶
The SQLModel table definitions: User, Collection, CollectionGrant,
Content, Document, LlmCache, EmbeddingModel, and their
relationships — the schema Architecture › Storage
describes.
models ¶
SQLModel table definitions.
Table classes here are plain SQLAlchemy models underneath (SQLModel is a thin
Pydantic layer on top) - all async DB access goes through SQLAlchemy's own
AsyncEngine/AsyncSession (see engine.py), never SQLModel's sync-oriented
Session/create_engine helpers. Columns SQLModel's type system doesn't
know natively (TSVECTOR, pgvector.Vector) use the sa_column= escape
hatch, same as plain SQLAlchemy would need.
Note on search_vector: this is a plain, app-maintained TSVECTOR column,
NOT a Postgres GENERATED ALWAYS AS (...) STORED column - a generated
column's expression can only reference columns in its own table, but the
document body lives in Content.doc (joined via hash), not in
Document itself. It's kept in sync by update_document_search_vector()
in the search module (ported from the TS updateDocumentSearchVector),
called wherever a document's title/path/body changes - the same discipline
the working TS/Postgres implementation already uses successfully.
Per-model embedding tables (embeddings_<slug>) are NOT defined here -
they're created dynamically at runtime once a model's dimension is known
(see search/vector.py, Phase 5), mirroring the TS version's lazy vector
column creation but non-destructively (one table per model, never dropped
on a model switch).
User ¶
Bases: SQLModel
Exactly one row for now (the mocked single-user case) - see auth.py.
global_context is the TS version's context add / ("applies to all
collections") - user-scoped here rather than a single system-wide KV
row, since in a real multi-user future each user reasonably wants their
own global context, not one shared by everyone.
Collection ¶
Bases: SQLModel
Replaces the TS version's bare documents.collection TEXT tag with a
real, owned entity - the prerequisite for per-collection ACL. name is
scoped per-owner (UNIQUE(owner_user_id, name)), not globally unique like
the TS version's store_collections.name primary key.
Per-path context text (the TS version's context add <path> "text",
where <path> can be the collection root or a sub-path) lives in
CollectionContext, not as a single string field here - the TS model
supports many contexts per collection, keyed by path prefix.
CollectionContext ¶
Bases: SQLModel
One row per (collection, path_prefix) context entry - path_prefix
is "" for the collection root (context add marq://coll/ with no
sub-path), or a relative sub-path (context add marq://coll/notes).
CollectionGrant ¶
Bases: SQLModel
Additive ACL table - unpopulated beyond the implicit owner today.
can_access() in auth.py is mocked to always return True regardless of
whether a grant row exists; wiring this table into real checks later is
additive, not a rearchitecture.
Content ¶
Bases: SQLModel
Content-addressable storage - unchanged from the TS design (it's good, not legacy): identical document bodies dedupe across paths and collections by hash.
Document ¶
Bases: SQLModel
collection_id FK replaces the TS version's bare TEXT tag;
created_at/modified_at are real TIMESTAMPTZ (not TS's TEXT ISO
strings); active is a real BOOLEAN (not TS's INTEGER 0/1).
LlmCache ¶
Bases: SQLModel
result is JSONB (not TS's TEXT) - queryable, and the natural type
for what's always JSON-serialized data anyway.
EmbeddingModel ¶
Bases: SQLModel
Registry of embedding models that have ever been used - each active
row corresponds to one dynamically-created embeddings_<slug> table
(see search/vector.py, Phase 5), fixing the TS version's one-model-at-
a-time limitation.
role
class-attribute
instance-attribute
¶
'embed' | 'rerank' | 'generate' - CHECK constraint below, not an enum type.