Standalone/pipe clause-macro mutations — the composable cousins of the whole-from family
in Mutare.Ecto.Query. Where Query mutates from's keyword clauses, this mutates the
same kinds of thing written as standalone calls or pipe stages:
- Ordering —
order_by(q, [u], asc: u.name)/q |> order_by(asc: u.name): flip a sort direction (:asc↔:desc, nulls-placement variants), via the sharedMutare.Ecto.Orderingcatalog. - Aggregate —
select(q, [u], sum(u.amount))/q |> select_merge(%{n: max(u.x)}), and an aggregate written into anorder_by(q |> order_by([u], desc: sum(u.amount))): swap the aggregate (sum↔avg,min↔max), via the sharedMutare.Ecto.Aggregatewalker. (Ahavingaggregate is hosted instead —Mutare.Ecto.Host.) - Scalar —
select(q, [u], u.price * u.qty)/q |> order_by([u], desc: u.a + u.b)/q |> select([u], coalesce(u.score, 0)): mutate a value-computing form via the sharedMutare.Ecto.Scalarcatalog — the arithmetic swaps (+↔-,*↔/) and the coalesce fallback drop. (The same forms in awhere/havingcondition are hosted instead.) - Combination —
q |> intersect(^other)/except_all(q, ^other): swap the set operation by renaming the macro itself (intersect↔except,intersect_all↔except_all), via the sharedMutare.Ecto.Combinationcatalog. Unlike the others this mutates the call's name, not its last argument — the operand queries are untouched.
These macros route through the :routing classifier (Mutare.Ecto.Host.Routing), which keeps
their data positions raw while the routed node is still offered whole to mutate/2; the
mutation rides Mutare's ordinary in-place selector, since the macro call is itself an
expression. The orthogonal stage removal (q |> order_by(…) → q) lives in
Mutare.Ecto.ClauseDrop, and the :bound ±1 bump of a literal limit/offset is hosted
pin-only (Mutare.Ecto.Bound; NOTES "Bound bump: from whole-call rewrite to pin-only
hosting").
The mutated position is always the last argument (the ordering / the selector), which
is true for both the direct form (order_by(q, binds, ordering)) and the pipe form
(q |> order_by(binds, ordering), where q is the piped left side, not in args) — so no
pipe-mode bookkeeping is required.
Summary
Functions
Standalone/pipe clause-macro mutations for node as self-tagging Mutare.Ecto.Tags
(a swap family — order/aggregate — carries the finer operator/kind label), or [].