Mutare.Ecto.Host.Routing (mutare_ecto v0.3.0)

Copy Markdown View Source

Classifies arguments of registered query macros for Mutare.CallRouting.route_arguments/1. Core follows these routes; Mutare.Ecto.Host supplies the targets at :hosted positions.

Query sources

A query source is the call's first argument, whichever way the call was written: core hands a pipe stage over as the direct call it is sugar for, so Post |> where(…) is classified as where(Post, …). The source's shape then determines its treatment, identically for from and the composable where/join/limit stages:

  • A schema alias, table-name string (including interpolation), or {"table", Schema} pair stays :raw. Replacing a table/schema name makes a broken query.
  • An in binding declaration stays :raw. It is syntax the macro consumes, not an Elixir expression. This also withholds mutations inside its queryable (p in build(n + 1)); the host separately reads the declaration through Mutare.Ecto.Host.Bindings.
  • A fragment(...) source stays :raw: its template and arguments are SQL syntax.
  • A values(rows, types) source stays :raw: its row keys and declared SQL types describe the source's structure and must agree.
  • Every other source routes :expression: a variable, function call, nested from, or upstream pipeline. Core keeps its mutations reachable through the enclosing query stage.

No shape guess locates the source: at classification the arguments are the written syntax, before core resolves the calls inside them, so a source is read by its shape alone.

Query data

  • from routes its clause list per pair. Expression conditions (where/having/on) route :hosted; keyword-shorthand conditions route their scalar values :interpolated. Literal limit:/offset: values route :hosted for the pin-only bound bumps. Other clause values stay raw for the whole-from producers. Mutare.Ecto.AST.FromCall places the clauses and reads the source. A binding declaration routed :raw reaches the macro as the syntax it is in each whole-call mutant branch, piped or not.
  • Composable conditions locate their condition through Mutare.Ecto.Host.Condition. A predicate routes :hosted; a keyword shorthand routes per pair, exactly as in from. Written binding lists stay raw.
  • Plain clauses (select/order_by/…) keep their data raw. A literal-integer bound (limit/offset) instead routes :hosted, using Mutare.Ecto.Bound's literal-only guard.
  • join routes its trailing options per pair: on: uses the condition classification, while as:/prefix:/hints: stay raw.

A shorthand routes scalar values through ^ interpolation because Ecto rejects a bare selector case there. Keys, nil values (IS NULL, never = nil), existing pins and compound values stay raw. Those scalar mutants belong to core's producing family, not :ecto. Mutare.Ecto.Host.Condition decides whether a value is a predicate or shorthand once, so the host and classifier agree even when a sibling position causes the whole call to be hosted.

:hosted permits the host to consider a position; it does not promise the host will weave it. Declaration and receiving-clause constraints remain Mutare.Ecto.StaticCondition's. Whole nodes are still offered to the plugin's mutators regardless of their argument routes.

dynamic and is_named_binding register :raw instead of using this classifier (Mutare.Ecto.Surface.macro_registrations/0): neither threads a query. A free-standing dynamic is still offered whole to Mutare.Ecto.Dynamic.

Summary

Functions

Route the call's arguments — the source, wherever the call was written, is argument 0.

Per-argument treatments for a registered query macro, over the call's complete argument list (a piped source included, at position 0). Returns [] for a name the plugin doesn't route.

Functions

route_arguments(call)

Route the call's arguments — the source, wherever the call was written, is argument 0.

treatments(macro, args)

@spec treatments(atom(), [Macro.t()]) :: [Mutare.CallRouting.treatment()]

Per-argument treatments for a registered query macro, over the call's complete argument list (a piped source included, at position 0). Returns [] for a name the plugin doesn't route.