sqlode/query_ir

Intermediate representation shared between the query parser and the query analyzer.

This module defines two layers:

The expression-aware IR is intended to become the single semantic input for type inference; RawExpr / UnstructuredStmt remain only as explicit diagnostic hooks for concrete IR gaps.

Types

pub type Assignment {
  Assignment(column: String, value: Expr)
}

Constructors

  • Assignment(column: String, value: Expr)
pub type CaseBranch {
  CaseBranch(when_: Expr, then: Expr)
}

Constructors

A CTE definition. columns is the explicit column list when present (name(c1, c2) AS (…)). body is the nested statement.

pub type CteDef {
  CteDef(
    name: String,
    columns: List(String),
    body: Stmt,
    recursive: Bool,
  )
}

Constructors

  • CteDef(
      name: String,
      columns: List(String),
      body: Stmt,
      recursive: Bool,
    )

The expression AST. Designed to cover the subset of SQL that sqlode needs to infer parameter and result-column types for the complex fixtures (CTE + window + CASE, LATERAL + COALESCE, EXISTS

  • nested CASE, INSERT..SELECT..RETURNING).
pub type Expr {
  NullLit
  BoolLit(value: Bool)
  StringLit(value: String)
  NumberLit(value: String)
  Param(index: Int, raw: String)
  ColumnRef(table: option.Option(String), name: String)
  StarRef(table: option.Option(String))
  Unary(op: String, arg: Expr)
  Binary(op: String, left: Expr, right: Expr)
  Func(
    name: String,
    args: List(FuncArg),
    distinct: Bool,
    filter: option.Option(Expr),
    over: option.Option(WindowSpec),
  )
  Cast(expr: Expr, target_type: String)
  Case(
    scrutinee: option.Option(Expr),
    branches: List(CaseBranch),
    else_: option.Option(Expr),
  )
  InExpr(expr: Expr, source: InSource, negated: Bool)
  Exists(core: SelectCore, negated: Bool)
  ScalarSubquery(core: SelectCore)
  Quantified(
    op: String,
    left: Expr,
    quantifier: Quantifier,
    right: Expr,
  )
  Between(expr: Expr, low: Expr, high: Expr, negated: Bool)
  IsCheck(expr: Expr, predicate: IsPredicate, negated: Bool)
  LikeExpr(
    expr: Expr,
    op: LikeOp,
    pattern: Expr,
    escape: option.Option(Expr),
    negated: Bool,
  )
  ArrayLit(elements: List(Expr))
  Tuple(elements: List(Expr))
  Macro(name: String, body: List(lexer.Token))
  RawExpr(reason: String, tokens: List(lexer.Token))
}

Constructors

  • NullLit

    NULL

  • BoolLit(value: Bool)

    TRUE, FALSE

  • StringLit(value: String)

    String literal

  • NumberLit(value: String)

    Numeric literal; string form preserves precision for downstream callers and lets us decide int vs float without reparsing.

  • Param(index: Int, raw: String)

    Parameter placeholder: $1, ?, ?1, :name, etc. index is the 1-based index sqlode assigns to the placeholder.

  • ColumnRef(table: option.Option(String), name: String)

    Column reference (col or table.col).

  • StarRef(table: option.Option(String))

    t.* or * — only valid inside COUNT(*), really.

  • Unary(op: String, arg: Expr)

    Unary prefix operator.

  • Binary(op: String, left: Expr, right: Expr)

    Binary operator (arithmetic, comparison, logical, string, JSON).

  • Func(
      name: String,
      args: List(FuncArg),
      distinct: Bool,
      filter: option.Option(Expr),
      over: option.Option(WindowSpec),
    )

    Function call. distinct covers COUNT(DISTINCT x). filter and over carry the optional tail clauses.

  • Cast(expr: Expr, target_type: String)

    CAST(expr AS type) or the shorthand expr::type.

  • Case(
      scrutinee: option.Option(Expr),
      branches: List(CaseBranch),
      else_: option.Option(Expr),
    )

    CASE [scrutinee] WHEN … THEN … ELSE … END.

  • InExpr(expr: Expr, source: InSource, negated: Bool)

    expr [NOT] IN …

  • Exists(core: SelectCore, negated: Bool)

    [NOT] EXISTS (subquery)

  • ScalarSubquery(core: SelectCore)

    Correlated scalar subquery.

  • Quantified(
      op: String,
      left: Expr,
      quantifier: Quantifier,
      right: Expr,
    )

    left op ANY|ALL (right)right may be a subquery or array.

  • Between(expr: Expr, low: Expr, high: Expr, negated: Bool)

    expr BETWEEN low AND high.

  • IsCheck(expr: Expr, predicate: IsPredicate, negated: Bool)

    expr IS [NOT] NULL / IS [NOT] TRUE|FALSE|UNKNOWN.

  • LikeExpr(
      expr: Expr,
      op: LikeOp,
      pattern: Expr,
      escape: option.Option(Expr),
      negated: Bool,
    )

    [NOT] LIKE / [NOT] ILIKE / [NOT] SIMILAR TO.

  • ArrayLit(elements: List(Expr))

    ARRAY[a, b, c].

  • Tuple(elements: List(Expr))

    Tuple / row constructor (a, b, c).

  • Macro(name: String, body: List(lexer.Token))

    sqlode.arg(name) / sqlode.narg(name) / sqlode.slice(name) / sqlode.embed(table) — sqlode-specific macros.

  • RawExpr(reason: String, tokens: List(lexer.Token))

    Explicit unsupported-expression marker. Analyzer passes surface UnsupportedExpression when inference hits this node.

