"""JSON IR (intermediate representation) Pydantic models. See ARCHITECTURE.md ยง7 for the schema. Initial scope: single-table; filter, group_by, agg, order_by, limit. Joins, having, offset, boolean tree filters are deferred to later versions. """ from typing import Any, Literal from pydantic import BaseModel, Field FilterOp = Literal[ "=", "!=", "<", "<=", ">", ">=", "in", "not_in", "is_null", "is_not_null", "like", "between", ] AggFn = Literal["count", "count_distinct", "sum", "avg", "min", "max"] ValueType = Literal["int", "decimal", "string", "datetime", "date", "bool"] SortDir = Literal["asc", "desc"] class ColumnSelect(BaseModel): kind: Literal["column"] = "column" column_id: str alias: str | None = None class AggSelect(BaseModel): kind: Literal["agg"] = "agg" fn: AggFn column_id: str | None = None alias: str | None = None SelectItem = ColumnSelect | AggSelect class FilterClause(BaseModel): column_id: str op: FilterOp value: Any value_type: ValueType class OrderByClause(BaseModel): column_id: str dir: SortDir = "asc" class QueryIR(BaseModel): ir_version: str = "1.0" source_id: str table_id: str select: list[SelectItem] filters: list[FilterClause] = Field(default_factory=list) group_by: list[str] = Field(default_factory=list) order_by: list[OrderByClause] = Field(default_factory=list) limit: int | None = None