Changelog

View Source

Unreleased

0.22.0 — 2026-05-15

Added

Statement-level features

  • q:having/1,2 — SQL HAVING clause; composes with andalso like where.
  • q:lateral_join/2,3,4LATERAL join; subquery closure receives outer data, supports custom ON condition.
  • q:order_by/2NULLS FIRST / NULLS LAST via 3-element tuple {Field, asc|desc, nulls_first|nulls_last}.
  • q:first/2,3 — emits FETCH FIRST n ROWS [ONLY|WITH TIES]; takes mode no_ties | with_ties. Shares the storage slot with q:limit/1,2, so whichever is set last wins; first(N, no_ties) is equivalent to limit(N).

  • Schema-qualified table names via optional schema => binary() field in schema map → emits "schema"."table".

Expression-level operators and predicates

Numeric functions

String functions

Date/time functions

Aggregates

Arrays

JSON / JSONB

Changed

  • Atom → binary conversions now use UTF-8 instead of latin1 in equery_utils:to_binary/1 and pg_sql type-name rendering. Atoms with non-ASCII characters no longer lose data.
  • pg_sql:value() type renamed to pg_sql:expr() to disambiguate from qast:value() (the AST node).
  • equery_utils:order_item_exp/1 — shared helper used by both top-level ORDER BY and aggregate-internal ordering.

Fixed

  • real_table() type updated from {real, iolist(), reference()} to {real, binary() | {binary(), binary()}, reference()} to match actual usage (schema-qualified names broke the old type).

  • Type literals in pg_sql:array_length/1 and qjson:jsonb_set/4/jsonb_insert/4 wrapped with qast:value/2 to satisfy success typing.