defmodule Ash.Test.Resource.Changes.UpdateChangeTest do @moduledoc false use ExUnit.Case, async: true defmodule TimeMachine do @moduledoc false def double_age(42) do raise "boom" end def double_age(age) when is_integer(age) and age >= 0 and age < 200 do age * 2 end end defmodule Author do @moduledoc false use Ash.Resource, data_layer: Ash.DataLayer.Ets, domain: Ash.Test.Domain ets do private?(true) end actions do create :double_age do accept([:name, :age]) change update_change(:age, &TimeMachine.double_age/1) validate numericality(:age, less_than: 200) end create :triple_age do accept([:name, :age]) change update_change(:age, fn age -> age * 3 end) end end attributes do uuid_primary_key :id attribute(:name, :string, public?: true, allow_nil?: false) attribute(:age, :integer, public?: true, allow_nil?: false, constraints: [min: 0]) end end describe "update_change builtin" do test "works with valid change" do author = Author |> Ash.Changeset.for_create(:double_age, %{name: "foo", age: 20}) |> Ash.create!() assert author.age == 40 end test "works with inline function" do author = Author |> Ash.Changeset.for_create(:triple_age, %{name: "foo", age: 20}) |> Ash.create!() assert author.age == 60 end test "calls update function with casted attribute" do author = Author |> Ash.Changeset.for_create(:double_age, %{name: "foo", age: "20"}) |> Ash.create!() assert author.age == 40 end test "doesn't call update function with failed constraint" do {:error, _} = Author |> Ash.Changeset.for_create(:double_age, %{name: "foo", age: -5}) |> Ash.create() end test "doesn't call update function with missing required attribute" do {:error, _} = Author |> Ash.Changeset.for_create(:double_age, %{name: "foo"}) |> Ash.create() end test "doesn't call update function with other changeset errors" do {:error, _} = Author |> Ash.Changeset.for_create(:double_age, %{age: 42}) |> Ash.create() end end end