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

In-fragment SQL mutations for a **free-standing** `dynamic/1,2` call — the expression a user
builds ahead of time and splices later:

    d = dynamic([p], p.views > 100)
    Repo.all(where(query, ^d))

The body is a general SQL expression, including lists, maps, aliases, and windows.
It shares SQL value semantics with a hosted `where`/`having`, so the same catalog
walks it (`Mutare.Ecto.Fragment`, scalar and aggregate swaps folded in — `sum`↔`avg` for a
dynamic used in a `having`). At the `where(q, ^d)` splice site, a top-level `^d` is hosted
like any other condition, but the catalog stops at the pin. Its interior contains only a bare
variable, which core does not mutate (`Mutare.Ecto.Island`). The splice therefore produces no
mutations; this module mutates the `dynamic` *where it is built*.

**Delivery** differs from the hosted path. `dynamic` is registered `:raw`
(`Mutare.Ecto.Surface.macro_registrations/0`), so core never descends into its DSL arguments —
but core still offers the *whole call* to `mutate/2` (which is why it is `:raw`, not the
call-level `:skip`: a skipped call is never passed to a mutator), and a free-standing `dynamic`
sits in an ordinary expression position (its value is a runtime `%Ecto.Query.DynamicExpr{}`, not a spliced
query clause). So each mutant is the whole call rebuilt with exactly one point of the condition
swapped, delivered by Mutare's ordinary in-place selector `case` — the same Bucket-1 delivery as
the whole-`from` rewrites in `Mutare.Ecto.Query`. No host / `^`-weaving is needed, each selector
branch invokes the `dynamic` macro independently, and exactly one `DynamicExpr` builds per run.
Each mutant is still **reported at the mutated expression** — the walk anchors it
(`Mutare.Ecto.Walk`) — so a line-scoped `# mutare:ignore` reaches one comparison of a
multi-line `dynamic`.

The written binding list is preserved (`Mutare.Ecto.BindingReorder` handles reordering).
`Mutare.Ecto.Island` supplies pin-interior mutants, delivered here as whole-call rewrites.

# `mutations`

```elixir
@spec mutations(Mutare.Ecto.AST.QueryCall.t(), Mutare.Ecto.Context.t()) :: [
  Mutare.Ecto.SubMutator.tagged() | Mutare.Mutator.Mutation.t()
]
```

Every single-point in-fragment mutant of a free-standing `dynamic/1,2` call, each the **whole
call** rebuilt with one condition position swapped — the plugin's own catalog mutants as
`Mutare.Ecto.Tag`s, the island mutants returned by core as producer-attributed
`Mutare.Mutator.Mutation`s — or `[]` when there is nothing to mutate. The last argument is a general SQL expression, including a list or map;
it is not classified as a filter. Its declaration is never read: the whole-call rebuild re-emits the written list as it stands, so
even one the plugin cannot interpret (which a woven `dynamic/2` could not re-declare) is
mutated here.

---

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