type_names_are_unique.ex (2693B)
1 defmodule Absinthe.Phase.Schema.Validation.TypeNamesAreUnique do 2 use Absinthe.Phase 3 alias Absinthe.Blueprint 4 5 def run(bp, _) do 6 bp = 7 bp 8 |> Blueprint.prewalk(&handle_schemas(&1, :identifier)) 9 |> Blueprint.prewalk(&handle_schemas(&1, :name)) 10 11 {:ok, bp} 12 end 13 14 defp handle_schemas(%Blueprint.Schema.SchemaDefinition{} = schema, key) do 15 if Enum.any?(schema.type_definitions, fn 16 %Blueprint.Schema.SchemaDefinition{} -> 17 true 18 19 _ -> 20 false 21 end) do 22 raise "SchemaDefinition Inside Schema Definition" 23 end 24 25 types = Enum.group_by(schema.type_definitions, &Map.fetch!(&1, key)) 26 directives = Enum.group_by(schema.directive_definitions, &Map.fetch!(&1, key)) 27 28 types = Map.merge(types, directives) 29 30 schema = Blueprint.prewalk(schema, &validate_types(&1, types, key)) 31 {:halt, schema} 32 end 33 34 defp handle_schemas(obj, _) do 35 obj 36 end 37 38 @types [ 39 Blueprint.Schema.DirectiveDefinition, 40 Blueprint.Schema.EnumTypeDefinition, 41 Blueprint.Schema.InputObjectTypeDefinition, 42 Blueprint.Schema.InterfaceTypeDefinition, 43 Blueprint.Schema.ObjectTypeDefinition, 44 Blueprint.Schema.ScalarTypeDefinition, 45 Blueprint.Schema.UnionTypeDefinition 46 ] 47 defp validate_types(%type{} = object, types, key) when type in @types do 48 ident = Map.fetch!(object, key) 49 50 case Map.fetch!(types, ident) do 51 [_] -> 52 object 53 54 others -> 55 detail = %{ 56 value: ident, 57 artifact: 58 case key do 59 :identifier -> "Absinthe type identifier" 60 :name -> "Type name" 61 end 62 } 63 64 object |> put_error(error(detail, others)) 65 end 66 end 67 68 defp validate_types(type, _, _) do 69 type 70 end 71 72 defp error(data, types) do 73 %Absinthe.Phase.Error{ 74 message: explanation(data), 75 locations: types |> Enum.map(& &1.__reference__.location), 76 phase: __MODULE__, 77 extra: data 78 } 79 end 80 81 @moduledoc false 82 83 @description """ 84 References to types must be unique. 85 86 > All types within a GraphQL schema must have unique names. No two provided 87 > types may have the same name. No provided type may have a name which 88 > conflicts with any built in types (including Scalar and Introspection 89 > types). 90 91 Reference: https://github.com/facebook/graphql/blob/master/spec/Section%203%20--%20Type%20System.md#type-system 92 """ 93 94 def explanation(%{artifact: artifact, value: name}) do 95 """ 96 #{artifact} #{inspect(name)} is not unique. 97 98 #{@description} 99 """ 100 end 101 102 # This rule is only used for its explanation. Error details are added during 103 # compilation. 104 def check(_), do: [] 105 end