Coverage for src / lexigram / contracts / data / types.py: 1%
73 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-19 05:41 +0800
1"""Value types for data access contracts."""
3from __future__ import annotations
5from dataclasses import dataclass
6from dataclasses import field as dc_field
7from enum import StrEnum
8from typing import Any, Literal, TypeAlias
10__all__ = [
11 "AndExpr",
12 "CursorPaginationSpec",
13 "FieldContains",
14 "FieldEq",
15 "FieldGt",
16 "FieldGte",
17 "FieldIn",
18 "FieldLt",
19 "FieldLte",
20 "FieldNeq",
21 "FilterExpression",
22 "LogicalOperator",
23 "NotExpr",
24 "OrExpr",
25 "PaginationSpec",
26 "ProjectionSpec",
27 "SortSpecification",
28]
31class LogicalOperator(StrEnum):
32 """Logical combination operator for filter groups."""
34 AND = "and"
35 OR = "or"
38@dataclass(frozen=True)
39class FieldEq:
40 """Equality predicate: ``field == value``."""
42 field: str
43 value: Any
46@dataclass(frozen=True)
47class FieldGt:
48 """Greater-than predicate: ``field > value``."""
50 field: str
51 value: Any
54@dataclass(frozen=True)
55class FieldLt:
56 """Less-than predicate: ``field < value``."""
58 field: str
59 value: Any
62@dataclass(frozen=True)
63class FieldGte:
64 """Greater-than-or-equal predicate: ``field >= value``."""
66 field: str
67 value: Any
70@dataclass(frozen=True)
71class FieldLte:
72 """Less-than-or-equal predicate: ``field <= value``."""
74 field: str
75 value: Any
78@dataclass(frozen=True)
79class FieldNeq:
80 """Not-equal predicate: ``field != value``."""
82 field: str
83 value: Any
86@dataclass(frozen=True)
87class FieldContains:
88 """Substring predicate: ``value in field``."""
90 field: str
91 value: Any
94@dataclass(frozen=True)
95class FieldIn:
96 """Membership predicate: ``field in values``."""
98 field: str
99 values: tuple[Any, ...]
102@dataclass(frozen=True)
103class AndExpr:
104 """Logical conjunction of two filter expressions."""
106 left: FilterExpression
107 right: FilterExpression
110@dataclass(frozen=True)
111class OrExpr:
112 """Logical disjunction of two filter expressions."""
114 left: FilterExpression
115 right: FilterExpression
118@dataclass(frozen=True)
119class NotExpr:
120 """Logical negation of a filter expression."""
122 expr: FilterExpression
125FilterExpression: TypeAlias = (
126 FieldEq
127 | FieldGt
128 | FieldGte
129 | FieldLt
130 | FieldLte
131 | FieldNeq
132 | FieldContains
133 | FieldIn
134 | AndExpr
135 | OrExpr
136 | NotExpr
137)
138"""Composable predicate tree for repository queries.
140Build expressions using the concrete leaf/node types:
142 >>> expr = AndExpr(FieldEq("status", "active"), FieldGt("age", 18))
143"""
146# ---------------------------------------------------------------------------
147# Sort specification
148# ---------------------------------------------------------------------------
151@dataclass(frozen=True)
152class SortSpecification:
153 """Specifies ordering for a query result.
155 Attributes:
156 field: Name of the field to sort on.
157 direction: Sort direction — ``"asc"`` or ``"desc"``.
158 """
160 field: str
161 direction: Literal["asc", "desc"] = "asc"
164# ---------------------------------------------------------------------------
165# Pagination specifications
166# ---------------------------------------------------------------------------
169@dataclass(frozen=True)
170class PaginationSpec:
171 """Offset-based pagination parameters.
173 Attributes:
174 page: 1-based page number.
175 size: Number of results per page.
176 """
178 page: int = 1
179 size: int = 20
181 @property
182 def offset(self) -> int:
183 """Zero-based offset for the current page."""
184 return (self.page - 1) * self.size
187@dataclass(frozen=True)
188class CursorPaginationSpec:
189 """Cursor-based (keyset) pagination parameters.
191 Attributes:
192 cursor: Opaque cursor string returned from a previous response.
193 size: Number of results per page.
194 """
196 cursor: str | None = None
197 size: int = 20
200# ---------------------------------------------------------------------------
201# ProjectionProtocol specification
202# ---------------------------------------------------------------------------
205@dataclass(frozen=True)
206class ProjectionSpec:
207 """Describes which fields to include or exclude from query results.
209 Attributes:
210 include: Explicit set of field names to return.
211 exclude: Names of fields to omit from the result.
212 """
214 include: frozenset[str] = dc_field(default_factory=frozenset)
215 exclude: frozenset[str] = dc_field(default_factory=frozenset)