The InfluxQL SELECT subset InfluxElixir.Client.Local answers, shaped
the way InfluxDB 3 answers it (verified against the engine; see
docs/design/2026-09-23_local-influxql.md).
InfluxQL is not SQL with other keywords. Every row carries
"iox::measurement" and "time"; rows come back in time order; a row with
no selected field value is dropped; an unknown column or measurement is an
empty result, not an error; aggregates are named after the function
(mean, count, ...) and put time at the epoch, except a lone selector
(MAX, MIN, FIRST, LAST), which returns its point's time and tags;
LIMIT and OFFSET apply per GROUP BY series.
This module is pure. parse/1 turns the statement into a query map;
run/3 shapes rows the caller has already filtered with the statement's
WHERE clause (Client.Local runs it through its SQL engine).
Refused by name, rather than answered wrongly: GROUP BY time(...) (the
engine fills every empty bucket), regular expressions, fill(), INTO,
SLIMIT/SOFFSET, subqueries, GROUP BY *, functions other than
MEAN SUM COUNT MIN MAX FIRST LAST, F(*) other than COUNT(*), and
plain columns beside anything but a single selector.
Summary
Functions
Parses an InfluxQL SELECT. Returns {:error, message} for syntax the
engine rejects and for the constructs listed in the moduledoc.
Shapes rows — the measurement's points already filtered by the
statement's WHERE, as SQL row maps with "time" — into the engine's
answer. tags names the measurement's tag columns; everything else but
time is a field.
Types
@type item() :: :star | {:column, binary(), binary()} | {:aggregate, binary(), binary() | :star, binary() | nil}
A select item: every column, a column, or a function of a column.
@type query() :: %{ items: [item()], measurement: binary(), where: binary() | nil, group_by: [binary()], descending: boolean(), limit: non_neg_integer() | nil, offset: non_neg_integer() }
A parsed SELECT.
Functions
Parses an InfluxQL SELECT. Returns {:error, message} for syntax the
engine rejects and for the constructs listed in the moduledoc.
Shapes rows — the measurement's points already filtered by the
statement's WHERE, as SQL row maps with "time" — into the engine's
answer. tags names the measurement's tag columns; everything else but
time is a field.