Kirayedar (Kirayedar v0.1.0)

View Source

Kirayedar - Multi-tenancy library for Elixir/Phoenix.

Provides schema-based isolation using PostgreSQL schemas or MySQL databases. Manages tenant state through the process dictionary and provides DDL operations.

Configuration

config :kirayedar,
  repo: MyApp.Repo,
  primary_domain: "example.com",
  admin_host: "admin.example.com",
  tenant_model: MyApp.Accounts.Tenant,
  adapter: :postgres  # or :mysql (optional - auto-detected from repo)

Usage

# Create a tenant
Kirayedar.create(repo, "tenant_slug")

# Drop a tenant
Kirayedar.drop(repo, "tenant_slug")

# Get current tenant
Kirayedar.current_tenant()

# Set current tenant
Kirayedar.put_tenant("tenant_slug")

# Run code without tenant scope
Kirayedar.scope_global(fn -> Repo.all(GlobalTable) end)

Telemetry Events

Kirayedar emits the following telemetry events:

  • [:kirayedar, :tenant, :create] - Tenant schema creation
  • [:kirayedar, :tenant, :drop] - Tenant schema deletion
  • [:kirayedar, :tenant, :migrate] - Tenant migration execution
  • [:kirayedar, :tenant, :create, :error] - Errors during creation
  • [:kirayedar, :tenant, :drop, :error] - Errors during deletion
  • [:kirayedar, :tenant, :migrate, :error] - Errors during migration

Each success event includes measurements: %{duration: milliseconds} Each event includes metadata: %{tenant: string, repo: module, action: atom}

Summary

Functions

Clears the current tenant from the process dictionary.

Creates a new tenant schema/database.

Gets the current tenant from the process dictionary.

Drops an existing tenant schema/database.

Sets the current tenant in the process dictionary. When set to nil, clears the tenant context.

Runs a block of code without any tenant prefix. Useful for querying global tables from within a tenant request.

Executes a function within the context of a specific tenant.

Types

repo()

@type repo() :: module()

tenant_id()

@type tenant_id() :: String.t() | nil

Functions

clear_tenant()

@spec clear_tenant() :: :ok

Clears the current tenant from the process dictionary.

create(repo, tenant_id)

@spec create(repo(), String.t()) :: :ok | {:error, term()}

Creates a new tenant schema/database.

Examples

iex> Kirayedar.create(MyApp.Repo, "acme_corp")
:ok

iex> Kirayedar.create(MyApp.Repo, "invalid slug!")
{:error, :invalid_tenant_id}

current_tenant()

@spec current_tenant() :: tenant_id()

Gets the current tenant from the process dictionary.

drop(repo, tenant_id)

@spec drop(repo(), String.t()) :: :ok | {:error, term()}

Drops an existing tenant schema/database.

Examples

iex> Kirayedar.drop(MyApp.Repo, "acme_corp")
:ok

put_tenant(tenant_id)

@spec put_tenant(tenant_id()) :: :ok

Sets the current tenant in the process dictionary. When set to nil, clears the tenant context.

scope_global(fun)

@spec scope_global((-> any())) :: any()

Runs a block of code without any tenant prefix. Useful for querying global tables from within a tenant request.

Examples

# Query global settings while in tenant context
Kirayedar.scope_global(fn ->
  Repo.all(GlobalSettings)
end)

# Access shared reference data
Kirayedar.scope_global(fn ->
  Repo.get(Country, "US")
end)

with_tenant(tenant_id, fun)

@spec with_tenant(tenant_id(), (-> any())) :: any()

Executes a function within the context of a specific tenant.

Examples

iex> Kirayedar.with_tenant("acme_corp", fn ->
...>   MyApp.Repo.all(MyApp.Post)
...> end)
[%MyApp.Post{}, ...]