# `Bylaw.Ecto.Query.Checks.HardDeleteOnSoftDeleteSchema`
[🔗](https://github.com/ryanzidago/bylaw/blob/v0.1.0-alpha.1/lib/bylaw/ecto/query/checks/hard_delete_on_soft_delete_schema.ex#L1)

Validates that soft-delete schemas are not hard-deleted with `delete_all`.

Schemas that declare a persisted `:deleted_at` or `:archived_at` field usually
expect lifecycle removal to be represented as an update. A bulk hard delete on
that schema is therefore suspicious even when the query is otherwise bounded.

## Examples

Bad:

    query =
      from(Post, as: :post)
      |> where([post: p], p.status == ^:archived)

    Repo.delete_all(query)

Why this is bad:

If `Post` has a persisted `:deleted_at` or `:archived_at` field, hard-deleting
rows bypasses the lifecycle model and permanently removes records the schema
normally treats as soft-deletable.

Better:

Prefer `Repo.update_all/3` setting `:deleted_at` or `:archived_at` instead of
`Repo.delete_all/2` when this check reports an issue.

    query =
      from(Post, as: :post)
      |> where([post: p], p.status == ^:archived)

    Repo.update_all(query, set: [deleted_at: DateTime.utc_now()])

Why this is better:

Removal is represented in the soft-delete field, preserving the schema's
lifecycle convention.

## Notes

This check uses persisted root schema fields as the signal. It ignores
schema-less queries, virtual fields, source subqueries, and soft-delete fields
on joined schemas.

The check is zero-config. Field presence in `__schema__(:fields)` is the
signal.

## Options

  * `:validate` - explicit `false` disables the check. Defaults to `true`.

## Usage

Add this module to the explicit check list passed through `Bylaw.Ecto.Query`.
See `Bylaw.Ecto.Query` for the full `c:Ecto.Repo.prepare_query/3` setup.

The root query and every combination branch are inspected independently. The
check ignores schema-less queries, non-query values, virtual fields, source
subqueries, and soft-delete fields that appear only on joined schemas.

# `validate`

```elixir
@spec validate(
  Bylaw.Ecto.Query.Check.operation(),
  Bylaw.Ecto.Query.Check.query(),
  opts()
) ::
  Bylaw.Ecto.Query.Check.result()
```

Implements the `Bylaw.Ecto.Query.Check` validation callback.

---

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