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

Whole-`from` query mutations — the ones expressible **without** Mutare's foreign-semantics
DSL host. Each returns a whole mutated `from(...)` node, which
Mutare's ordinary in-place selector wraps; the localized in-fragment mutations (operator
swaps inside a `where`, via `^`/`dynamic`) arrive with the host extensions.

  * **Filter drop** — remove one `where`/`having`/`or_where`/`or_having` clause from the
    query. "Is this filter tested?" Reuses the surviving clauses, so it always compiles, and
    works for both the binding form (`from p in Post, where: p.active`) and the bindingless
    form (`from Post, where: [active: true]`) since it operates on the clause list, not the
    clause value.
  * **Clause drop** — remove one `group_by`/`distinct`/`preload`/`lock`/`select_merge`/
    `with_ties` clause, or one set operation (`union:`, `except:`, …): the `from`-keyword
    twin of `Mutare.Ecto.ClauseDrop`'s stage drop, under the same family. "Is what this
    clause contributes tested?" A `from` expands as a whole when the metamutant compiles, so
    a key drops here only if the rest of the list cannot need it — it binds no variable,
    nothing names it, and no plan requires it. That holds the pipeline's other drops back:
    a **join** binds a variable the other clauses read, so its drop would fail the single
    build unless the binding were first proved unreferenced; a **`select:`** is required by
    a schemaless source, an **`update:`** by `update_all`, and a **`windows:`** is named by
    `over/2`. What remains can still depend on a dropped clause at the *engine* — a
    `select` that mixes an aggregate with a plain column needs its `group_by` on Postgres —
    which raises under that one mutant only (`Mutare.Ecto.ClauseDrop`, "A drop weakens the
    query, or breaks it").
  * **Order flip** — flip an `order_by` direction (`:asc`↔`:desc`, and the `*_nulls_*`
    variants). "Does any test pin the sort direction?"
  * **Bound (drop)** — drop a `limit`/`offset` clause. "Is the window tested at all?" The
    family's other half, the `±1` bump of a literal bound, is hosted pin-only instead
    (`Mutare.Ecto.Bound`). Of a repeated bound (`limit: 5, limit: 10`) only the last — the one
    Ecto keeps — drops, uncovering the previous; the overridden one never reaches the query,
    so its drop would be equivalent (`Mutare.Ecto.AST.FromCall.effective_clause?/2`).
  * **JoinType** — narrow a join's kind by rewriting its clause *key*: `left_join`→`inner_join`,
    and `full_join`→`left_join`/`right_join` (plus `left_join`↔`right_join` sideways). "Does any
    test exercise the orphan row this join kind keeps that a narrower kind would drop?" An outer
    join is written *because* unmatched rows must survive, so seed data built for that reason is
    likely to already include an orphan for which the narrower kind returns different rows —
    a killable mutation. The reverse (`inner_join`/`join`→`left_join`, `*`→`full_join`) is deliberately not
    offered: it widens a join the author picked precisely to *exclude* unmatched rows, and
    absent a reason to test for an orphan that shouldn't matter, the widened query usually
    returns identical rows — an equivalent mutant more often than a killable one. The
    `left_join`↔`right_join` swap and `full_join`→`left_join` are portable (every adapter
    supports `INNER`/`LEFT`); `full_join`→`right_join` and the `RIGHT` leg of `left_join`↔
    `right_join` are **dialect-gated** (`:postgres`/`:mysql` — SQLite lacks `RIGHT JOIN`).
    The flips are the shared `Mutare.Ecto.JoinType` catalog's, keyed by join qualifier, which
    `Mutare.Ecto.Clause` applies to a standalone `join(q, :left, …)` under this same policy.
  * **Combination** — swap a set-operation clause's *key*: `intersect:`↔`except:` and
    `intersect_all:`↔`except_all:`. "Does any test pin which rows the combination keeps?" The
    shared `Mutare.Ecto.Combination` catalog defines the pairing, its portability, and the
    `union` exclusion.
  * **Aggregate (in `select`/`order_by`)** — swap an aggregate inside a `select`/`select_merge`
    or `order_by` clause value (`sum`↔`avg`, `min`↔`max`), via the shared `Mutare.Ecto.Aggregate`
    walker. "Does any test pin which aggregate the column is reduced/sorted by?" (An aggregate
    inside a `having` is delivered through the host instead — see `Mutare.Ecto.Host`.)
  * **Scalar (in `select`/`order_by`)** — mutate a value-computing form inside a
    `select`/`select_merge` or `order_by` clause value, via the shared `Mutare.Ecto.Scalar`
    catalog: the arithmetic swaps (`+`↔`-`, `*`↔`/`; "does any test pin the computed value?")
    and the coalesce fallback drop (`coalesce(x, d)` → `x`; "does any test exercise the NULL
    row the default is for?"). (The same forms inside a `where`/`having` condition are hosted
    instead, alongside the operator swaps.)
  * **Binding reorder (source list)** — when the source declares a positional binding list
    (`from [a, b] in q, …`), transpose each pair of those bindings (`[a, b]` → `[b, a]`). "Did
    the author bind the sources in the right order?" The list was written at the whole-`from`
    level, so its reorder is delivered here — see `Mutare.Ecto.BindingReorder` for the rule
    and its policy.

Each mutation is returned as a `Mutare.Ecto.Tag`: its label is the finer operator/kind a swap
family names (order/join/aggregate — `nil` for a structural drop), and its attribution
(`Mutare.Mutator.Mutation.at/2`/`at_drop/1`) names the **inner clause** the rewrite changed,
so the site is reported there rather than at the whole `from` (see `Mutare.Ecto.Walk` on
attribution). `config` carries `dialects:` for the join gate. The `from` is read apart and
rebuilt through `Mutare.Ecto.AST.FromCall`, which preserves the written form and handles
emptied clause lists. A scalar `from/1` (`from(Post)`, no clauses) yields nothing, while
a source binding list (`from([a, b] in query)`) can still reorder.

# `producer`

```elixir
@type producer() ::
  :filter_drop
  | :bound
  | :clause_drop
  | :ordering
  | :join_type
  | :combination
  | :aggregate
  | :scalar
  | :binding_reorder
```

One whole-`from` producer, named in `Mutare.Ecto.Surface`'s vocabulary: a `from_drop` family
walked over the clause list (`:filter_drop`, `:bound`, `:clause_drop`), a `from` capability walked over the
clauses carrying it (the `:ordering`/`:aggregate`/`:scalar` value swaps, the
`:join_type`/`:combination` key swaps), or the source-level `:binding_reorder`.

# `mutations`

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

Whole-`from` mutations for a `from(...)` node as self-tagging `Mutare.Ecto.Tag`s (the label the
finer operator/kind for a swap family, `nil` for a structural drop; the attribution the inner
clause the site is reported at), or `[]`.

# `mutations_for`

```elixir
@spec mutations_for(
  Mutare.Ecto.AST.FromCall.t(),
  Mutare.Ecto.Config.t(),
  [producer()],
  (atom() -&gt;
     boolean())
) ::
  [Mutare.Ecto.SubMutator.tagged()]
```

The whole-`from` mutations for `from` under an already-resolved `%Config{}` — the body
`mutations/2` delegates to — restricted to `producers` (default: every producer, in
`mutations/2`'s order) over the clauses whose key satisfies `clause?` (default: every clause;
`:binding_reorder` rewrites the source, not a clause, so the predicate never reaches it).

Exposed so `Mutare.Ecto.Subquery` can mutate an inner `from` using just the producers whose
mutations can affect the wrapper's result (with the parsed `FromCall` and config, not a full
callback context): the row-set producers under every wrapper, and the `select` projection's
`:aggregate`/`:scalar` swaps under a value-wrapper only — rather than running all eight and
filtering out inapplicable mutations. An unknown producer is a programming error and raises.

---

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