File size: 2,378 Bytes
6bff5d9 0721bb4 6bff5d9 0721bb4 6bff5d9 0721bb4 6bff5d9 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | """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
|