zf

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

arguments_of_correct_type.ex (5147B)


      1 defmodule Absinthe.Phase.Document.Validation.ArgumentsOfCorrectType do
      2   @moduledoc false
      3 
      4   # Validates document to ensure that all arguments are of the correct type.
      5 
      6   alias Absinthe.{Blueprint, Phase, Phase.Document.Validation.Utils, Schema, Type}
      7 
      8   use Absinthe.Phase
      9 
     10   @doc """
     11   Run this validation.
     12   """
     13   @spec run(Blueprint.t(), Keyword.t()) :: Phase.result_t()
     14   def run(input, _options \\ []) do
     15     result = Blueprint.prewalk(input, &handle_node(&1, input.schema))
     16 
     17     {:ok, result}
     18   end
     19 
     20   # Check arguments, objects, fields, and lists
     21   @spec handle_node(Blueprint.node_t(), Schema.t()) :: Blueprint.node_t()
     22   # handled by Phase.Document.Validation.KnownArgumentNames
     23   defp handle_node(%Blueprint.Input.Argument{schema_node: nil} = node, _schema) do
     24     {:halt, node}
     25   end
     26 
     27   # handled by Phase.Document.Validation.ProvidedNonNullArguments
     28   defp handle_node(%Blueprint.Input.Argument{input_value: %{normalized: nil}} = node, _schema) do
     29     {:halt, node}
     30   end
     31 
     32   defp handle_node(%Blueprint.Input.Argument{flags: %{invalid: _}} = node, schema) do
     33     descendant_errors = collect_child_errors(node.input_value, schema)
     34 
     35     message =
     36       error_message(
     37         node.name,
     38         Blueprint.Input.inspect(node.input_value),
     39         descendant_errors
     40       )
     41 
     42     error = error(node, message)
     43 
     44     node = node |> put_error(error)
     45 
     46     {:halt, node}
     47   end
     48 
     49   defp handle_node(node, _) do
     50     node
     51   end
     52 
     53   defp collect_child_errors(%Blueprint.Input.List{} = node, schema) do
     54     node.items
     55     |> Enum.map(& &1.normalized)
     56     |> Enum.with_index()
     57     |> Enum.flat_map(fn
     58       {%{schema_node: nil} = child, _} ->
     59         collect_child_errors(child, schema)
     60 
     61       {%{flags: %{invalid: _}} = child, idx} ->
     62         child_type_name =
     63           child.schema_node
     64           |> Type.value_type(schema)
     65           |> Type.name(schema)
     66 
     67         child_inspected_value = Blueprint.Input.inspect(child)
     68 
     69         [
     70           value_error_message(idx, child_type_name, child_inspected_value)
     71           | collect_child_errors(child, schema)
     72         ]
     73 
     74       {child, _} ->
     75         collect_child_errors(child, schema)
     76     end)
     77   end
     78 
     79   defp collect_child_errors(%Blueprint.Input.Object{} = node, schema) do
     80     node.fields
     81     |> Enum.flat_map(fn
     82       %{flags: %{invalid: _}, schema_node: nil} = child ->
     83         field_suggestions =
     84           case Type.unwrap(node.schema_node) do
     85             %Type.Scalar{} -> []
     86             %Type.Enum{} -> []
     87             nil -> []
     88             _ -> suggested_field_names(node.schema_node, child.name)
     89           end
     90 
     91         [unknown_field_error_message(child.name, field_suggestions)]
     92 
     93       %{flags: %{invalid: _}} = child ->
     94         child_type_name =
     95           Type.value_type(child.schema_node, schema)
     96           |> Type.name(schema)
     97 
     98         child_errors =
     99           case child.schema_node do
    100             %Type.Scalar{} -> []
    101             %Type.Enum{} -> []
    102             _ -> collect_child_errors(child.input_value, schema)
    103           end
    104 
    105         child_inspected_value = Blueprint.Input.inspect(child.input_value)
    106 
    107         [
    108           value_error_message(child.name, child_type_name, child_inspected_value)
    109           | child_errors
    110         ]
    111 
    112       child ->
    113         collect_child_errors(child.input_value.normalized, schema)
    114     end)
    115   end
    116 
    117   defp collect_child_errors(%Blueprint.Input.Value{normalized: norm}, schema) do
    118     collect_child_errors(norm, schema)
    119   end
    120 
    121   defp collect_child_errors(_node, _) do
    122     []
    123   end
    124 
    125   defp suggested_field_names(schema_node, name) do
    126     schema_node.fields
    127     |> Map.values()
    128     |> Enum.map(& &1.name)
    129     |> Absinthe.Utils.Suggestion.sort_list(name)
    130   end
    131 
    132   # Generate the error for the node
    133   @spec error(Blueprint.node_t(), String.t()) :: Phase.Error.t()
    134   defp error(node, message) do
    135     %Phase.Error{
    136       phase: __MODULE__,
    137       message: message,
    138       locations: [node.source_location]
    139     }
    140   end
    141 
    142   def error_message(arg_name, inspected_value, verbose_errors \\ [])
    143 
    144   def error_message(arg_name, inspected_value, []) do
    145     ~s(Argument "#{arg_name}" has invalid value #{inspected_value}.)
    146   end
    147 
    148   def error_message(arg_name, inspected_value, verbose_errors) do
    149     error_message(arg_name, inspected_value) <> "\n" <> Enum.join(verbose_errors, "\n")
    150   end
    151 
    152   def value_error_message(id, expected_type_name, inspected_value) when is_integer(id) do
    153     ~s(In element ##{id + 1}: ) <>
    154       expected_type_error_message(expected_type_name, inspected_value)
    155   end
    156 
    157   def value_error_message(id, expected_type_name, inspected_value) do
    158     ~s(In field "#{id}": ) <> expected_type_error_message(expected_type_name, inspected_value)
    159   end
    160 
    161   def unknown_field_error_message(field_name, suggestions \\ [])
    162 
    163   def unknown_field_error_message(field_name, []) do
    164     ~s(In field "#{field_name}": Unknown field.)
    165   end
    166 
    167   def unknown_field_error_message(field_name, suggestions) do
    168     ~s(In field "#{field_name}": Unknown field.) <>
    169       Utils.MessageSuggestions.suggest_message(suggestions)
    170   end
    171 
    172   defp expected_type_error_message(expected_type_name, inspected_value) do
    173     ~s(Expected type "#{expected_type_name}", found #{inspected_value}.)
    174   end
    175 end