# mutare_ecto v0.4.2 - 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 expression 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 & 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.