unique_input_field_names.ex (1864B)
1 defmodule Absinthe.Phase.Document.Validation.UniqueInputFieldNames do 2 @moduledoc false 3 4 # Validates document to ensure that all input fields have unique names. 5 6 alias Absinthe.{Blueprint, Phase} 7 8 use Absinthe.Phase 9 use Absinthe.Phase.Validation 10 11 @doc """ 12 Run the validation. 13 """ 14 @spec run(Blueprint.t(), Keyword.t()) :: Phase.result_t() 15 def run(input, _options \\ []) do 16 result = Blueprint.prewalk(input, &handle_node/1) 17 {:ok, result} 18 end 19 20 # Find input objects 21 @spec handle_node(Blueprint.node_t()) :: Blueprint.node_t() 22 defp handle_node(%{normalized: %Blueprint.Input.Object{} = node} = parent) do 23 fields = Enum.map(node.fields, &process(&1, node.fields)) 24 node = %{node | fields: fields} 25 %{parent | normalized: node} 26 end 27 28 defp handle_node(node) do 29 node 30 end 31 32 # Check an input field, finding any duplicates 33 @spec process(Blueprint.Input.Field.t(), [Blueprint.Input.Field.t()]) :: 34 Blueprint.Input.Field.t() 35 defp process(field, fields) do 36 check_duplicates(field, Enum.filter(fields, &(&1.name == field.name))) 37 end 38 39 # Add flags and errors if necessary for each input field 40 @spec check_duplicates(Blueprint.Input.Field.t(), [Blueprint.Input.Field.t()]) :: 41 Blueprint.Input.Field.t() 42 defp check_duplicates(field, [_single]) do 43 field 44 end 45 46 defp check_duplicates(field, _multiple) do 47 field 48 |> flag_invalid(:duplicate_name) 49 |> put_error(error(field)) 50 end 51 52 # Generate an error for an input field 53 @spec error(Blueprint.Input.Field.t()) :: Phase.Error.t() 54 defp error(node) do 55 %Phase.Error{ 56 phase: __MODULE__, 57 message: error_message(), 58 locations: [node.source_location] 59 } 60 end 61 62 @doc """ 63 Generate the error message. 64 """ 65 @spec error_message :: String.t() 66 def error_message do 67 "Duplicate input field name." 68 end 69 end