# `Mutare.Ecto.Host.Routing`
[🔗](https://github.com/foxbenjaminfox/mutare_ecto/blob/v0.4.2/lib/mutare/ecto/host/routing.ex#L1)

Classifies arguments of registered query macros for `c: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 normalized call's first argument (`Mutare.Ecto.AST.QueryCall`). Its
shape determines its treatment, for both `from` and 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`.

# `resolver`

```elixir
@type resolver() :: (Macro.t() -&gt; {:ok, module()} | :error)
```

Reads a module name through the call site's aliases and enclosing module.

# `route_arguments`

```elixir
@spec route_arguments(Mutare.CallRouting.Call.t()) ::
  Mutare.CallRouting.ArgumentRoutes.t()
```

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

# `treatments`

```elixir
@spec treatments(atom(), [Macro.t()], resolver()) :: [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.

`resolve` reads a module name in the arguments through the call site's aliases and the module
`__MODULE__` names there (`Mutare.CallRouting.Call.resolved_module/2`); the default knows none.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