A table or subquery in the FROM clause.

pub type FromItem {
  TableRef(name: String, alias: option.Option(String))
  SubqueryRef(
    tokens: List(lexer.Token),
    alias: option.Option(String),
  )
}

Constructors

Items in a FROM clause.

pub type FromItemEx {
  FromTable(name: String, alias: option.Option(String))
  FromSubquery(
    core: SelectCore,
    alias: String,
    column_aliases: List(String),
  )
  FromValues(
    rows: List(List(Expr)),
    alias: String,
    column_aliases: List(String),
  )
  FromJoin(
    left: FromItemEx,
    right: FromItemEx,
    kind: JoinKind,
    on: JoinOn,
    lateral: Bool,
  )
}

Constructors

  • FromTable(name: String, alias: option.Option(String))
  • FromSubquery(
      core: SelectCore,
      alias: String,
      column_aliases: List(String),
    )
  • FromValues(
      rows: List(List(Expr)),
      alias: String,
      column_aliases: List(String),
    )
  • FromJoin(
      left: FromItemEx,
      right: FromItemEx,
      kind: JoinKind,
      on: JoinOn,
      lateral: Bool,
    )
pub type FuncArg {
  FuncArg(expr: Expr)
}

Constructors

  • FuncArg(expr: Expr)
pub type InSource {
  InList(values: List(Expr))
  InSubquery(core: SelectCore)
  InSliceMacro(name: String)
}

Constructors

  • InList(values: List(Expr))
  • InSubquery(core: SelectCore)
  • InSliceMacro(name: String)

    IN <sqlode.slice(name)> — a sqlode-specific variadic list.

pub type InsertSource {
  InsertValues(rows: List(List(Expr)))
  InsertSelect(core: SelectCore)
  InsertDefaultValues
}

Constructors

  • InsertValues(rows: List(List(Expr)))
  • InsertSelect(core: SelectCore)
  • InsertDefaultValues
pub type IsPredicate {
  IsNull
  IsTrue
  IsFalse
  IsUnknown
  IsDistinctFrom(target: Expr)
}

Constructors

  • IsNull
  • IsTrue
  • IsFalse
  • IsUnknown
  • IsDistinctFrom(target: Expr)

A JOIN clause.

pub type JoinClause {
  JoinClause(
    table_name: String,
    alias: option.Option(String),
    on_tokens: option.Option(List(lexer.Token)),
  )
}

Constructors

pub type JoinKind {
  InnerJoin
  LeftJoin
  RightJoin
  FullJoin
  CrossJoin
}

Constructors

  • InnerJoin
  • LeftJoin
  • RightJoin
  • FullJoin
  • CrossJoin
pub type JoinOn {
  JoinOnExpr(expr: Expr)
  JoinUsing(columns: List(String))
  JoinNoCondition
}

Constructors

  • JoinOnExpr(expr: Expr)
  • JoinUsing(columns: List(String))
  • JoinNoCondition
pub type LikeOp {
  Like
  Ilike
  SimilarTo
}

Constructors

  • Like
  • Ilike
  • SimilarTo
pub type NullsOrder {
  NullsFirst
  NullsLast
}

Constructors

  • NullsFirst
  • NullsLast
pub type OrderKey {
  OrderKey(
    expr: Expr,
    descending: Bool,
    nulls: option.Option(NullsOrder),
  )
}

Constructors

pub type Quantifier {
  QAny
  QAll
  QSome
}

