Selecto.Tenant (Selecto v0.3.14)

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

Link to this section Summary

Functions

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

Raise when tenant scope is required and missing.

Merge execution options with tenant-derived defaults.

Normalize tenant context input into a map with atom keys.

Append a required filter to the query set.

Append a required tenant filter from field + value.

Read the tenant context from a Selecto query.

Return whether tenant scope is required for this query.

Validate tenant scope requirements for read and derivation paths.

Attach tenant context to a Selecto query.

Link to this section Types

Link to this type

tenant_context()

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

Link to this section Functions

Link to this function

apply_tenant_scope(selecto, opts \\ [])

@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
Link to this function

ensure_scope!(selecto, opts \\ [])

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

Raise when tenant scope is required and missing.

Link to this function

merge_execution_opts(selecto, opts \\ [])

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

Link to this function

normalize_context(tenant_id)

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

Normalize tenant context input into a map with atom keys.

Link to this function

require_tenant_filter(selecto, filter)

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

Append a required filter to the query set.

Link to this function

require_tenant_filter(selecto, tenant_field, tenant_id)

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

Append a required tenant filter from field + value.

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

Read the tenant context from a Selecto query.

Link to this function

tenant_required?(selecto, opts \\ [])

@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
Link to this function

validate_scope(selecto, opts \\ [])

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

Link to this function

with_tenant(selecto, tenant_context)

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

Attach tenant context to a Selecto query.