Ash.Resource.Dsl (ash v1.37.2) View Source
The built in resource DSL. The core DSL components of a resource are:
Table of Contents
- identities
- identity
- attributes
- attribute
- create_timestamp
- update_timestamp
- timestamps
- integer_primary_key
- uuid_primary_key
- relationships
- has_one
- has_many
- many_to_many
- belongs_to
- actions
- create
- change
- validate
- argument
- read
- argument
- prepare
- update
- change
- validate
- argument
- destroy
- change
- validate
- argument
- create
- resource
- validations
- validate
- aggregates
- count
- first
- calculations
- calculate
- argument
- calculate
- multitenancy
- code_interface
- define
identities
Unique identifiers for the resource
Examples:
identities do
identity :full_name, [:first_name, :last_name]
identity :email, [:email]
end
identity
Represents a unique constraint on the resource.
Used for indicating that some set of attributes, calculations or aggregates uniquely identify a resource.
This will allow these fields to be passed to Ash.Api.get/3
, e.g get(Resource, [some_field: 10])
,
if all of the keys are filterable. Otherwise they are purely descriptive at the moment.
The primary key of the resource does not need to be listed as an identity.
Introspection Target:
Examples:
identity :name, [:name]
identity :full_name, [:first_name, :last_name]
:name
- Required. The name of the identity. Used by extensions to target specific identities for fetching single instances of a resource:keys
- Required. The names of attributes, aggregates or calculations that uniquely identify this resource.:description
- An optional description for the identity:message
- An error message to use when the unique identity would be violated
attributes
A section for declaring attributes on the resource.
Attributes are fields on an instance of a resource. The two required pieces of knowledge are the field name, and the type.
Examples:
attributes do
uuid_primary_key :id
attribute :first_name, :string do
allow_nil? false
end
attribute :last_name, :string do
allow_nil? false
end
attribute :email, :string do
allow_nil? false
constraints [
match: ~r/^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+.[a-zA-Z0-9-.]+$/
]
end
attribute :type, :atom do
constraints [
one_of: [:admin, :teacher, :student]
]
end
create_timestamp :inserted_at
update_timestamp :updated_at
end
attribute
Declares an attribute on the resource
Type can be either a built in type (see Ash.Type
) for more, or a module
implementing the Ash.Type
behaviour.
Strings are trimmed by default. If you want to retain whitespace, use
attribute :foo, :string, constraints: [trim?: false]
Introspection Target:
Examples:
attribute :first_name, :string do
primary_key? true
end
:name
- The name of the attribute.:type
- The type of the attribute.:constraints
- Constraints to provide to the type when casting the value. See the type's documentation for more information.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:primary_key?
- Whether or not the attribute is part of the primary key (one or more fields that uniquely identify a resource). If primary_key? is true, allow_nil? must be false. The default value isfalse
.:allow_nil?
- Whether or not the attribute can be set to nil. The default value istrue
.:generated?
- Whether or not the value may be generated by the data layer. If it is, the data layer will know to read the value back after writing. The default value isfalse
.:writable?
- Whether or not the value can be written to. The default value istrue
.:private?
- Whether or not the attribute will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql. The default value isfalse
.:update_default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_update/4
sets the default in the changeset if a value is not provided.:default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_create/4
sets the default in the changeset if a value is not provided.:description
- An optional description for the attribute.
create_timestamp
Declares a non-writable attribute with a create default of &DateTime.utc_now/0
Introspection Target:
Examples:
create_timestamp :inserted_at
:name
- The name of the attribute.:type
- The type of the attribute. The default value isAsh.Type.UtcDatetimeUsec
.:constraints
- Constraints to provide to the type when casting the value. See the type's documentation for more information.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:primary_key?
- Whether or not the attribute is part of the primary key (one or more fields that uniquely identify a resource). If primary_key? is true, allow_nil? must be false. The default value isfalse
.:allow_nil?
- Whether or not the attribute can be set to nil. The default value isfalse
.:generated?
- Whether or not the value may be generated by the data layer. If it is, the data layer will know to read the value back after writing. The default value isfalse
.:writable?
- Whether or not the value can be written to. The default value isfalse
.:private?
- Whether or not the attribute will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql. The default value istrue
.:update_default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_update/4
sets the default in the changeset if a value is not provided.:default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_create/4
sets the default in the changeset if a value is not provided. The default value is&DateTime.utc_now/0
.:description
- An optional description for the attribute.
update_timestamp
Declares a non-writable attribute with a create and update default of &DateTime.utc_now/0
Introspection Target:
Examples:
update_timestamp :inserted_at
:name
- The name of the attribute.:type
- The type of the attribute. The default value isAsh.Type.UtcDatetimeUsec
.:constraints
- Constraints to provide to the type when casting the value. See the type's documentation for more information.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:primary_key?
- Whether or not the attribute is part of the primary key (one or more fields that uniquely identify a resource). If primary_key? is true, allow_nil? must be false. The default value isfalse
.:allow_nil?
- Whether or not the attribute can be set to nil. The default value isfalse
.:generated?
- Whether or not the value may be generated by the data layer. If it is, the data layer will know to read the value back after writing. The default value isfalse
.:writable?
- Whether or not the value can be written to. The default value isfalse
.:private?
- Whether or not the attribute will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql. The default value istrue
.:update_default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_update/4
sets the default in the changeset if a value is not provided. The default value is&DateTime.utc_now/0
.:default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_create/4
sets the default in the changeset if a value is not provided. The default value is&DateTime.utc_now/0
.:description
- An optional description for the attribute.
timestamps
Declares non-writable inserted_at
and updated_at
attributes whith create and update defaults of &DateTime.utc_now/0
.
Introspection Target:
Examples:
timestamps()
integer_primary_key
Declares a generated (set by the data layer), non writable, non nil, primary key column of type integer.
Using integer_primary_key
, allow_nil?
is automatically set to false
.
Introspection Target:
Examples:
integer_primary_key :id
:name
- The name of the attribute.:type
- The type of the attribute. The default value isAsh.Type.Integer
.:constraints
- Constraints to provide to the type when casting the value. See the type's documentation for more information.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:primary_key?
- Whether or not the attribute is part of the primary key (one or more fields that uniquely identify a resource). If primary_key? is true, allow_nil? must be false. The default value istrue
.:generated?
- Whether or not the value may be generated by the data layer. If it is, the data layer will know to read the value back after writing. The default value istrue
.:writable?
- Whether or not the value can be written to. The default value isfalse
.:private?
- Whether or not the attribute will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql. The default value isfalse
.:update_default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_update/4
sets the default in the changeset if a value is not provided.:default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_create/4
sets the default in the changeset if a value is not provided.:description
- An optional description for the attribute.
uuid_primary_key
Declares a non writable, non nil, primary key column of type uuid, which defaults to Ash.UUID.generate/0
.
Using uuid_primary_key
, allow_nil?
is automatically set to false
.
Introspection Target:
Examples:
uuid_primary_key :id
:name
- The name of the attribute.:type
- The type of the attribute. The default value isAsh.Type.UUID
.:constraints
- Constraints to provide to the type when casting the value. See the type's documentation for more information.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:primary_key?
- Whether or not the attribute is part of the primary key (one or more fields that uniquely identify a resource). If primary_key? is true, allow_nil? must be false. The default value istrue
.:generated?
- Whether or not the value may be generated by the data layer. If it is, the data layer will know to read the value back after writing. The default value isfalse
.:writable?
- Whether or not the value can be written to. The default value isfalse
.:private?
- Whether or not the attribute will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql. The default value isfalse
.:update_default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_update/4
sets the default in the changeset if a value is not provided.:default
- A zero argument function, an {mod, fun, args} triple or a value.Ash.Changeset.for_create/4
sets the default in the changeset if a value is not provided. The default value is&Ash.UUID.generate/0
.:description
- An optional description for the attribute.
relationships
A section for declaring relationships on the resource.
Relationships are a core component of resource oriented design. Many components of Ash
will use these relationships. A simple use case is side_loading (done via the Ash.Query.load/2
).
Examples:
relationships do
belongs_to :post, MyApp.Post do
primary_key? true
end
belongs_to :category, MyApp.Category do
primary_key? true
end
end
relationships do
belongs_to :author, MyApp.Author
many_to_many :categories, MyApp.Category do
through MyApp.PostCategory
destination_field_on_join_table :category_id
source_field_on_join_table :post_id
end
end
relationships do
has_many :posts, MyApp.Post do
destination_field: :author_id
end
has_many :composite_key_posts, MyApp.CompositeKeyPost do
destination_field :author_id
end
end
has_one
Declares a has_one relationship. In a relationsal database, the foreign key would be on the other table.
Generally speaking, a has_one
also implies that the destination table is unique on that foreign key.
Introspection Target:
Ash.Resource.Relationships.HasOne
Examples:
# In a resource called `Word`
has_one :dictionary_entry, DictionaryEntry do
source_field :text
destination_field :word_text
end
:name
- The name of the relationship:destination
- The destination resource:destination_field
- Required. The field on the related resource that should match thesource_field
on this resource.:source_field
- The field on this resource that should match thedestination_field
on the related resource. The default value is:id
.:writable?
- Whether or not the relationship may be edited. The default value istrue
.:description
- An optional description for the relationship:context
- Context to be set on any queries or changesets generated for this relationship.
This is used by ash_postgres for polymorphic resources.:private?
- Whether or not the relationship will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql The default value isfalse
.:not_found_message
- A message to show if there is a conflict with this relationship in the database on update or create.
For example, if a value is added that has no match in the destination (very hard to do with the way Ash relationship changes work).:violation_message
- A message to show if there is a conflict with this relationship in the database on destroy. For example, if a record is deleted while related records still exist (and aren't configured to cascade deletes)
has_many
Declares a has_many relationship. There can be any number of related entities.
Introspection Target:
Ash.Resource.Relationships.HasMany
Examples:
# In a resource called `Word`
has_many :definitions, DictionaryDefinition do
source_field :text
destination_field :word_text
end
:name
- The name of the relationship:destination
- The destination resource:destination_field
- The field on the related resource that should match thesource_field
on this resource.:source_field
- The field on this resource that should match thedestination_field
on the related resource. The default value is:id
.:writable?
- Whether or not the relationship may be edited. The default value istrue
.:description
- An optional description for the relationship:context
- Context to be set on any queries or changesets generated for this relationship.
This is used by ash_postgres for polymorphic resources.:private?
- Whether or not the relationship will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql The default value isfalse
.:not_found_message
- A message to show if there is a conflict with this relationship in the database on update or create.
For example, if a value is added that has no match in the destination (very hard to do with the way Ash relationship changes work).:violation_message
- A message to show if there is a conflict with this relationship in the database on destroy. For example, if a record is deleted while related records still exist (and aren't configured to cascade deletes)
many_to_many
Declares a many_to_many relationship. Many to many relationships require a join table.
A join table is typically a table who's primary key consists of one foreign key to each resource.
Introspection Target:
Ash.Resource.Relationships.ManyToMany
Examples:
# In a resource called `Word`
many_to_many :books, Book do
through BookWord
source_field :text
source_field_on_join_table: :word_text
destination_field: :id
destination_field_on_join_table: :book_id
end
:source_field_on_join_table
- Required. The field on the join table that should line up withsource_field
on this resource.:destination_field_on_join_table
- Required. The field on the join table that should line up withdestination_field
on the related resource. Default: [relationshihp_name]_id:through
- Required. The resource to use as the join resource.:join_relationship
- The has_many relationship to the join table. Defaults to <relationship_name>_join_assoc:join_attributes
- Attributes to expose as editable when modifying the relationship.
Extensions may use this when deciding what fields to render from the join table.
SeeAsh.Changeset.append_to_relationship/3
andAsh.Changeset.replace_relationship/3
for how to edit these fields. The default value is[]
.:name
- The name of the relationship:destination
- The destination resource:destination_field
- The field on the related resource that should match thesource_field
on this resource. The default value is:id
.:source_field
- The field on this resource that should match thedestination_field
on the related resource. The default value is:id
.:writable?
- Whether or not the relationship may be edited. The default value istrue
.:description
- An optional description for the relationship:context
- Context to be set on any queries or changesets generated for this relationship.
This is used by ash_postgres for polymorphic resources.:private?
- Whether or not the relationship will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql The default value isfalse
.:not_found_message
- A message to show if there is a conflict with this relationship in the database on update or create.
For example, if a value is added that has no match in the destination (very hard to do with the way Ash relationship changes work).:violation_message
- A message to show if there is a conflict with this relationship in the database on destroy. For example, if a record is deleted while related records still exist (and aren't configured to cascade deletes)
belongs_to
Declares a belongs_to relationship. In a relational database, the foreign key would be on the source table.
This creates a field on the resource with the corresponding name and type, unless define_field?: false
is provided.
Introspection Target:
Ash.Resource.Relationships.BelongsTo
Examples:
# In a resource called `Word`
belongs_to :dictionary_entry, DictionaryEntry do
source_field :text,
destination_field: :word_text
end
:primary_key?
- Whether this field is, or is part of, the primary key of a resource. The default value isfalse
.:required?
- Whether this relationship must always be present, e.g: must be included on creation, and never removed (it can still be changed) The default value isfalse
.:define_field?
- If set tofalse
a field is not created on the resource for this relationship, and one must be manually added inattributes
. The default value istrue
.:field_type
- The field type of the automatically created field. The default value is:uuid
.:name
- The name of the relationship:destination
- The destination resource:destination_field
- The field on the related resource that should match thesource_field
on this resource. The default value is:id
.:source_field
- The field on this resource that should match thedestination_field
on the related resource. - Defaults to <name>_id:writable?
- Whether or not the relationship may be edited. The default value istrue
.:description
- An optional description for the relationship:context
- Context to be set on any queries or changesets generated for this relationship.
This is used by ash_postgres for polymorphic resources.:private?
- Whether or not the relationship will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql The default value isfalse
.:not_found_message
- A message to show if there is a conflict with this relationship in the database on update or create.
For example, if a value is added that has no match in the destination (very hard to do with the way Ash relationship changes work).:violation_message
- A message to show if there is a conflict with this relationship in the database on destroy. For example, if a record is deleted while related records still exist (and aren't configured to cascade deletes)
actions
A section for declaring resource actions.
All manipulation of data through the underlying data layer happens through actions.
There are four types of action: create
, read
, update
, and destroy
. You may
recognize these from the acronym CRUD
. You can have multiple actions of the same
type, as long as they have different names. This is the primary mechanism for customizing
your resources to conform to your business logic. It is normal and expected to have
multiple actions of each type in a large application.
Primary actions
If you have multiple actions of the same type, one of them must be designated as the
primary action for that type, via: primary?: true
. This tells the ash what to do
if an action of that type is requested, but no specific action name is given. This is how
many relationship changes will happen, by utilizing the primary actions. For this reason,
when defining actions, you usually want to ensure that the primary action takes no required
arguments . Without that, relationship changes to your resources might fail due to missing
arguments. This does, however, allow you to customize exactly how related entities are read/
created.
- create
- change
- validate
- argument
- read
- argument
- prepare
- update
- change
- validate
- argument
- destroy
- change
- validate
- argument
Examples:
actions do
create :signup do
argument :password, :string
argument :password_confirmation, :string
validate confirm(:password, :password_confirmation)
change {MyApp.HashPassword, []} # A custom implemented Change
end
read :me do
# An action that auto filters to only return the user for the current user
filter [id: actor(:id)]
end
update :update do
accept [:first_name, :last_name]
end
destroy do
change set_attribute(:deleted_at, &DateTime.utc_now/0)
# This tells it that even though this is a delete action, it
# should be treated like an update because `deleted_at` is set.
# This should be coupled with a `base_filter` on the resource
# or with the read actions having a `filter` for `is_nil: :deleted_at`
soft? true
end
end
Imports:
Ash.Resource.Change.Builtins
Ash.Resource.Preparation.Builtins
Ash.Resource.Validation.Builtins
Ash.Filter.TemplateHelpers
:defaults
- By default, an action of each type is added to each resource.
If any other actions of that same type are added, the default of that type is not added. If you wish to skip adding defaults of certain types, specify this option with the defaults that you do want implemented. The default value is[:create, :read, :update, :destroy]
.
create
Declares a create
action. For calling this action, see the Ash.Api
documentation.
Introspection Target:
Examples:
create :register do
primary? true
end
:name
- Required. The name of the action:primary?
- Whether or not this action should be used when no action is specified by the caller. The default value isfalse
.:description
- An optional description for the action:accept
- The list of attributes and relationships to accept. Defaults to all attributes on the resource:reject
- A list of attributes and relationships not to accept. This is useful if you want to say 'accept all but x'
If this is specified along withaccept
, then everything in theaccept
list minuse any matches in thereject
list will be accepted.
change
A change to be applied to the changeset after it is generated. They are run in order, from top to bottom.
To implement your own, see Ash.Resource.Change
.
To use it, you can simply refer to the module and its options, like so:
change {MyChange, foo: 1}
But for readability, you may want to define a function elsewhere and import it, so you can say something like:
change my_change(1)
For destroys, changes
are not applied unless soft?
is set to true.
Introspection Target:
Examples:
change relate_actor(:reporter)
change {MyCustomChange, :foo}
:change
- Required. The module and options for a change.
validate
Declares a validation for the current action
Introspection Target:
Examples:
validate changing(:email)
:validation
- Required. The module/opts pair of the validation:expensive?
- If a validation is expensive, it won't be run on invalid changes. All inexpensive validations are always run, to provide informative errors. The default value isfalse
.:message
- If provided, overrides any message set by the validation error:description
- An optional description for the validation
argument
Declares an argument on the action
The type can be either a built in type (see Ash.Type
) for more, or a module implementing
the Ash.Type
behaviour.
Introspection Target:
Examples:
argument :password_confirmation, :string
:allow_nil?
- Whether or not the argument may be ommitted or set tonil
The default value istrue
.:type
- Required. The type of the argument:name
- Required. The name of the argument:private?
- Whether or not the argument should be part of the public API The default value isfalse
.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:default
- The default value for the argument to take. It can be a zero argument function e.g&MyMod.my_fun/0
or a value:constraints
- Type constraints on the argument The default value is[]
.
read
Declares a read
action. For calling this action, see the Ash.Api
documentation.
Pagination
:keyset?
- Whether or not keyset based pagination is supported The default value isfalse
.:offset?
- Whether or not offset based pagination is supported The default value isfalse
.:default_limit
- The default page size to apply, if one is not supplied:countable
- Whether not a returned page will have a full count of all records. Use:by_default
to do it automatically. The default value isfalse
.:max_page_size
- The maximum amount of records that can be requested in a single page The default value is250
.:required?
- Whether or not pagination can be disabled. Only relevant if some pagination configuration is supplied. The default value istrue
.
Introspection Target:
Examples:
read :read_all do
primary? true
end
:filter
- A filter template, that may contain actor references. SeeAsh.Filter
for more on templates:pagination
- Options for how the action should support pagination. See the pagination section for more information. The default value isfalse
.:name
- Required. The name of the action:primary?
- Whether or not this action should be used when no action is specified by the caller. The default value isfalse
.:description
- An optional description for the action
argument
Declares an argument on the action
The type can be either a built in type (see Ash.Type
) for more, or a module implementing
the Ash.Type
behaviour.
Introspection Target:
Examples:
argument :password_confirmation, :string
:allow_nil?
- Whether or not the argument may be ommitted or set tonil
The default value istrue
.:type
- Required. The type of the argument:name
- Required. The name of the argument:private?
- Whether or not the argument should be part of the public API The default value isfalse
.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:default
- The default value for the argument to take. It can be a zero argument function e.g&MyMod.my_fun/0
or a value:constraints
- Type constraints on the argument The default value is[]
.
prepare
Declares a preparation, which can be used to prepare a query for a read action.
Introspection Target:
Examples:
prepare default_sort([:foo, :bar])
:preparation
- Required. The module and options for a preparation.
update
Declares a update
action. For calling this action, see the Ash.Api
documentation.
Introspection Target:
Examples:
update :flag_for_review, primary?: true
:name
- Required. The name of the action:primary?
- Whether or not this action should be used when no action is specified by the caller. The default value isfalse
.:description
- An optional description for the action:accept
- The list of attributes and relationships to accept. Defaults to all attributes on the resource:reject
- A list of attributes and relationships not to accept. This is useful if you want to say 'accept all but x'
If this is specified along withaccept
, then everything in theaccept
list minuse any matches in thereject
list will be accepted.
change
A change to be applied to the changeset after it is generated. They are run in order, from top to bottom.
To implement your own, see Ash.Resource.Change
.
To use it, you can simply refer to the module and its options, like so:
change {MyChange, foo: 1}
But for readability, you may want to define a function elsewhere and import it, so you can say something like:
change my_change(1)
For destroys, changes
are not applied unless soft?
is set to true.
Introspection Target:
Examples:
change relate_actor(:reporter)
change {MyCustomChange, :foo}
:change
- Required. The module and options for a change.
validate
Declares a validation for the current action
Introspection Target:
Examples:
validate changing(:email)
:validation
- Required. The module/opts pair of the validation:expensive?
- If a validation is expensive, it won't be run on invalid changes. All inexpensive validations are always run, to provide informative errors. The default value isfalse
.:message
- If provided, overrides any message set by the validation error:description
- An optional description for the validation
argument
Declares an argument on the action
The type can be either a built in type (see Ash.Type
) for more, or a module implementing
the Ash.Type
behaviour.
Introspection Target:
Examples:
argument :password_confirmation, :string
:allow_nil?
- Whether or not the argument may be ommitted or set tonil
The default value istrue
.:type
- Required. The type of the argument:name
- Required. The name of the argument:private?
- Whether or not the argument should be part of the public API The default value isfalse
.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:default
- The default value for the argument to take. It can be a zero argument function e.g&MyMod.my_fun/0
or a value:constraints
- Type constraints on the argument The default value is[]
.
destroy
Declares a destroy
action. For calling this action, see the Ash.Api
documentation.
Introspection Target:
Examples:
destroy :soft_delete do
primary? true
end
:soft?
- If specified, the destroy action calls the datalayer's update function with any specified changes.:name
- Required. The name of the action:primary?
- Whether or not this action should be used when no action is specified by the caller. The default value isfalse
.:description
- An optional description for the action:accept
- The list of attributes and relationships to accept. Defaults to all attributes on the resource:reject
- A list of attributes and relationships not to accept. This is useful if you want to say 'accept all but x'
If this is specified along withaccept
, then everything in theaccept
list minuse any matches in thereject
list will be accepted.
change
A change to be applied to the changeset after it is generated. They are run in order, from top to bottom.
To implement your own, see Ash.Resource.Change
.
To use it, you can simply refer to the module and its options, like so:
change {MyChange, foo: 1}
But for readability, you may want to define a function elsewhere and import it, so you can say something like:
change my_change(1)
For destroys, changes
are not applied unless soft?
is set to true.
Introspection Target:
Examples:
change relate_actor(:reporter)
change {MyCustomChange, :foo}
:change
- Required. The module and options for a change.
validate
Declares a validation for the current action
Introspection Target:
Examples:
validate changing(:email)
:validation
- Required. The module/opts pair of the validation:expensive?
- If a validation is expensive, it won't be run on invalid changes. All inexpensive validations are always run, to provide informative errors. The default value isfalse
.:message
- If provided, overrides any message set by the validation error:description
- An optional description for the validation
argument
Declares an argument on the action
The type can be either a built in type (see Ash.Type
) for more, or a module implementing
the Ash.Type
behaviour.
Introspection Target:
Examples:
argument :password_confirmation, :string
:allow_nil?
- Whether or not the argument may be ommitted or set tonil
The default value istrue
.:type
- Required. The type of the argument:name
- Required. The name of the argument:private?
- Whether or not the argument should be part of the public API The default value isfalse
.:sensitive?
- Whether or not the attribute value contains sensitive information, like PII. If so, it will be redacted while inspecting data. The default value isfalse
.:default
- The default value for the argument to take. It can be a zero argument function e.g&MyMod.my_fun/0
or a value:constraints
- Type constraints on the argument The default value is[]
.
resource
Resource-wide configuration
Examples:
resource do
description "A description of this resource"
base_filter [is_nil: :deleted_at]
end
Imports:
:description
- A human readable description of the resource, to be used in generated documentation:base_filter
- A filter statement to be applied to any queries on the resource:default_context
- Default context to apply to any queries/changesets generated for this resource.
validations
Declare validations prior to performing actions against the resource
Examples:
validations do
validate {Mod, [foo: :bar]}
validate at_least_one_of_present([:first_name, :last_name])
end
Imports:
validate
Declares a validation for creates and updates.
Introspection Target:
Examples:
validate {Mod, [foo: :bar]}
validate at_least_one_of_present([:first_name, :last_name])
:validation
- Required. The module/opts pair of the validation:on
- The action types the validation should run on.
Many validations don't make sense in the context of deletion, so by default it is left out of the list. The default value is[:create, :update]
.:expensive?
- If a validation is expensive, it won't be run on invalid changes. All inexpensive validations are always run, to provide informative errors. The default value isfalse
.:message
- If provided, overrides any message set by the validation error:description
- An optional description for the validation
aggregates
Declare named aggregates on the resource.
These are aggregates that can be loaded only by name using Ash.Query.load/2
.
They are also available as top level fields on the resource.
Examples:
aggregates do
count :assigned_ticket_count, :reported_tickets do
filter [active: true]
end
end
count
Declares a named count aggregate on the resource
Supports filter
, but not sort
(because that wouldn't affect the count)
Introspection Target:
Examples:
count :assigned_ticket_count, :assigned_tickets do
filter [active: true]
end
:name
- Required. The field to place the aggregate in:relationship_path
- Required. The relationship or relationship path to use for the aggregate:kind
- Required. The kind of the aggregate:field
- false The field to aggregate. Defaults to the first field in the primary key of the resource:filter
- A filter to apply to the aggregate The default value is[]
.:description
- An optional description for the aggregate:private?
- Whether or not the aggregate will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql The default value isfalse
.
first
Declares a named first
aggregate on the resource
First aggregates return the first value of the related record
that matches. Supports both filter
and sort
.
Introspection Target:
Examples:
first :first_assigned_ticket_subject, :assigned_tickets, :subject do
filter [active: true]
sort [:subject]
end
:name
- Required. The field to place the aggregate in:relationship_path
- Required. The relationship or relationship path to use for the aggregate:kind
- Required. The kind of the aggregate:field
- false The field to aggregate. Defaults to the first field in the primary key of the resource:filter
- A filter to apply to the aggregate The default value is[]
.:sort
- A sort to be applied to the aggregate:description
- An optional description for the aggregate:private?
- Whether or not the aggregate will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql The default value isfalse
.
calculations
Declare named calculations on the resource.
These are calculations that can be loaded only by name using Ash.Query.load/2
.
They are also available as top level fields on the resource.
- calculate
- argument
Examples:
calculations do
calculate :full_name, :string, MyApp.MyResource.FullName
end
Imports:
calculate
Declares a named calculation on the resource.
Takes a module that must adopt the Ash.Calculation
behaviour. See that module
for more information.
Introspection Target:
Examples:
calculate :full_name, :string, MyApp.MyResource.FullName
calculate :full_name, :string, {MyApp.FullName, keys: [:first_name, :last_name]}
calculate :full_name, :string, full_name([:first_name, :last_name])
:name
- Required. The field name to use for the calculation value:type
- Required.:calculation
- Required. The module or {module, opts} to use for the calculation:description
- An optional description for the calculation:private?
- Whether or not the calculation will appear in any interfaces created off of this resource, e.g AshJsonApi and AshGraphql The default value isfalse
.
argument
An argument to be passed into the calculation's arguments map
Introspection Target:
Ash.Resource.Calculation.Argument
Examples:
argument :params, :map do
default %{}
end
argument :retries, :integer do
allow_nil? false
end
:name
- Required. The name to use for the argument:type
- Required. The type of the argument:default
- false A default value to use for the argument if not provided:allow_nil?
- Whether or not the argument value may be nil The default value istrue
.:constraints
- Constraints to provide to the type when casting the value. See the type's documentation for more information. The default value is[]
.
multitenancy
Options for configuring the multitenancy behavior of a resource.
To specify a tenant, use Ash.Query.set_tenant/2
or
Ash.Changeset.set_tenant/2
before passing it to an operation.
Examples:
multitenancy do
strategy :attribute
attribute :organization_id
global? true
end
:strategy
- Determine how to perform multitenancy.:attribute
will expect that an attribute matches the giventenant
, e.gorg_id
.context
(the default) implies that the tenant will be passed to the datalayer as context. How a given data layer handles multitenancy will differ depending on the implementation. See the datalayer documentation for more. The default value is:context
.:attribute
- If using theattribute
strategy, the attribute to use, e.gorg_id
:global?
- Whether or not the data also exists outside of each tenant. This allows running queries and making changes without setting a tenant. This may eventually be extended to support describing the relationship to global data. For example, perhaps the global data is shared among all tenants (requiring "union" support in data layers), or perhaps global data is "merged" using some strategy (also requiring "union" support). The default value isfalse
.:parse_attribute
- An mfa ({module, function, args}) pointing to a function that takes a tenant and returns the attribute value The default value is{Ash.Resource.Dsl, :identity, []}
.
code_interface
Functions that will be defined on the Api module to interact with this resource.
Examples:
code_interface do
define :create_user, action: :create
define :get_user_by_id, action: :get_by_id, args: [:id], get?: true
end
define
Defines a function on the Api with the corresponding name and arguments.
If the action is an update or destroy, it will take a record or a changeset as its first argument. If the action is a read action, it will take a starting query as an opt in the last argument.
All functions will have an optional last argument that accepts options. Those options are:
:tenant
- set the tenant of the query/changeset:context
- set context on the query/changeset:actor
- set the actor for authorization:authorize?
- whether or not to perform authorization. If an actor option is provided (even if it isnil
), defaults totrue
. If not, defaults tofalse
.:verbose?
- a flag to toggle verbose output from the internal Ash engine (for debugging)
For reads:
:query
- a query to start the action with, can be used to filter/sort the results of the action.
They will also have an optional third argument that is a freeform map to provide action input. It must be a map.
If it is a keyword list, it will be assumed that it is actually options
(for convenience).
This allows for the following behaviour:
# Because the 3rd argument is a keyword list, we use it as options
Api.register_user(username, password, [tenant: "organization_22"])
# Because the 3rd argument is a keyword list, we use it as action input
Api.register_user(username, password, %{key: "val"})
# When all are provided it is unambiguous
Api.register_user(username, password, %{key: "val"}, [tenant: "organization_22"])
Introspection Target:
Examples:
define :get_user_by_id, action: :get_by_id, args: [:id], get?: true
:name
- Required. The name of the function that will be defined:action
- The name of the action that will be called. Defaults to the same name as the function.:args
- Map specific arguments to named inputs. Can provide any argument/attributes that the action allows.:get?
- Only relevant for read actions. Expects to only receive a single result from a read action.
For example,get_user_by_email
.