Queries¶
db.select(Model) returns a SelectQuery. Chain .where(...), .order_by(...),
.limit(...), .offset(...), and .join(...) to build it, then call a terminal
method (.all(), .first(), .one(), .count(), .exists()).
SelectQuery¶
query
¶
SelectQuery: typed, chainable query builder.
SelectQuery
¶
Bases: Generic[T]
A SELECT query over a single model.
Reads rows from the table (under the database lock) and filters / orders /
limits in memory. All terminal methods (all, first, one, ...)
acquire the lock and materialize results.
join
¶
Begin a multi-model join rooted at this query's model.
Returns a :class:~tinystore.query.joins.JoinQuery; the on condition
must compare two model field proxies, e.g.
Post.author_id == User.id.
Joins¶
joins
¶
JoinQuery: in-memory INNER / LEFT joins across registered models.
Joins are evaluated in memory: every participating table is read fully and
combined with nested loops. This is deliberate and documented — TinyStore stores
rows as JSON files, so a disk-efficient join is not the goal of v1. The result
of a join is a list of :class:Row objects, one per combined row, with
attribute access by lowercased model name (row.user, row.post) and
positional access (row[0]).
Example
.. code-block:: python
rows = (
db.select(User)
.join(Post, on=Post.author_id == User.id)
.where(User.name == "Alice")
.order_by(Post.title)
.all()
)
for r in rows:
print(r.user.name, r.post.title)
Row
¶
A single joined result row.
Behaves like a tuple of model instances (in the order the models were
added to the query) and also supports attribute access by lowercased model
name. Unmatched RIGHT rows in a LEFT join contribute None to their
slot.
JoinQuery
¶
A SELECT across multiple models with in-memory joins.
Expressions¶
Field proxies (User.age) build typed expressions when compared. Predicates
combine with & (and), | (or), and ~ (not).
expressions
¶
Query expression AST.
Expressions are composable objects (no eval). Each expression implements
matches(row) where row is a stored JSON-row dict. Field proxies are
produced by Model.field access (installed as non-data class descriptors in
:mod:tinystore.model); e.g. User.name == "Alice" yields a
:class:Comparison.
Evaluation semantics (see the project plan, decision D16):
None/ missing fields are "absent", not a type error. Ordering operators againstNonereturnFalse;is_null/is_not_nullare explicit.- For
==/!=/</<=/>/>=, if both the row value and the comparison value are non-Noneand belong to incompatible runtime type groups, a :class:~tinystore.exceptions.QueryErroris raised (strict mode).
Expression
¶
Bases: ABC
Base class for all query expressions.
JoinCondition
¶
A cross-table equality predicate produced by comparing two field proxies.
Post.author_id == User.id yields JoinCondition(Post, "author_id",
User, "id"). The two sides are stored neutrally; the join resolves which
side is the newly-joined model and which is already in the result set.
FieldProxy
¶
Returned by Model.field class access; builds expressions.
User.name == "Alice" returns a :class:Comparison. Note: defining
__eq__ makes instances unhashable, which is fine (proxies are transient
builders, not stored in sets/dicts).