// AST statements (Stmt) and the WHERE-clause expression tree (Expr).
///|
/// An item in the SELECT list — either a column reference or an aggregate call.
pub(all) enum SelectExpr {
Col(ColumnRef)
Agg(Aggregation)
} derive(Debug, Eq)
///|
/// A SELECT statement.
pub(all) struct SelectStmt {
table : String
columns : Array[SelectExpr] // empty = SELECT *
where_clause : Expr?
joins : Array[JoinClause]
group_by : Array[ColumnRef]
having : Expr?
order_by : Array[OrderByClause]
limit : Int?
offset : Int?
distinct : Bool
distinct_on : Array[ColumnRef]
} derive(Debug, Eq)
///|
/// A WHERE clause expression — a tree of comparisons joined by AND / OR / NOT.
pub(all) enum Expr {
Compare(ColumnRef, Operator, Value)
CompareCols(ColumnRef, Operator, ColumnRef)
And(Array[Expr])
Or(Array[Expr])
Not(Expr)
InList(ColumnRef, Array[Value])
InSelect(ColumnRef, SelectStmt)
Between(ColumnRef, Value, Value)
IsNull(ColumnRef)
IsNotNull(ColumnRef)
AggCompare(Aggregation, Operator, Value)
CompareSelect(ColumnRef, Operator, SelectStmt)
} derive(Debug, Eq)
///|
/// Combine two expressions with AND. Flattens nested And for cleaner SQL.
pub fn Expr::and_(self : Expr, other : Expr) -> Expr {
match self {
Expr::And(arr) => {
arr.push(other)
Expr::And(arr)
}
_ => Expr::And([self, other])
}
}
///|
/// Combine two expressions with OR. Flattens nested Or for cleaner SQL.
pub fn Expr::or_(self : Expr, other : Expr) -> Expr {
match self {
Expr::Or(arr) => {
arr.push(other)
Expr::Or(arr)
}
_ => Expr::Or([self, other])
}
}
///|
/// Wrap an expression with NOT.
pub fn not_(expr : Expr) -> Expr {
Expr::Not(expr)
}
///|
/// An INSERT statement (placeholder — wired in a later ticket).
pub(all) struct InsertStmt {
table : String
columns : Array[ColumnRef]
values : Array[Array[Value]]
on_conflict : OnConflict?
returning : Array[ColumnRef]?
} derive(Debug, Eq)
///|
pub(all) enum OnConflict {
DoNothing(String)
DoUpdate(String, Array[SetClause])
} derive(Debug, Eq)
///|
pub(all) struct SetClause {
column : ColumnRef
value : Value
} derive(Debug, Eq)
///|
/// An UPDATE statement. where_clause is non-optional.
pub(all) struct UpdateStmt {
table : String
set_clauses : Array[SetClause]
where_clause : Expr
returning : Array[ColumnRef]?
} derive(Debug, Eq)
///|
/// A DELETE statement. where_clause is non-optional.
pub(all) struct DeleteStmt {
table : String
where_clause : Expr
returning : Array[ColumnRef]?
} derive(Debug, Eq)
///|
/// An INNER JOIN clause.
pub(all) struct JoinClause {
table : String
on : Expr
} derive(Debug, Eq)
///|
/// ORDER BY direction.
pub(all) enum OrderDirection {
Asc
Desc
} derive(Debug, Eq)
///|
pub(all) struct OrderByClause {
column : ColumnRef
direction : OrderDirection
} derive(Debug, Eq)
///|
/// An aggregation function call.
pub(all) enum Aggregation {
Count(ColumnRef?)
Sum(ColumnRef)
Avg(ColumnRef)
Min(ColumnRef)
Max(ColumnRef)
} derive(Debug, Eq)
// ---------------------------------------------------------------------------
// Aggregation operators (for HAVING clauses)
// ---------------------------------------------------------------------------
///|
pub fn[T : ToValue] Aggregation::gt(self : Aggregation, value : T) -> Expr {
Expr::AggCompare(self, Operator::Gt, value.to_value())
}
///|
pub fn[T : ToValue] Aggregation::gte(self : Aggregation, value : T) -> Expr {
Expr::AggCompare(self, Operator::Gte, value.to_value())
}
///|
pub fn[T : ToValue] Aggregation::lt(self : Aggregation, value : T) -> Expr {
Expr::AggCompare(self, Operator::Lt, value.to_value())
}
///|
pub fn[T : ToValue] Aggregation::lte(self : Aggregation, value : T) -> Expr {
Expr::AggCompare(self, Operator::Lte, value.to_value())
}
///|
pub fn[T : ToValue] Aggregation::eq(self : Aggregation, value : T) -> Expr {
Expr::AggCompare(self, Operator::Eq, value.to_value())
}
///|
pub fn[T : ToValue] Aggregation::neq(self : Aggregation, value : T) -> Expr {
Expr::AggCompare(self, Operator::Neq, value.to_value())
}