How to create an atomic validation for the amount on AshMoney?

I have an attribute using AshMoney like so:
attribute :amount, :money do
constraints storage_type: :money_with_currency
allow_nil? false
end
attribute :amount, :money do
constraints storage_type: :money_with_currency
allow_nil? false
end
And I'd like to validate that the amount part is non-zero, ignoring the currency. I've managed to create a custom validation for it but it's not atomic:
@impl true
def validate(changeset = %Ash.Changeset{}, _opts, _context) do
amount = Ash.Changeset.get_attribute(changeset, :amount)

if Decimal.eq?(amount.amount, Decimal.new(0)) do
{:error, field: :amount, message: "can't be zero"}
else
:ok
end
end
@impl true
def validate(changeset = %Ash.Changeset{}, _opts, _context) do
amount = Ash.Changeset.get_attribute(changeset, :amount)

if Decimal.eq?(amount.amount, Decimal.new(0)) do
{:error, field: :amount, message: "can't be zero"}
else
:ok
end
end
9 Replies
barnabasj
barnabasj•2mo ago
I think if you have the postgres extension installed, you should just be able to compare against the value 0
jonas_h
jonas_hOP•2mo ago
This does compile:
validate argument_does_not_equal(:amount, 0)
validate argument_does_not_equal(:amount, 0)
However it doesn't seem to block the creation of the resource
barnabasj
barnabasj•2mo ago
can you try attribute_does_not_equal instead
jonas_h
jonas_hOP•2mo ago
Cool, that works 🙂 Another question: Is it possible to do the same on an aggregate? I got this:
Invalid Error

* Invalid value provided for in_out_balance: must equal 0.

Value: #Ash.NotLoaded<:aggregate, field: :in_out_balance>
Invalid Error

* Invalid value provided for in_out_balance: must equal 0.

Value: #Ash.NotLoaded<:aggregate, field: :in_out_balance>
aggregates do
sum :in_out_balance, :parts, field: :amount
end
aggregates do
sum :in_out_balance, :parts, field: :amount
end
And
validate attribute_equals(:in_out_balance, 0)
validate attribute_equals(:in_out_balance, 0)
barnabasj
barnabasj•2mo ago
you could try to do your own validation moduel that mirrors this one https://github.com/ash-project/ash/blob/v3.5.34/lib/ash/resource/validation/attribute_does_not_equal.ex but only has a atomic callback.
GitHub
ash/lib/ash/resource/validation/attribute_does_not_equal.ex at v3.5...
A declarative, extensible framework for building Elixir applications. - ash-project/ash
barnabasj
barnabasj•2mo ago
I think the problem is that it tries to do the regular validate in your case and there the value is not loaded
jonas_h
jonas_hOP•2mo ago
Okay, cool. Thanks again!
barnabasj
barnabasj•2mo ago
or this one is the one you used

Did you find this page helpful?