Constructors

  • QAny
  • QAll
  • QSome
pub type RichQuery {
  RichQuery(
    base: model.ParsedQuery,
    tokens: List(lexer.Token),
    stmt: Stmt,
  )
}

Constructors

The body of a SELECT. Reused for subqueries (scalar, IN, EXISTS) and for INSERT..SELECT.

pub type SelectCore {
  SelectCore(
    distinct: Bool,
    select_items: List(SelectItemEx),
    from: List(FromItemEx),
    where_: option.Option(Expr),
    group_by: List(Expr),
    having: option.Option(Expr),
    order_by: List(OrderKey),
    limit: option.Option(Expr),
    offset: option.Option(Expr),
    set_op: option.Option(SetOp),
  )
}

Constructors

A single item in a SELECT list.

pub type SelectItem {
  StarItem(table_prefix: option.Option(String))
  ExpressionItem(
    tokens: List(lexer.Token),
    alias: option.Option(String),
  )
}

Constructors

A select item in the expression-aware IR.

pub type SelectItemEx {
  StarEx(table_prefix: option.Option(String))
  ExprItem(expr: Expr, alias: option.Option(String))
}

Constructors

  • StarEx(table_prefix: option.Option(String))

    *, table.*

  • ExprItem(expr: Expr, alias: option.Option(String))

    An expression, possibly aliased. origin records the source table when the expression is a simple qualified column, so result-column resolution can skip the token rescan.

pub type SetOp {
  SetOp(kind: SetOpKind, all: Bool, right: SelectCore)
}

Constructors

pub type SetOpKind {
  Union
  Intersect
  Except
}

Constructors

  • Union
  • Intersect
  • Except

Top-level statement structure extracted from the token list.

pub type SqlStatement {
  SelectStatement(
    select_items: List(SelectItem),
    from: List(FromItem),
    joins: List(JoinClause),
    where_tokens: option.Option(List(lexer.Token)),
    group_by_tokens: option.Option(List(lexer.Token)),
    having_tokens: option.Option(List(lexer.Token)),
    order_by_tokens: option.Option(List(lexer.Token)),
    limit_tokens: option.Option(List(lexer.Token)),
  )
  InsertStatement(
    table_name: String,
    columns: List(String),
    value_groups: List(List(lexer.Token)),
    returning_tokens: option.Option(List(lexer.Token)),
  )
  UpdateStatement(
    table_name: String,
    set_tokens: List(lexer.Token),
    where_tokens: option.Option(List(lexer.Token)),
    returning_tokens: option.Option(List(lexer.Token)),
  )
  DeleteStatement(
    table_name: String,
    where_tokens: option.Option(List(lexer.Token)),
    returning_tokens: option.Option(List(lexer.Token)),
  )
  UnstructuredStatement(tokens: List(lexer.Token))
}

Constructors

Top-level statement shape in the expression-aware IR.

Every variant carries its own list of CTE definitions so an INSERT/UPDATE/DELETE prefixed with WITH (fixture 4) is modelled end-to-end instead of being stripped at a boundary.

pub type Stmt {
  SelectStmt(ctes: List(CteDef), core: SelectCore)
  InsertStmt(
    ctes: List(CteDef),
    table: String,
    columns: List(String),
    source: InsertSource,
    returning: List(SelectItemEx),
  )
  UpdateStmt(
    ctes: List(CteDef),
    table: String,
    alias: option.Option(String),
    assignments: List(Assignment),
    from: List(FromItemEx),
    where_: option.Option(Expr),
    returning: List(SelectItemEx),
  )
  DeleteStmt(
    ctes: List(CteDef),
    table: String,
    alias: option.Option(String),
    using: List(FromItemEx),
    where_: option.Option(Expr),
    returning: List(SelectItemEx),
  )
  UnstructuredStmt(reason: String, tokens: List(lexer.Token))
}

Constructors

StructuredQuery wraps TokenizedQuery with the structured IR. The raw token list is preserved for backward compatibility with code that hasn’t migrated to the structured representation yet.

pub type StructuredQuery {
  StructuredQuery(
    base: model.ParsedQuery,
    tokens: List(lexer.Token),
    statement: SqlStatement,
  )
}

Constructors

pub type TokenizedQuery {
  TokenizedQuery(
    base: model.ParsedQuery,
    tokens: List(lexer.Token),
  )
}

Constructors

pub type WindowSpec {
  WindowSpec(
    partition_by: List(Expr),
    order_by: List(OrderKey),
    frame: option.Option(List(lexer.Token)),
  )
}

Constructors

Search Document