default_enum_value_present.ex (2524B)
1 defmodule Absinthe.Phase.Schema.Validation.DefaultEnumValuePresent do 2 use Absinthe.Phase 3 alias Absinthe.Blueprint 4 alias Absinthe.Blueprint.Schema 5 6 def run(blueprint, _opts) do 7 blueprint = Blueprint.prewalk(blueprint, &validate_schema/1) 8 9 {:ok, blueprint} 10 end 11 12 def validate_schema(%Schema.SchemaDefinition{} = schema) do 13 enums = 14 schema.type_definitions 15 |> Enum.filter(&match?(%Schema.EnumTypeDefinition{}, &1)) 16 |> Map.new(&{&1.identifier, &1}) 17 18 schema = Blueprint.prewalk(schema, &validate_defaults(&1, enums)) 19 {:halt, schema} 20 end 21 22 def validate_schema(node), do: node 23 24 def validate_defaults(%{default_value: nil} = node, _) do 25 node 26 end 27 28 def validate_defaults(%{default_value: default_value, type: type} = node, enums) do 29 type = Blueprint.TypeReference.unwrap(type) 30 31 case Map.fetch(enums, type) do 32 {:ok, enum} -> 33 values = Enum.map(enum.values, & &1.value) 34 value_list = Enum.map(values, &"\n * #{inspect(&1)}") 35 36 case value_conforms_to_enum(node.type, default_value, values) do 37 {:error, value} -> 38 detail = %{ 39 value_list: value_list, 40 type: type, 41 default_value: value 42 } 43 44 node |> put_error(error(node, detail)) 45 46 {:ok, _} -> 47 node 48 end 49 50 _ -> 51 node 52 end 53 end 54 55 def validate_defaults(node, _) do 56 node 57 end 58 59 defp value_conforms_to_enum(%Blueprint.TypeReference.List{of_type: of_type}, value, enum_values) 60 when is_list(value) do 61 value 62 |> Enum.map(&value_conforms_to_enum(of_type, &1, enum_values)) 63 |> Enum.find({:ok, value}, &match?({:error, _}, &1)) 64 end 65 66 defp value_conforms_to_enum(%_{of_type: of_type}, value, enum_values) do 67 value_conforms_to_enum(of_type, value, enum_values) 68 end 69 70 defp value_conforms_to_enum(_, value, enum_values) do 71 if value in enum_values do 72 {:ok, value} 73 else 74 {:error, value} 75 end 76 end 77 78 defp error(node, data) do 79 %Absinthe.Phase.Error{ 80 message: explanation(data), 81 locations: [node.__reference__.location], 82 phase: __MODULE__, 83 extra: data 84 } 85 end 86 87 @moduledoc false 88 89 def explanation(%{default_value: default_value, type: type, value_list: value_list}) do 90 """ 91 The default_value for an enum must be present in the enum values. 92 93 Could not use default value of `#{inspect(default_value)}` for #{inspect(type)}. 94 95 Valid values are: 96 #{value_list} 97 """ 98 end 99 end