zf

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

input_output_types_correctly_placed.ex (3830B)


      1 defmodule Absinthe.Phase.Schema.Validation.InputOutputTypesCorrectlyPlaced do
      2   use Absinthe.Phase
      3   alias Absinthe.Blueprint
      4 
      5   def run(bp, _) do
      6     bp = Blueprint.prewalk(bp, &handle_schemas/1)
      7     {:ok, bp}
      8   end
      9 
     10   defp handle_schemas(%Blueprint.Schema.SchemaDefinition{} = schema) do
     11     types = Map.new(schema.type_definitions, &{&1.identifier, &1})
     12     schema = Blueprint.prewalk(schema, &validate_type(&1, types, schema))
     13     {:halt, schema}
     14   end
     15 
     16   defp handle_schemas(obj) do
     17     obj
     18   end
     19 
     20   defp validate_type(%Blueprint.Schema.InputValueDefinition{} = arg, types, schema) do
     21     type =
     22       Blueprint.TypeReference.unwrap(arg.type)
     23       |> Blueprint.TypeReference.to_type(schema)
     24 
     25     arg_type = Map.get(types, type)
     26 
     27     if arg_type && wrong_type?(Blueprint.Schema.InputValueDefinition, arg_type) do
     28       detail = %{
     29         argument: arg.identifier,
     30         type: arg_type.identifier,
     31         struct: arg_type.__struct__
     32       }
     33 
     34       arg |> put_error(error(arg.__reference__.location, detail))
     35     else
     36       arg
     37     end
     38   end
     39 
     40   defp validate_type(%struct{fields: fields} = type, types, schema) do
     41     fields =
     42       Enum.map(fields, fn
     43         %{type: _} = field ->
     44           type =
     45             Blueprint.TypeReference.unwrap(field.type)
     46             |> Blueprint.TypeReference.to_type(schema)
     47 
     48           field_type = Map.get(types, type)
     49 
     50           if field_type && wrong_type?(struct, field_type) do
     51             detail = %{
     52               field: field.identifier,
     53               type: field_type.identifier,
     54               struct: field_type.__struct__,
     55               parent: struct
     56             }
     57 
     58             field |> put_error(error(field.__reference__.location, detail))
     59           else
     60             field
     61           end
     62 
     63         field ->
     64           field
     65       end)
     66 
     67     %{type | fields: fields}
     68   end
     69 
     70   defp validate_type(type, _types, _schema) do
     71     type
     72   end
     73 
     74   @output_types [
     75     Blueprint.Schema.ObjectTypeDefinition,
     76     Blueprint.Schema.UnionTypeDefinition,
     77     Blueprint.Schema.InterfaceTypeDefinition
     78   ]
     79   defp wrong_type?(type, field_type) when type in @output_types do
     80     !output_type?(field_type)
     81   end
     82 
     83   @input_types [
     84     Blueprint.Schema.InputObjectTypeDefinition,
     85     Blueprint.Schema.InputValueDefinition
     86   ]
     87   defp wrong_type?(type, field_type) when type in @input_types do
     88     !input_type?(field_type)
     89   end
     90 
     91   defp error(location, data) do
     92     %Absinthe.Phase.Error{
     93       message: explanation(data),
     94       locations: [location],
     95       phase: __MODULE__,
     96       extra: data
     97     }
     98   end
     99 
    100   @moduledoc false
    101 
    102   @description """
    103   Only input types may be used as inputs. Input types may not be used as output types
    104 
    105   Input types consist of Scalars, Enums, and Input Objects.
    106   """
    107 
    108   def explanation(%{argument: argument, type: type, struct: struct}) do
    109     struct = struct |> Module.split() |> List.last()
    110 
    111     """
    112     #{inspect(type)} is not a valid input type for argument #{inspect(argument)} because
    113     #{inspect(type)} is an #{Macro.to_string(struct)}. Arguments may only be input types.
    114 
    115     #{@description}
    116     """
    117   end
    118 
    119   def explanation(%{field: field, type: type, struct: struct, parent: parent}) do
    120     struct = struct |> Module.split() |> List.last()
    121     parent = parent |> Module.split() |> List.last()
    122 
    123     """
    124     #{inspect(type)} is not a valid type for field #{inspect(field)} because
    125     #{inspect(type)} is an #{struct}, and this field is part of an #{parent}.
    126 
    127     #{@description}
    128     """
    129   end
    130 
    131   defp input_type?(%Blueprint.Schema.ScalarTypeDefinition{}), do: true
    132   defp input_type?(%Blueprint.Schema.EnumTypeDefinition{}), do: true
    133   defp input_type?(%Blueprint.Schema.InputObjectTypeDefinition{}), do: true
    134   defp input_type?(_), do: false
    135 
    136   defp output_type?(%Blueprint.Schema.InputObjectTypeDefinition{}), do: false
    137   defp output_type?(_), do: true
    138 end