defmodule ExSQL.AST.Select do @moduledoc """ A `SELECT` statement. `columns` is a list of `:star`, `{:qualified_star, table}`, or `{expr, alias | nil}` tuples. Expressions are tagged tuples as produced by `ExSQL.Parser` — see that module for the expression grammar. `from` is a join tree: * `nil` — no FROM clause * `{:table, name, alias | nil}` * `{:subquery, %Select{}, alias | nil}` * `{:join, type, left, right, constraint}` where `type` is `%{natural: boolean, left: boolean}`, `left` is a join tree, `right` a single source, and `constraint` is `nil`, `{:on, expr}`, or `{:using, [name]}`. Comma joins, `CROSS JOIN`, and `INNER JOIN` all parse to `left: false` — they differ only as planner hints in SQLite. """ defstruct columns: [], from: nil, where: nil, group_by: [], having: nil, windows: %{}, order_by: [], limit: nil, offset: nil, distinct: false @type expr :: ExSQL.Parser.expr() @type join_type :: %{natural: boolean(), left: boolean()} @type constraint :: nil | {:on, expr()} | {:using, [String.t()]} @type source :: {:table, String.t(), String.t() | nil} | {:subquery, t(), String.t() | nil} | {:join, join_type(), source(), source(), constraint()} @type t :: %__MODULE__{ columns: [:star | {:qualified_star, String.t()} | {expr(), String.t() | nil}], from: source() | nil, where: expr() | nil, group_by: [expr()], having: expr() | nil, windows: %{String.t() => map()}, order_by: [{expr(), :asc | :desc}], limit: expr() | nil, offset: expr() | nil, distinct: boolean() } end