Resolves the AGE graph name for a :context-multitenant resource + tenant.
The resolved name is a Postgres schema (AGE graph), so it must be a valid AGE identifier, at most 63 bytes, injective (distinct tenants map to distinct graphs — a hard isolation invariant), and deterministic.
Default two-branch encoder:
- pass-through — a tenant whose stringified form is identifier-body-clean
(
[A-Za-z0-9_]+) becomes"t_" <> tenant; thet_prefix supplies the required letter start, so a leading digit (ULID, integer id) is fine. Keeps ULID/integer/slug tenants readable. - encode — any other tenant (hyphens/exotic, e.g. a UUID) becomes
"g" <> Base.encode32(tenant, :lower, no-padding); alphabet[a-z2-7]is all valid, thegprefix guarantees a letter start, and a 36-byte UUID string fits at 59 bytes.
Injectivity: branch A always starts t, branch B always starts g, so the two
namespaces are disjoint; each branch is a constant prefix over an injective
input. Anything that will not fit 63 bytes fails closed with a value-free
error, steering the host to the tenant_graph MFA override. Injectivity is over
the stringified tenant (integer 42 and string "42" collide) — harmless in
a homogeneous tenant space; the MFA is the escape hatch otherwise.
Summary
Functions
Returns the AGE graph name for resource and tenant.
Functions
@spec graph_name(Ash.Resource.t(), term()) :: String.t()
Returns the AGE graph name for resource and tenant.
Uses the resource's tenant_graph MFA if configured, otherwise the default
two-branch encoder. Always returns a valid AGE identifier or raises a
value-free ArgumentError (fail-closed).