defmodule Ash.Domain.Verifiers.ValidateRelatedResourceInclusion do @moduledoc """ Ensures that all related resources are included in a domain. """ use Spark.Dsl.Verifier alias Spark.Dsl.Verifier @impl true def verify(dsl) do resources = dsl |> Verifier.get_entities([:resources]) |> Enum.map(& &1.resource) for resource <- resources do for relationship <- Ash.Resource.Info.relationships(resource) do if !Ash.Resource.Info.resource?(relationship.destination) do raise """ Relationship #{inspect(resource)}.#{relationship.name} has an invalid destination: #{inspect(relationship.destination)}. """ end domain = domain(relationship, dsl) if !domain do raise """ Could not determine domain for relationship #{inspect(resource)}.#{relationship.name}. Please configure a domain on the relationship directly. """ end if !Spark.Dsl.is?(domain, Ash.Domain) do raise """ Domain #{inspect(domain)}, in #{inspect(resource)}.#{relationship.name} is not a valid `Ash.Domain` """ end message = "is not accepted by domain `#{inspect(domain)}`" case Ash.Domain.Info.resource(domain, relationship.destination) do {:ok, _resource} -> :ok _ -> if relationship.type == :has_many && relationship.autogenerated_join_relationship_of do parent_relationship = Ash.Resource.Info.relationship( resource, relationship.autogenerated_join_relationship_of ) raise """ Error when compiling `#{inspect(relationship.source)}`: Resource `#{inspect(relationship.destination)}` #{message} for autogenerated join relationship: `:#{relationship.name}` Relationship was generated by the `many_to_many` relationship `#{inspect(parent_relationship.name)}` If the `through` resource `#{inspect(relationship.destination)}` is not accepted by the same domain as the destination resource `#{inspect(parent_relationship.destination)}`, then you must define that relationship manually. To define it manually, add the following to your relationships: has_many :#{relationship.name}, #{inspect(relationship.destination)} do # configure the relationship attributes ... end You can use a name other than `:#{relationship.name}`, but if you do, make sure to add that to `:#{parent_relationship.name}`, i.e many_to_many :#{relationship.name}, #{inspect(relationship.destination)} do ... join_relationship :your_new_name end """ else raise """ Error when compiling `#{inspect(relationship.source)}`: Resource `#{inspect(relationship.destination)}` in relationship `:#{relationship.name}` #{message}. Please do one of the following 1. add the resource to the domain `#{inspect(domain)}` 2. configure a different domain """ end end end end :ok end defp domain(relationship, dsl) do if relationship.domain do relationship.domain else Ash.Resource.Info.domain(relationship.destination) || Verifier.get_persisted(dsl, :module) end end end