Ash Integration
View SourceElex ships an optional Ash resource validation that type-checks expression strings stored on Ash attributes. The validation runs when the attribute changes on a changeset.
Setup
Add both Elex and Ash to your dependencies:
def deps do
[
{:elex, "~> 0.2.0"},
{:ash, "~> 3.22"}
]
endElex.AshValidation is compiled only when Ash is available. Without Ash in
your dependency tree, the module is not present.
Basic usage
Validate that a :formula attribute contains an expression returning a decimal:
defmodule MyApp.Product do
use Ash.Resource
attributes do
attribute :formula, :string do
allow_nil? false
end
end
validations do
validate Elex.AshValidation,
attribute: :formula,
context: Elex.new_context(),
expected_type: :decimal
end
endWhen a user submits an invalid expression, Ash returns a changeset error with a human-readable message from Elex.
Options
| Option | Required | Description |
|---|---|---|
:attribute | yes | Atom name of the string attribute holding the expression |
:context | yes | Elex.Context with allowed variables and functions |
:expected_type | yes | :decimal, :boolean, or :string |
:add_value_type_from_attribute | no | Attribute atom; adds a "value" variable typed from that attribute's current value |
:description | no | Custom text included in validation error messages |
Context with variables
Pass a context that includes every variable your users may reference:
context =
Elex.new_context()
|> Elex.add_variables(%{
"price" => 0,
"quantity" => 0
})
validations do
validate Elex.AshValidation,
attribute: :formula,
context: context,
expected_type: :decimal
endVariables in the context need types for validation to succeed, but their values are not used during validation — only types matter.
Validating against the current value
Use :add_value_type_from_attribute when expressions may reference a value
variable representing the attribute being validated:
attributes do
attribute :threshold, :decimal
attribute :condition, :string
end
validations do
validate Elex.AshValidation,
attribute: :condition,
context: Elex.new_context(),
expected_type: :boolean,
add_value_type_from_attribute: :threshold
endThis lets users write expressions like value > 100 where value is typed as
:decimal from the :threshold attribute.
What gets validated
On change, Elex.AshValidation:
- Reads the new value of the target attribute (skips validation when unchanged)
- Parses the expression string with
Elex.Parser.parse/3 - Checks the result type matches
:expected_type - Returns
:okor anAsh.Error.Changes.InvalidAttributeerror
Parse and type errors surface as attribute errors with the expression string as the invalid value.
Further reading
Elex.AshValidation— full API reference- Getting Started — building contexts and validating expressions
- Expression Language — syntax reference