phase.ex (1885B)
1 defmodule Absinthe.Phase do 2 @moduledoc """ 3 Behaviour for Absinthe Phases. 4 5 A phase takes an `Absinthe.Blueprint` document and returns another blueprint document. 6 All validation, resolution, and result building happens via phases. See 7 `Absinthe.Pipeline` for information on how to run phases. See the code under 8 this namespace for information on individual phases. 9 """ 10 11 @type t :: module 12 @type result_t :: 13 {:ok, any} 14 | {:jump, any, t} 15 | {:insert, any, t | [t]} 16 | {:replace, any, t | [t]} 17 | {:error, any} 18 | {:record_phases, any, (any, any -> any)} 19 20 alias __MODULE__ 21 alias Absinthe.Blueprint 22 23 defmacro __using__(_) do 24 quote do 25 @behaviour Phase 26 import(unquote(__MODULE__)) 27 28 @spec flag_invalid(Blueprint.node_t()) :: Blueprint.node_t() 29 def flag_invalid(%{flags: _} = node) do 30 Absinthe.Blueprint.put_flag(node, :invalid, __MODULE__) 31 end 32 33 @spec flag_invalid(Blueprint.node_t(), atom) :: Blueprint.node_t() 34 def flag_invalid(%{flags: _} = node, flag) do 35 flagging = %{:invalid => __MODULE__, flag => __MODULE__} 36 update_in(node.flags, &Map.merge(&1, flagging)) 37 end 38 39 def put_flag(%{flags: _} = node, flag) do 40 Absinthe.Blueprint.put_flag(node, flag, __MODULE__) 41 end 42 43 def inherit_invalid(%{flags: _} = node, children, add_flag) do 44 case any_invalid?(children) do 45 true -> 46 flag_invalid(node, add_flag) 47 48 false -> 49 node 50 end 51 end 52 end 53 end 54 55 @spec put_error(Blueprint.node_t(), Phase.Error.t()) :: Blueprint.node_t() 56 def put_error(%{errors: _} = node, error) do 57 update_in(node.errors, &[error | &1]) 58 end 59 60 def any_invalid?(nodes) do 61 Enum.any?(nodes, &match?(%{flags: %{invalid: _}}, &1)) 62 end 63 64 @callback run(any, any) :: result_t 65 end