AshVersioned.Resource

Copy Markdown

Configures a resource for versioning. The source table gets a stable resource identifier, a version number, and a flag marking a row as the latest version, and mutations append new rows instead of updating in place.

Versioned resources must already have the following fields declared in attributes.

  • A surrogate primary key (uuid_v7_primary_key, integer_primary_key, or one already on a ported table). Composite keys are not supported.
  • Create and update timestamps (usually :inserted_at and :updated_at) with any non-null datetime-family attribute.

versioning

Configures SCD (type 2) version tracking on this resource.

Nested DSLs

Options

NameTypeDefaultDocs
create_timestamp_attributeatom:inserted_atThe name of the timestamp attribute used when inserting a new version. This reflects when this version became active. The attribute must already be defined in attributes.
update_timestamp_attributeatom:updated_atThe name of the timestamp attribute updated when a version is marked stale. This reflects when this version became inactive. The attribute must already be defined in attributes.
exclude_update_actionslist(atom)[]Update actions intentionally left as ordinary in-place updates instead of appending a new version. Every other update action on the resource is wired to append automatically. WARNING: This should only be used in exceptional circumstances, because it breaks the core promise of SCD (type 2) versioning: inactive versions don't change.
exclude_read_actionslist(atom)[]Read actions that should skip the default latest (and archived) scoping applied to every other read action. This could include hand-declared audit or admin-facing actions that need to see stale and archived versions.
history_actionatom:version_historyThe name of the generated read action that returns every version, ignoring the default latest/archived scoping.
source_prefixString.tIf specified, this prefix is applied to the underlying source of the generated AshVersioned fields. Fields adopting defined fields (define_attribute? false) or that declare source ignore this setting. elixir versioning do archive() source_prefix "vo_" end This is equivalent to: elixir versioning do archive :archived, source: :vo_archived identity :resource_id, source: :vo_resource_id latest :latest_version, source: :vo_latest_version version :version_number, source: :vo_version_number end The prefix is applied in front of any name given, so identity :mo_id would become identity :mo_id, source: :vo_mo_id.

versioning.identity

identity name \\ :resource_id

Configures the identity held by every version of the same versioned resource; a "logical" primary key.

If omitted, this is equivalent to identity :resource_id.

Examples

identity :resource_id
identity do
  origin :accepted
end
identity :resource_id, origin: :accepted
identity :mo_id do
  define_attribute? false
end

Arguments

NameTypeDefaultDocs
nameatom:resource_idThe name of the identity attribute.

Options

NameTypeDefaultDocs
define_attribute?booleantrueIf set to false, the identity attribute is not created and one must be manually added to attributes, invalidating many other options.
origin:generated | :accepted:generatedIf not set or set as :generated, the value of the identity is generated on resource creation. If set to :accepted, the identity is an accepted parameter on every create action.
typeany:uuid_v7The type of the generated attribute. See Ash.Type for more details. Types other than :uuid and :uuid_v7 require that origin be set to :accepted.
sourceatomThe name of the field on the underlying data layer.

Introspection

Target: AshVersioned.Resource.Identity

versioning.version

version name \\ :version_number

Configures the monotonically increasing version number, starting at 0.

If omitted, this is equivalent to version :version_number.

Examples

version :version_number
version :mo_version do
  define_attribute? false
end

Arguments

NameTypeDefaultDocs
nameatom:version_numberThe name of the version attribute.

Options

NameTypeDefaultDocs
define_attribute?booleantrueIf set to false, the version attribute is not created and one must be manually added to attributes, invalidating many other options.
sourceatomThe name of the field on the underlying data layer.

Introspection

Target: AshVersioned.Resource.Version

versioning.latest

latest name \\ :latest_version

Configures the boolean flag marking the current version for this resource.

If omitted, this is equivalent to latest :latest_version.

Examples

latest :latest_version
latest :mo_is_latest do
  define_attribute? false
end

Arguments

NameTypeDefaultDocs
nameatom:latest_versionThe name of the latest attribute.

Options

NameTypeDefaultDocs
define_attribute?booleantrueIf set to false, the latest attribute is not created and one must be manually added to attributes, invalidating many other options.
sourceatomThe name of the field on the underlying data layer.

