AshArcadic.Multitenancy (AshArcadic v0.1.0)

Copy Markdown View Source

Resolves the ArcadeDB database name for a :context-multitenant resource + tenant. The name reaches a URL path, so it must be a valid Arcadic.Identifier (letter-first, ≤128 bytes), injective (distinct tenants → distinct databases — a hard isolation invariant), and deterministic.

Default two-branch encoder:

  • passthrough — a tenant whose stringified form is [A-Za-z0-9_]+ becomes "t_" <> tenant (the t_ supplies the letter start; a leading digit is fine). Keeps ULID/integer/slug tenants readable.
  • encode — anything else becomes "g" <> Base.encode32(tenant, :lower, no-pad); alphabet [a-z2-7], the g guarantees a letter start.

Branch A always starts t, branch B always starts g → disjoint namespaces; each branch is a constant prefix over an injective input. Anything that will not fit 128 bytes fails closed with a value-free error (steer to tenant_database).

The encoder keys on to_string(tenant), so distinct tenant terms that share a string form collide — integer 42 and string "42" both map to "t_42". This is harmless in a homogeneous tenant space; a space that mixes term types for the same logical tenant must set tenant_database to disambiguate. The default also assumes a String.Chars tenant: a non-String.Chars term (tuple/map/struct) raises rather than encoding — steer such tenants through tenant_database.

NOTE: the derived name is operator-visible (server logs, Arcadic.Server.list_databases). The passthrough branch echoes the tenant id into that surface — a tenant space whose id is itself classified should set tenant_database to hash it (see usage-rules).

Summary

Functions

The ArcadeDB database name for resource + tenant, or a value-free raise (fail-closed).

Functions

database_name(resource, tenant)

@spec database_name(Ash.Resource.t(), term()) :: String.t()

The ArcadeDB database name for resource + tenant, or a value-free raise (fail-closed).