Coverage for snekql/expressions.py: 83%
29 statements
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-07 21:13 +0300
« prev ^ index » next coverage.py v7.14.1, created at 2026-06-07 21:13 +0300
1"""Query Builder expression objects shared by fields and queries."""
3from __future__ import annotations
5from dataclasses import dataclass, field
6from typing import TypeVar
8from snekql.errors import QueryConstructionError
10OwnerT = TypeVar("OwnerT")
13@dataclass(frozen=True)
14class Predicate[OwnerT]:
15 """Boolean SQL predicate for one table model.
17 Predicates are produced by column descriptor methods such as `User.email.eq`.
18 They compose with `&`, `|`, and `~` instead of Python comparison operators.
19 """
21 kind: str = ""
22 column: object | None = None
23 value: object = None
24 values: tuple[object, ...] = field(default_factory=tuple)
25 children: tuple[Predicate[OwnerT], ...] = field(default_factory=tuple)
27 def __and__(self, other: Predicate[OwnerT]) -> Predicate[OwnerT]:
28 return Predicate(kind="and", children=(self, other))
30 def __or__(self, other: Predicate[OwnerT]) -> Predicate[OwnerT]:
31 return Predicate(kind="or", children=(self, other))
33 def __invert__(self) -> Predicate[OwnerT]:
34 return Predicate(kind="not", children=(self,))
36 def __bool__(self) -> bool:
37 msg = "predicates cannot be used as booleans"
38 raise QueryConstructionError(msg)
41@dataclass(frozen=True)
42class OrderBy[OwnerT]:
43 """SQL ordering expression for one table model.
45 `OrderBy` values are produced by column descriptor methods like `.asc()` and
46 `.desc()` and consumed by select query builders.
47 """
49 column: object | None = None
50 direction: str = ""
53@dataclass(frozen=True)
54class Assignment[OwnerT]:
55 """SQL update assignment for one table model.
57 `Assignment` values are produced by update-assignable column descriptors via
58 `.to(value)` and consumed by `update(Model).set(...)`.
59 """
61 column: object | None = None
62 value: object = None