# `Selecto.Tenant`

Multi-tenant helpers for Selecto query state.

This module provides a lightweight tenant context contract for read-path
queries. Tenant scope is enforced by appending tenant constraints to the
query's required filter bucket (`set.required_filters`).

# `tenant_context`

```elixir
@type tenant_context() :: %{
  optional(:tenant_id) =&gt; term(),
  optional(:tenant_mode) =&gt; atom() | String.t(),
  optional(:tenant_field) =&gt; atom() | String.t(),
  optional(:prefix) =&gt; String.t(),
  optional(:namespace) =&gt; String.t(),
  optional(:required) =&gt; boolean(),
  optional(:required_filters) =&gt; [Selecto.Types.filter()]
}
```

# `apply_tenant_scope`

```elixir
@spec apply_tenant_scope(
  Selecto.Types.t(),
  keyword()
) :: Selecto.Types.t()
```

Apply tenant scope to a query's required filter bucket.

Options:

- `:tenant` - explicit tenant context override
- `:tenant_id` - explicit tenant id override
- `:tenant_field` - explicit tenant field override
- `:required_filters` - additional required filters

# `ensure_scope!`

```elixir
@spec ensure_scope!(
  Selecto.Types.t(),
  keyword()
) :: :ok
```

Raise when tenant scope is required and missing.

# `merge_execution_opts`

```elixir
@spec merge_execution_opts(
  Selecto.Types.t(),
  keyword()
) :: keyword()
```

Merge execution options with tenant-derived defaults.

If no `:prefix` option is provided explicitly and tenant context includes a
`:prefix`, the prefix is injected into execution opts.

# `normalize_context`

```elixir
@spec normalize_context(tenant_context() | keyword() | String.t() | atom() | nil) ::
  tenant_context() | nil
```

Normalize tenant context input into a map with atom keys.

# `require_tenant_filter`

```elixir
@spec require_tenant_filter(Selecto.Types.t(), Selecto.Types.filter()) ::
  Selecto.Types.t()
```

Append a required filter to the query set.

# `require_tenant_filter`

```elixir
@spec require_tenant_filter(Selecto.Types.t(), atom() | String.t(), term()) ::
  Selecto.Types.t()
```

Append a required tenant filter from field + value.

# `tenant`

```elixir
@spec tenant(Selecto.Types.t()) :: tenant_context() | nil
```

Read the tenant context from a Selecto query.

# `tenant_required?`

```elixir
@spec tenant_required?(
  Selecto.Types.t(),
  keyword()
) :: boolean()
```

Return whether tenant scope is required for this query.

Precedence:

1. `opts[:require_tenant]`
2. tenant context `:required` / `:require_tenant`
3. domain `:tenant_required` / `:require_tenant`
4. inferred true for `tenant_mode` in shared-column/shared-rls/schema modes

# `validate_scope`

```elixir
@spec validate_scope(
  Selecto.Types.t(),
  keyword()
) :: :ok | {:error, Selecto.Error.t()}
```

Validate tenant scope requirements for read and derivation paths.

Returns `:ok` when tenant scope is optional or present. Returns structured
validation error when tenant scope is required but missing.

# `with_tenant`

```elixir
@spec with_tenant(
  Selecto.Types.t(),
  tenant_context() | keyword() | String.t() | atom() | nil
) ::
  Selecto.Types.t()
```

Attach tenant context to a Selecto query.

---

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