GreenAsh.Registry (GreenAsh v0.3.0)

Copy Markdown View Source

Runtime discovery of Ash resources / actions from the list of domains provided by the host (via the router macro), and module <-> slug / primary key resolution for the console's routes.

No resource is hardcoded: everything comes from the domains passed as an argument and from Ash introspection.

Summary

Functions

Action struct by name (string or atom), or nil when resource declares no such action.

Label of an action: its description if defined, otherwise its humanized name.

Actions of a resource.

Decodes a primary key token into an identifier usable by Ash.get/2.

Encodes a record's primary key into a token for URL/form use.

Pagination declared by a read action, or nil.

Resource matching a slug among domains, or nil.

Short label of a resource (last segment of the module).

URL slug of a resource, unique among those domains expose (e.g. MyApp.Bank.Account -> "account").

Human description of a resource, if defined, otherwise its label.

All resources exposed by domains.

Whether resource cannot be read without a tenant being set.

Functions

action(resource, name)

Action struct by name (string or atom), or nil when resource declares no such action.

Action names arrive from the URL, so an unknown one is a routine event, not a bug: String.to_existing_atom/1 on a name no atom exists for raises, and a raise inside mount/3 is a 500 rather than a screen saying what is wrong.

action_label(action)

Label of an action: its description if defined, otherwise its humanized name.

actions(resource)

Actions of a resource.

decode_pk(resource, token)

Decodes a primary key token into an identifier usable by Ash.get/2.

encode_pk(record)

Encodes a record's primary key into a token for URL/form use.

Simple PK -> the raw value (backward-compatible). Composite PK -> a base64url token of a JSON {field => value}.

pagination(action)

Pagination declared by a read action, or nil.

Only required? pagination changes how a caller must read: Ash then refuses a read carrying no page options, and answers with an Ash.Page.* struct rather than a list — length/1 on one raises. A read that merely allows pagination is still read with plain limit/offset.

Note that Ash's defaults [:read] declares pagination while a hand-written read block does not, so neither can be assumed.

resource_by_slug(domains, slug)

Resource matching a slug among domains, or nil.

resource_label(resource)

Short label of a resource (last segment of the module).

resource_slug(resource, domains)

URL slug of a resource, unique among those domains expose (e.g. MyApp.Bank.Account -> "account").

The short form — the last module segment — is used wherever it is unambiguous, so slugs stay stable for the common case. It cannot be used blindly, though: MyApp.Bank.Account and MyApp.Sales.Account both end in Account, and giving them one slug does not merely hide the second. Every link to it, and every :actor naming it, resolves to the first instead — the console then shows one resource while claiming to show the other, with nothing on screen to suggest it. Colliding resources take a domain-qualified slug ("bank_account"), lengthening until they differ.

resource_title(resource)

Human description of a resource, if defined, otherwise its label.

resources(domains)

All resources exposed by domains.

tenant_required?(resource)

Whether resource cannot be read without a tenant being set.

Mirrors the check Ash itself performs before running a read (Ash.Actions.Read.validate_multitenancy/1): a resource is only constrained if it declares a multitenancy strategy and is not global?.

The console has no tenant to offer yet, so such a resource is signalled rather than opened — without this it reaches Ash.read!/2 and raises Ash.Error.Invalid.TenantRequired.