Introspection

Target: AshVersioned.Resource.Latest

versioning.archive

archive attribute \\ :archived

Declares this resource archivable, which makes every destroy action a soft?: true destroy action.

If not set, defining destroy actions on the resource is a compile error.

Examples

archive :archived
archive do
  action :discard
end

Arguments

NameTypeDefaultDocs
attributeatom:archivedThe name of the boolean attribute marking a version as archived.

Options

NameTypeDefaultDocs
define_attribute?booleantrueIf set to false, the archived attribute is not created and one must be manually added to attributes, invalidating many other options.
actionatom | false:archiveThe name of a generated default destroy action, created using this name unless a destroy action is already defined (regardless of its name). Set to false to skip generating it unconditionally.
read_actionatom | false:get_with_archivedThe name of a generated get_by read action that returns the latest version of a resource by its identity attribute, whether or not it's archived. This action is scoped to return the latest version of a resource. Skipped if an action with this name is already defined. Set to false to skip generating it unconditionally.
unarchiveatom | false:unarchiveThe name of a generated update action that sets the archived to false, accepting no input. Skipped if an action with this name is already defined. Set to false to skip generating it unconditionally.
exclude_read_actionslist(atom)[]Additional read actions (beyond read_action) that should skip the filtering archived resources while still respecting the latest version filtering. An action name only needs to appear here or in the top-level exclude_read_actions, not both.
sourceatomThe name of the field on the underlying data layer.

Introspection

Target: AshVersioned.Resource.Archive

versioning.reference_actor

reference_actor name

Creates a :string attribute for storing the actor responsible for resource version creation.

reference_actor can be used when the actor field holds heterogeneous ID spaces (admin, customer, or sentinel values like "system") that may not resolve to Ash resources. It works best with prefixed object ID strings (admin_QweRTy, customer_Dv0rAk, etc.).

For more than one possible Ash resource actor type, use belongs_to_actor instead, which discriminates by the actor type.

Examples

reference_actor :created_by
reference_actor :created_by, transform: &MyApp.actor_reference/1

Arguments

NameTypeDefaultDocs
nameatomThe name of the attribute to use for the actor.

Options

NameTypeDefaultDocs
transform(any -> any) | mfa&AshVersioned.ReferenceActorValue.value_for/1A function or {module, function, args} to transform the actor into a suitable string reference. The default is AshVersioned.ReferenceActorValue.value_for/1. Use a different function when support for composite primary keys, prefixed keys, or some other requirement arises.
allow_nil?booleantrueWhether this attribute can be nil.
public?booleanfalseWhether this attribute should be shown over public interfaces.

Introspection

Target: AshVersioned.Resource.ReferenceActor

versioning.belongs_to_actor

belongs_to_actor name, destination

Creates a belongs_to relationship to the actor resource. When creating a new version, associates the action's actor with the matching resource type. For polymorphic or variant types, declare a belongs_to_actor for each type.

If your actor is not a resource, consider using reference_actor instead.

Examples

belongs_to_actor :edited_by, MyApp.Users.Author
belongs_to_actor :reviewed_by, MyApp.Users.Author, domain: MyApp.Users

Arguments

NameTypeDefaultDocs
nameatomThe name of the relationship to use for the actor.
destinationmoduleThe resource of the actor (e.g. MyApp.Users.User)

Options

NameTypeDefaultDocs
allow_nil?booleantrueWhether this relationship must always be present. The generated attribute will not allow nil values.
domainatomThe Domain module to use when working with the related entity.
attribute_typeany:uuidThe type of the generated attribute. See Ash.Type for more.
public?booleanfalseWhether this relationship should be included in public interfaces
define_attribute?booleantrueIf set to false, an attribute is not created on the resource for this relationship, and one must be manually added in attributes, invalidating many other options.
on_delete:delete | :nilify | :nothing | :restrict | {:nilify, atom | list(atom)}:nothingThe action to take on this row when the actor is deleted. Can also be {:nilify, columns} to nilify specific columns (Postgres 15+ only). Only relevant for resources using a SQL data layer. Has no impact when destination is an AshVersioned.Resource.

Introspection

Target: AshVersioned.Resource.BelongsToActor