AshReplicant.Resolver (AshReplicant v0.2.0)

Copy Markdown View Source

Runtime resolution for the AshReplicant sink — the tenant/classification layer that keeps replicant tenant-blind. Pure functions over compiled resource metadata (no DB access):

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

source_key()

@type source_key() :: {schema :: String.t(), table :: String.t()}

upsert_reflection()

@type upsert_reflection() :: {[atom()], [atom()], MapSet.t(atom())}

The batch-invariant upsert reflection: {skip, cloak_attrs, attribute_names}.

Functions

attrs_for_upsert(resource, record)

@spec attrs_for_upsert(module(), map()) :: {map(), [atom()]}

build_index(domains)

@spec build_index([module()]) ::
  {:ok, %{required(source_key()) => module()}}
  | {:error, {:duplicate_source, source_key()}}
  | {:error, {:missing_source_table, module()}}

destroy_action(resource)

@spec destroy_action(module()) :: atom()

The primary destroy action name (mirrors upsert_action/1 for :create).

lookup(index, schema, table)

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

pk_values(resource, record)

@spec pk_values(module(), map()) :: map()

primary_key(resource)

@spec primary_key(module()) :: [atom()]

resolve_tenant(resource, record)

@spec resolve_tenant(module(), map()) :: {:ok, term()} | {:error, :tenant_required}

upsert_action(resource)

@spec upsert_action(module()) :: atom()

The upsert-capable create action name (the resource's primary create action).

upsert_identity(resource)

@spec upsert_identity(module()) :: atom() | nil

The upsert identity name from the DSL (nil → primary-key upsert).

upsert_input(arg, record)

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

upsert_reflection(resource)

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

writable_target(resource, source_col)

@spec writable_target(module(), String.t()) :: {:ok, atom()} | :skip