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

Validates that a query has a root `where` predicate referencing configured keys.

This is useful for tenant boundaries where every query should include a
predicate for fields such as `:organization_id` or `:user_id`.

## Examples

Bad:

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

Why this is bad:

If `:organization_id` is configured as mandatory, this query has no visible
tenant boundary in the root `where` clause. It can read rows across
organizations.

Better:

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

Why this is better:

The configured key appears in a supported root predicate, so the query is
explicitly scoped to one organization.

## Notes

This check accepts supported direct root `==` and `in` predicates. It does not
prove tenant safety when keys are hidden inside fragments or field-to-field
comparisons.

The check is static. It accepts configured root fields directly in `==` and `in`
predicates inside `where` expressions, but it cannot prove fields hidden
inside raw SQL fragments. Combination queries such as `union`, `union_all`,
`except`, and `intersect` validate the parent query and every combination
branch independently.

When the root query uses an Ecto schema, the configured keys are first narrowed
to fields that exist on that schema. If none of the configured keys exist, the
check is not applicable and returns `:ok`. Schema-less sources are still
validated because there is no schema reflection signal.

## Options

  * `:validate` - explicit `false` disables the check. Defaults to `true`.
  * `:keys` - required non-empty list of field names when the check runs.
  * `:match` - `:any` or `:all`. Defaults to `:any`.

Example check spec:

    {Bylaw.Ecto.Query.Checks.MandatoryWhereKeys,
     keys: [:organization_id],
     match: :all}

## 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.

# `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*
