diff --git a/lib/ash/resource/dsl.ex b/lib/ash/resource/dsl.ex index f1a26b56..fd224244 100644 --- a/lib/ash/resource/dsl.ex +++ b/lib/ash/resource/dsl.ex @@ -1332,7 +1332,8 @@ defmodule Ash.Resource.Dsl do @verifiers [ Ash.Resource.Verifiers.ValidateRelationshipAttributesMatch, - Ash.Resource.Verifiers.VerifyReservedCalculationArguments + Ash.Resource.Verifiers.VerifyReservedCalculationArguments, + Ash.Resource.Verifiers.VerifyIdentityFields ] @moduledoc """ diff --git a/lib/ash/resource/verifiers/verfiy_identities.ex b/lib/ash/resource/verifiers/verfiy_identities.ex new file mode 100644 index 00000000..9b971dd8 --- /dev/null +++ b/lib/ash/resource/verifiers/verfiy_identities.ex @@ -0,0 +1,23 @@ +defmodule Ash.Resource.Verifiers.VerifyIdentityFields do + @moduledoc """ + Raises an error on potentially incompatible identity attributes. + """ + use Spark.Dsl.Verifier + + def verify(dsl) do + identities = Ash.Resource.Info.identities(dsl) + + for identity <- identities do + for key <- identity.keys do + if !Ash.Resource.Info.attribute(dsl, key) do + raise Spark.Error.DslError, + module: Spark.Dsl.Verifier.get_persisted(dsl, :module), + message: "All identity keys must be attributes. Got: #{inspect(key)}", + path: [:identities, identity.name] + end + end + end + + :ok + end +end diff --git a/test/resource/identities_test.exs b/test/resource/identities_test.exs index 24ccc3ae..eeb7242a 100644 --- a/test/resource/identities_test.exs +++ b/test/resource/identities_test.exs @@ -69,5 +69,37 @@ defmodule Ash.Test.Resource.IdentitiesTest do %Ash.Resource.Identity{description: "require one of name/contents"} ] = Ash.Resource.Info.identities(Post) end + + test "enforce identity constraints on attributes" do + assert_raise Spark.Error.DslError, + ~r/All identity keys must be attributes. Got: :naem/, + fn -> + defmodule Site do + @moduledoc false + use Ash.Resource + + attributes do + uuid_primary_key :id + attribute :url, :string + end + end + + defposts do + actions do + read :read do + primary? true + end + + relationships do + belongs_to :site, Site + end + end + + identities do + identity :name_site, [:naem, :site] + end + end + end + end end end