// Value expression model: the single declarative way to express computed // values in dao methods — update SET expressions and criteria right sides. // Structural AST (never SQL strings): column references are Field objects // (definition-time ownership checks), values bind as parameters at render // time. New node kinds can be added without touching existing declarations. import type { Field } from './dsl.js'; /** Binary operator on numeric values. */ export type BinOp = 'add' | 'sub' | 'mul' | 'div'; /** A value expression: column reference / literal / method parameter / binary * operation. Recursive — leaves are col/lit/param, bin combines them. */ export type ValueExpr = | { kind: 'col'; field: Field } | { kind: 'lit'; value: string | number } | { kind: 'param'; name: string } | { kind: 'bin'; op: BinOp; left: ValueExpr; right: ValueExpr }; /** An update SET assignment: `col = expr` (besides the direct-assignment * columns carried by the args entity — a column must not appear in both). */ export interface SetExpr { col: Field; expr: ValueExpr; } export function col(field: Field): ValueExpr { return { kind: 'col', field }; } export function lit(value: string | number): ValueExpr { return { kind: 'lit', value }; } export function param(name: string): ValueExpr { return { kind: 'param', name }; } export function bin(op: BinOp, left: ValueExpr, right: ValueExpr): ValueExpr { return { kind: 'bin', op, left, right }; } /** Convenience builders for the common self-increment/decrement shapes. */ export const incr = (field: Field, by: ValueExpr): SetExpr => ({ col: field, expr: bin('add', col(field), by) }); export const decr = (field: Field, by: ValueExpr): SetExpr => ({ col: field, expr: bin('sub', col(field), by) }); /** Aggregate expression result of an aggregate query column. */ export interface ComputeExpr { fn: 'sum' | 'avg' | 'count'; /** Column the function applies to; absent for count(*). */ field?: Field; } /** Aggregate expressions: Compute.sum(col) / Compute.avg(col) / Compute.count(). */ export const Compute = { sum(field: Field): ComputeExpr { return { fn: 'sum', field }; }, avg(field: Field): ComputeExpr { return { fn: 'avg', field }; }, count(): ComputeExpr { return { fn: 'count' }; }, };