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