diff --git a/lib/verifiers/validate_references.ex b/lib/verifiers/validate_references.ex index eab2fca1..912d0701 100644 --- a/lib/verifiers/validate_references.ex +++ b/lib/verifiers/validate_references.ex @@ -11,13 +11,29 @@ defmodule AshPostgres.Verifiers.ValidateReferences do dsl |> AshPostgres.DataLayer.Info.references() |> Enum.each(fn reference -> - if !Ash.Resource.Info.relationship(dsl, reference.relationship) do - raise Spark.Error.DslError, - path: [:postgres, :references, reference.relationship], - module: Verifier.get_persisted(dsl, :module), - message: - "Found reference configuration for relationship `#{reference.relationship}`, but no such relationship exists", - location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :references]) + relationship = Ash.Resource.Info.relationship(dsl, reference.relationship) + + cond do + is_nil(relationship) -> + raise Spark.Error.DslError, + path: [:postgres, :references, reference.relationship], + module: Verifier.get_persisted(dsl, :module), + message: + "Found reference configuration for relationship `#{reference.relationship}`, but no such relationship exists", + location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :references]) + + relationship.type != :belongs_to -> + raise Spark.Error.DslError, + path: [:postgres, :references, reference.relationship], + module: Verifier.get_persisted(dsl, :module), + message: + "Found reference configuration for relationship `#{reference.relationship}`, but it is a `#{relationship.type}` relationship. " <> + "References can only be configured for `belongs_to` relationships, because the foreign key is defined on the table with the `belongs_to` relationship. " <> + "To configure the behavior of this foreign key, add the reference configuration to the resource with the corresponding `belongs_to` relationship.", + location: Spark.Dsl.Transformer.get_section_anno(dsl, [:postgres, :references]) + + true -> + :ok end end) diff --git a/test/references_test.exs b/test/references_test.exs index 4381bfd8..770df27b 100644 --- a/test/references_test.exs +++ b/test/references_test.exs @@ -114,6 +114,68 @@ defmodule AshPostgres.ReferencesTest do assert io =~ "Unsupported match_type" end + test "raises error when reference is configured for a has_many relationship" do + Code.compiler_options(ignore_module_conflict: true) + on_exit(fn -> Code.compiler_options(ignore_module_conflict: false) end) + + {_, io} = + with_io(:stderr, fn -> + defmodule Parent do + @moduledoc false + use Ash.Resource, + domain: nil, + data_layer: AshPostgres.DataLayer + + attributes do + uuid_primary_key(:id) + end + + relationships do + has_many :children, AshPostgres.ReferencesTest.Child + end + + postgres do + table("parents") + repo(AshPostgres.TestRepo) + + references do + reference :children, on_delete: :delete + end + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + end + + defmodule Child do + @moduledoc false + use Ash.Resource, + domain: nil, + data_layer: AshPostgres.DataLayer + + attributes do + uuid_primary_key(:id) + end + + relationships do + belongs_to :parent, AshPostgres.ReferencesTest.Parent + end + + postgres do + table("children") + repo(AshPostgres.TestRepo) + end + + actions do + defaults([:create, :read, :update, :destroy]) + end + end + end) + + assert io =~ "References can only be configured for `belongs_to` relationships" + end + test "named reference results in properly applied foreign_key_constraint/3 on the underlying changeset" do # Create a comment with an invalid post_id assert {:error, %Ash.Error.Invalid{errors: errors}} =