InfluxElixir.Client.Local.SQLClauses (InfluxElixir v0.1.40)

Copy Markdown View Source

The GROUP BY and ORDER BY clauses of a SQL text, as DataFusion reads them (verified against InfluxDB 3 Core).

GROUP BY 1, ORDER BY 2 DESC and GROUP BY bucket (a select alias) are rewritten to the select items they name before anything else reads the clauses: a position becomes the item's expression in GROUP BY and its output name in ORDER BY, an alias in GROUP BY becomes its expression. A position outside the select list is the engine's planning error.

A GROUP BY item that is a DATE_BIN(...) sets the bucket interval; the others are grouping columns, and the two combine (GROUP BY DATE_BIN(...), host: one row per bucket per host).

Summary

Types

:asc / :desc (nulls last / first), or a direction with explicit NULLS placement.

ORDER BY terms in order; a target is time, a column, an output alias or an expression.

Functions

Checks the DATE_BINs of a select list against the GROUP BY bucket (group_interval, in nanoseconds): each must be that bucket, or the double refuses the query by name.

The bare-column GROUP BY items of a statement (a quoted name as the name it holds), or nil when there are none.

The GROUP BY DATE_BIN bucket of a statement in nanoseconds, or nil. The DATE_BIN is optional: without it the executor groups by columns or produces a single scalar row; a malformed interval still surfaces.

The ORDER BY a [ASC|DESC][, b [ASC|DESC] ...] terms of the text after the table. A target may be a column, time, an output alias (the DATE_BIN alias, say) or an expression (CAST(level AS INTEGER) DESC); a target the expression parser cannot read is {:expr, {:unreadable, text}}, which unreadable_order/1 refuses by name. The direction defaults to ascending, as in SQL.

How an ORDER BY term reads as a position among count select items (verified against InfluxDB 3 Core): a whole number from 1 to count is that position; 0, a position past count and one past UInt64 are the engine's planning errors, and so is a number with a fraction or an exponent. Anything else is not a position.

Rewrites the positions and select aliases of the clauses in rest, the text after the table, to the items they name. columns is the select list; namer gives the output name of an item without an alias, or nil when the double cannot write it (the item then stands for itself).

The refusal of an ORDER BY term the double cannot read (a function it does not have, a type it does not model: CAST(x AS FLOAT)), or :ok. The engine answers it with rows or an error of its own; naming it a column, as a schema error would, answers neither.

Types

direction()

@type direction() :: :asc | :desc | {:asc | :desc, :nulls_first | :nulls_last}

:asc / :desc (nulls last / first), or a direction with explicit NULLS placement.

order_by()

@type order_by() :: [
  {binary() | {:expr, InfluxElixir.Client.Local.SQLExpr.t()}, direction()}
]

ORDER BY terms in order; a target is time, a column, an output alias or an expression.

Functions

check_date_bins(columns, group_interval)

@spec check_date_bins(binary(), non_neg_integer() | nil) :: :ok | {:error, map()}

Checks the DATE_BINs of a select list against the GROUP BY bucket (group_interval, in nanoseconds): each must be that bucket, or the double refuses the query by name.

group_columns(sql)

@spec group_columns(binary()) :: [binary()] | nil

The bare-column GROUP BY items of a statement (a quoted name as the name it holds), or nil when there are none.

interval(sql)

@spec interval(binary()) :: {:ok, non_neg_integer() | nil} | {:error, term()}

The GROUP BY DATE_BIN bucket of a statement in nanoseconds, or nil. The DATE_BIN is optional: without it the executor groups by columns or produces a single scalar row; a malformed interval still surfaces.

order_by(rest)

@spec order_by(binary()) :: order_by()

The ORDER BY a [ASC|DESC][, b [ASC|DESC] ...] terms of the text after the table. A target may be a column, time, an output alias (the DATE_BIN alias, say) or an expression (CAST(level AS INTEGER) DESC); a target the expression parser cannot read is {:expr, {:unreadable, text}}, which unreadable_order/1 refuses by name. The direction defaults to ascending, as in SQL.

order_position(term, count)

@spec order_position(binary(), non_neg_integer()) ::
  {:ok, pos_integer()}
  | :not_positional
  | {:error, InfluxElixir.Client.Local.SQLError.t()}

How an ORDER BY term reads as a position among count select items (verified against InfluxDB 3 Core): a whole number from 1 to count is that position; 0, a position past count and one past UInt64 are the engine's planning errors, and so is a number with a fraction or an exponent. Anything else is not a position.

resolve_references(columns, rest, namer)

@spec resolve_references(binary(), binary(), (binary() -> binary() | nil)) ::
  {:ok, binary()} | {:error, InfluxElixir.Client.Local.SQLError.t()}

Rewrites the positions and select aliases of the clauses in rest, the text after the table, to the items they name. columns is the select list; namer gives the output name of an item without an alias, or nil when the double cannot write it (the item then stands for itself).

unreadable_order(order_by)

@spec unreadable_order(order_by()) ::
  :ok | {:error, InfluxElixir.Client.Local.SQLError.t()}

The refusal of an ORDER BY term the double cannot read (a function it does not have, a type it does not model: CAST(x AS FLOAT)), or :ok. The engine answers it with rows or an error of its own; naming it a column, as a schema error would, answers neither.