| """JSON IR (intermediate representation) Pydantic models. |
| |
| See ARCHITECTURE.md §7 for the schema. |
| |
| Scope: filter, group_by, agg, order_by, limit, plus a single-level `joins` to |
| related tables in the SAME source (KM-652 T4). having, offset, and boolean tree |
| filters are still deferred. Joins are supported on database (schema) sources only; |
| the validator rejects them on tabular sources (cross-file merge is a later step). |
| |
| With joins, `select` / `group_by` / `filters` / `order_by` may reference a |
| `column_id` from the base table OR any joined table (column_ids are globally |
| unique), so a measure in one table can be grouped by a dimension in a related one. |
| """ |
|
|
| 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"] |
| JoinType = Literal["inner", "left"] |
|
|
|
|
| class Join(BaseModel): |
| """A single equi-join to another table in the same source. |
| |
| `left_column_id` is a column already in the query (base table or an earlier |
| join); `right_column_id` is a column in `target_table_id`. The validator |
| requires the pair to match a foreign key declared in the catalog. |
| """ |
|
|
| target_table_id: str |
| left_column_id: str |
| right_column_id: str |
| type: JoinType = "inner" |
|
|
|
|
| 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 |
| joins: list[Join] = Field(default_factory=list) |
| 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 |
|
|