# mutare_ecto v0.3.0 - Table of Contents

> Mutare mutators for Ecto

## Pages

- [mutare_ecto](readme.md)
- [Changelog](changelog.md)
- [LICENSE](license.md)

## Modules

- [Mutare.Ecto.Dynamic](Mutare.Ecto.Dynamic.md): In-fragment SQL mutations for a **free-standing** `dynamic/1,2` call — the condition a user
builds ahead of time and splices later

- Mutator front
  - [Mutare.Ecto](Mutare.Ecto.md): A mutation-testing plugin for Ecto — a `Mutare.Mutator` that mutates the Ecto
surface (Repo calls, changeset pipelines, and the query DSL) while respecting
SQL semantics.

- Repo &amp; changeset mutators
  - [Mutare.Ecto.Changeset](Mutare.Ecto.Changeset.md): Drop a transparent step from a changeset pipeline — the changeset equivalent of removing a
guard. `cs |> validate_required([:name])` → `cs`. A surviving mutant means **no test
exercises** the behaviour that step contributes. Matched by resolving the call to
`Ecto.Changeset` (direct, aliased, or the common `import Ecto.Changeset`), so the form the
call uses doesn't matter.
  - [Mutare.Ecto.Changeset.Routing](Mutare.Ecto.Changeset.Routing.md): The per-argument routing classifier for the `Ecto.Changeset` pipeline stages the plugin mutates
(`Mutare.Ecto.Changeset.stages/0` — every validator, constraint, and Repo-time hook it can
drop) — the changeset counterpart of the query classifier `Mutare.Ecto.Host.Routing`. Nothing
here is hosted; the classifier only holds back from core's families the positions where a
core swap would be a **crash, not a mutant**, so a run that lists the plugin next to `:all`
reports no crasher in a changeset stage. The test of each pin is Ecto's own handling of the
swapped value
  - [Mutare.Ecto.QueryTerminal](Mutare.Ecto.QueryTerminal.md): Swap `Ecto.Query.first/1,2` ↔ `Ecto.Query.last/1,2` — the query "terminals" that restrict a
query to a single edge of its ordering. `first` keeps the first row by the order (primary key
ascending when none is given); `last` reverses it. Swapping them is a clean, same-arity rename
(so it always compiles), behaviour-changing whenever the query can return more than one row — a
survivor means no test pins *which* end the query is taking.
  - [Mutare.Ecto.RepoAggregate](Mutare.Ecto.RepoAggregate.md): Swap the aggregate of a `Repo.aggregate/3` call along an SQL-meaningful ladder —
`:sum`↔`:avg`, `:min`↔`:max`. A surviving mutant means no test distinguishes, say, the
sum of a column from its average: the aggregate is computed but its *kind* is unchecked.
  - [Mutare.Ecto.RepoWrite](Mutare.Ecto.RepoWrite.md): Mutations on the **persisting Repo writes** — `insert`/`update`/`delete`/`insert_or_update`
and their `!` variants. Two families, both matched by resolving the call's module to one of the
configured `repo:` modules (so direct, aliased, and `use Ecto.Repo`-defined forms all match)
  - [Mutare.Ecto.ValidationBoundary](Mutare.Ecto.ValidationBoundary.md): Swap a `validate_number/3` bound between its strict and non-strict form — the changeset
counterpart of the in-query `:comparison` swap. `validate_number(:age, greater_than: 0)` →
`validate_number(:age, greater_than_or_equal_to: 0)`. "Is the bound *itself* tested?" — the two
validations accept the same values except one exactly on the bound, so the mutant survives
unless a test builds a changeset whose value equals it and asserts the validation result. Family
`:validation_boundary`; equivalence-sensitive (`Mutare.Ecto.Equivalence`), because a kill needs
exactly that fixture.

- Query-DSL mutators
  - [Mutare.Ecto.BindingReorder](Mutare.Ecto.BindingReorder.md): Positional **binding-reorder** mutants for every standalone/pipe query macro that takes a binding
pattern list — the `where`/`having` condition macros, `select`, `select_merge`, `order_by`,
`group_by`, `distinct`, `join`, `preload`, `windows`, …, and the free-standing `dynamic/2`
(the condition/clause/join/dynamic descriptors in `Mutare.Ecto.Surface`).
  - [Mutare.Ecto.Clause](Mutare.Ecto.Clause.md): Standalone/pipe clause-macro mutations — the composable counterparts 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
  - [Mutare.Ecto.ClauseDrop](Mutare.Ecto.ClauseDrop.md): Drop a standalone/pipe **query clause** — the composable counterpart of `Mutare.Ecto.Query`'s
whole-`from` clause drops, analogous to `Mutare.Ecto.Changeset`'s validator drop.
Where `Query` removes a `where:`/`limit:`/`group_by:` clause from a `from(…)` keyword list, this
removes the same kinds of clause written as a standalone call or pipe stage
  - [Mutare.Ecto.Query](Mutare.Ecto.Query.md): 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.

- Hosted in-fragment mutations
  - [Mutare.Ecto.Fragment](Mutare.Ecto.Fragment.md): The plugin's **own** SQL-semantics mutation catalog for a query fragment — the boolean
condition of a `where`/`having` clause or of a free-standing `dynamic/1,2`. Given a condition's
AST, `mutants/1` returns every *single-point* variant: the same condition with **exactly one**
operator/predicate swapped, one variant per mutatable position. Each variant is a full,
compile-safe alternative the SQL engine will actually run; the host (`Mutare.Ecto.Host`) weaves
them behind a `^`/`dynamic` selector so one of them bakes into the query per run, while
`Mutare.Ecto.Dynamic` rebuilds a free-standing `dynamic` call whole (an ordinary expression
position, needing no weave).
  - [Mutare.Ecto.Host](Mutare.Ecto.Host.md): Builds selector-host targets for localized Ecto query conditions.
  - [Mutare.Ecto.Host.Routing](Mutare.Ecto.Host.Routing.md): 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.
  - [Mutare.Ecto.StaticCondition](Mutare.Ecto.StaticCondition.md): The condition the host cannot weave, and its whole-call delivery.

