unique_field_names.ex (1703B)
1 defmodule Absinthe.Phase.Schema.Validation.UniqueFieldNames do 2 @moduledoc false 3 4 @behaviour Absinthe.Phase 5 alias Absinthe.Blueprint 6 7 def run(bp, _) do 8 bp = 9 bp 10 |> Blueprint.prewalk(&handle_schemas(&1, :name)) 11 12 {:ok, bp} 13 end 14 15 defp handle_schemas(%Blueprint.Schema.SchemaDefinition{} = schema, key) do 16 schema = Blueprint.prewalk(schema, &validate_types(&1, key)) 17 {:halt, schema} 18 end 19 20 defp handle_schemas(obj, _) do 21 obj 22 end 23 24 defp validate_types(%type{} = object, key) 25 when type in [ 26 Blueprint.Schema.InputObjectTypeDefinition, 27 Blueprint.Schema.InterfaceTypeDefinition, 28 Blueprint.Schema.ObjectTypeDefinition 29 ] do 30 fields = 31 for field <- object.fields do 32 name_counts = Enum.frequencies_by(object.fields, &Map.get(&1, key)) 33 34 if duplicate?(name_counts, field, key) do 35 Absinthe.Phase.put_error(field, error(field, object)) 36 else 37 field 38 end 39 end 40 41 %{object | fields: fields} 42 end 43 44 defp validate_types(type, _) do 45 type 46 end 47 48 defp duplicate?(name_counts, field, key) do 49 field_identifier = Map.get(field, key) 50 Map.get(name_counts, field_identifier, 0) > 1 51 end 52 53 defp error(field, object) do 54 %Absinthe.Phase.Error{ 55 message: explanation(field, object), 56 locations: [field.__reference__.location], 57 phase: __MODULE__, 58 extra: field 59 } 60 end 61 62 def explanation(field, object) do 63 """ 64 The field #{inspect(field.name)} is not unique in type #{inspect(object.name)}. 65 66 The field must have a unique name within that Object type; no two fields may share the same name. 67 """ 68 end 69 end