zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

type_references_exist.ex (3156B)


      1 defmodule Absinthe.Phase.Schema.Validation.TypeReferencesExist do
      2   @moduledoc false
      3 
      4   use Absinthe.Phase
      5   alias Absinthe.Blueprint
      6   alias Absinthe.Blueprint.Schema
      7 
      8   def run(blueprint, _opts) do
      9     blueprint = Blueprint.prewalk(blueprint, &validate_schema/1)
     10 
     11     {:ok, blueprint}
     12   end
     13 
     14   def validate_schema(%Schema.SchemaDefinition{} = schema) do
     15     types =
     16       schema.type_definitions
     17       |> Enum.flat_map(&[&1.name, &1.identifier])
     18       |> MapSet.new()
     19 
     20     schema = Blueprint.prewalk(schema, &validate_types(&1, types))
     21     {:halt, schema}
     22   end
     23 
     24   def validate_schema(node), do: node
     25 
     26   def validate_types(%Blueprint.Schema.FieldDefinition{} = field, types) do
     27     check_or_error(field, field.type, types)
     28   end
     29 
     30   def validate_types(%Blueprint.Schema.ObjectTypeDefinition{} = object, types) do
     31     object
     32     |> check_types(:interfaces, &check_or_error(&2, &1, types))
     33     |> check_types(:imports, fn {type, _}, obj -> check_or_error(obj, type, types) end)
     34   end
     35 
     36   def validate_types(%Blueprint.Schema.InterfaceTypeDefinition{} = interface, types) do
     37     check_types(interface, :interfaces, &check_or_error(&2, &1, types))
     38   end
     39 
     40   def validate_types(%Blueprint.Schema.InputObjectTypeDefinition{} = object, types) do
     41     check_types(object, :imports, fn {type, _}, obj -> check_or_error(obj, type, types) end)
     42   end
     43 
     44   def validate_types(%Blueprint.Schema.InputValueDefinition{} = input, types) do
     45     check_or_error(input, input.type, types)
     46   end
     47 
     48   def validate_types(%Blueprint.Schema.UnionTypeDefinition{} = union, types) do
     49     check_types(union, :types, &check_or_error(&2, &1, types))
     50   end
     51 
     52   @no_types [
     53     Blueprint.Schema.DirectiveDefinition,
     54     Blueprint.Schema.EnumTypeDefinition,
     55     Blueprint.Schema.EnumValueDefinition,
     56     Blueprint.Schema.InterfaceTypeDefinition,
     57     Blueprint.Schema.ObjectTypeDefinition,
     58     Blueprint.Schema.ScalarTypeDefinition,
     59     Blueprint.Schema.SchemaDefinition,
     60     Blueprint.TypeReference.NonNull,
     61     Blueprint.TypeReference.ListOf,
     62     Absinthe.Blueprint.TypeReference.Name
     63   ]
     64   def validate_types(%struct{} = type, _) when struct in @no_types do
     65     type
     66   end
     67 
     68   def validate_types(type, _) do
     69     type
     70   end
     71 
     72   defp check_types(entity, key, fun) do
     73     entity
     74     |> Map.fetch!(key)
     75     |> Enum.reduce(entity, fun)
     76   end
     77 
     78   defp check_or_error(thing, type, types) do
     79     type = unwrap(type)
     80 
     81     if type in types do
     82       thing
     83     else
     84       put_error(thing, error(thing, type))
     85     end
     86   end
     87 
     88   defp unwrap(value) when is_binary(value) or is_atom(value) do
     89     value
     90   end
     91 
     92   defp unwrap(%Absinthe.Blueprint.TypeReference.Name{name: name}) do
     93     name
     94   end
     95 
     96   defp unwrap(type) do
     97     unwrap_type = Absinthe.Blueprint.TypeReference.unwrap(type)
     98 
     99     if unwrap_type == type do
    100       type
    101     else
    102       unwrap(unwrap_type)
    103     end
    104   end
    105 
    106   defp error(thing, type) do
    107     artifact_name = String.capitalize(thing.name)
    108 
    109     %Absinthe.Phase.Error{
    110       message: """
    111       In #{artifact_name}, #{inspect(type)} is not defined in your schema.
    112 
    113       Types must exist if referenced.
    114       """,
    115       locations: [thing.__reference__.location],
    116       phase: __MODULE__
    117     }
    118   end
    119 end