defmodule Ash.Resource.Transformers.ValidateEagerIdentities do @moduledoc """ Confirms that eager identities are not declared on a resource with no primary read. """ use Spark.Dsl.Transformer alias Spark.Dsl.Transformer alias Spark.Error.DslError def after_compile?, do: true def transform(dsl_state) do primary_read = dsl_state |> Transformer.get_entities([:actions]) |> Enum.find(&(&1.type == :read && &1.primary?)) dsl_state |> Transformer.get_entities([:identities]) |> Enum.filter(&(&1.eager_check_with || &1.pre_check_with)) |> case do [] -> {:ok, dsl_state} eager -> attributes = Transformer.get_entities(dsl_state, [:attributes]) if primary_read do non_attributes = Enum.filter(eager, fn identity -> Enum.any?(identity.keys, fn key -> !Enum.any?(attributes, &(&1.name == key)) end) end) case non_attributes do [] -> {:ok, dsl_state} [identity] -> {:error, DslError.exception( path: [:identities, identity.name], message: "Identity #{identity.name} is declared with `eager_check_with` or `pre_check_with` but not all of the `keys` are attributes." )} identities -> {:error, DslError.exception( path: [:identities], message: "Identities #{Enum.map_join(identities, ",", & &1.name)} are declared with `eager_check_with` or `pre_check_with` but not all of the `keys` are attributes." )} end else names = Enum.map(eager, & &1.name) case names do [name] -> {:error, DslError.exception( path: [:identities, name], message: "Identity #{name} is declared with `eager_check_with` or `pre_check_with` but the resource has no primary read action." )} names -> {:error, DslError.exception( path: [:identities], message: "Identities #{Enum.join(names, ",")} are declared with `eager_check_with` or `pre_check_with` but the resource has no primary read action." )} end end end end end