Runtime resolution for the AshReplicant sink — the tenant/classification layer
that keeps replicant tenant-blind. Pure functions over compiled resource
metadata (no DB access):
build_index/1— reflect the configured domains into a{source_schema, source_table} => resourceindex, failing closed on a duplicate source key (ambiguous route).resolve_tenant/2— per-row tenant fromtenant_attribute/tenant_mfa, failing closed with:tenant_requiredon a nil/blank tenant.writable_target/2/attrs_for_upsert/2— map source string columns to their real writable targets, routing AshCloak-sensitive columns through the cloak argument while namingencrypted_<col>inupsert_fields. The bulk snapshot path computesupsert_reflection/1once and maps each row viaupsert_input/2(the batch-invariant hoist).primary_key/1/pk_values/2/upsert_identity/1/upsert_action/1/destroy_action/1.
Summary
Types
The batch-invariant upsert reflection: {skip, cloak_attrs, attribute_names}.
Functions
The primary destroy action name (mirrors upsert_action/1 for :create).
Look up the mirror resource for a source {schema, table} in an index built by
build_index/1, applying the SAME nil-schema → "public" default the index
keys use (so the convention lives in one place next to the builder). Returns the
resource, or nil for an unmapped table.
The upsert-capable create action name (the resource's primary create action).
The upsert identity name from the DSL (nil → primary-key upsert).
Map one source record to {inputs, upsert_fields} under a precomputed
upsert_reflection/1. AshCloak-sensitive columns pass plaintext under the cloak
argument while upsert_fields names encrypted_<col>.
Compute the batch-invariant upsert reflection for a resource ONCE — the skip
list, the AshCloak cloak attributes, and the attribute-name set. Thread it into
upsert_input/2 per row of a column-homogeneous batch (the snapshot bulk path)
to avoid re-deriving these for every row. Single-record callers use
attrs_for_upsert/2, which computes the reflection inline.
Types
Functions
@spec build_index([module()]) :: {:ok, %{required(source_key()) => module()}} | {:error, {:duplicate_source, source_key()}} | {:error, {:missing_source_table, module()}}
The primary destroy action name (mirrors upsert_action/1 for :create).
@spec lookup(%{required(source_key()) => module()}, String.t() | nil, String.t()) :: module() | nil
Look up the mirror resource for a source {schema, table} in an index built by
build_index/1, applying the SAME nil-schema → "public" default the index
keys use (so the convention lives in one place next to the builder). Returns the
resource, or nil for an unmapped table.
The upsert-capable create action name (the resource's primary create action).
The upsert identity name from the DSL (nil → primary-key upsert).
@spec upsert_input(upsert_reflection(), map()) :: {map(), [atom()]}
Map one source record to {inputs, upsert_fields} under a precomputed
upsert_reflection/1. AshCloak-sensitive columns pass plaintext under the cloak
argument while upsert_fields names encrypted_<col>.
@spec upsert_reflection(module()) :: upsert_reflection()
Compute the batch-invariant upsert reflection for a resource ONCE — the skip
list, the AshCloak cloak attributes, and the attribute-name set. Thread it into
upsert_input/2 per row of a column-homogeneous batch (the snapshot bulk path)
to avoid re-deriving these for every row. Single-record callers use
attrs_for_upsert/2, which computes the reflection inline.