field_imports.ex (1620B)
1 defmodule Absinthe.Phase.Schema.FieldImports do 2 @moduledoc false 3 4 use Absinthe.Phase 5 alias Absinthe.Blueprint 6 alias Absinthe.Blueprint.Schema 7 8 def run(blueprint, _opts) do 9 blueprint = Blueprint.prewalk(blueprint, &handle_imports/1) 10 {:ok, blueprint} 11 end 12 13 def handle_imports(%Schema.SchemaDefinition{} = schema) do 14 # Per Phase.Schema.ValidateTypeReferences, the types are already 15 # in the order they need to be in to accumulate imports properly. 16 types = 17 Enum.reduce(schema.type_definitions, %{}, fn type, types -> 18 Map.put(types, type.identifier, import_fields(type, types)) 19 end) 20 21 types = Enum.map(schema.type_definitions, &Map.fetch!(types, &1.identifier)) 22 {:halt, %{schema | type_definitions: types}} 23 end 24 25 def handle_imports(node), do: node 26 27 @can_import [ 28 Schema.ObjectTypeDefinition, 29 Schema.InputObjectTypeDefinition, 30 Schema.InterfaceTypeDefinition 31 ] 32 @exclude_fields [ 33 :__typename 34 ] 35 def import_fields(%def_type{} = type, types) when def_type in @can_import do 36 Enum.reduce(type.imports, type, fn {source, opts}, type -> 37 source_type = Map.fetch!(types, source) 38 39 rejections = Keyword.get(opts, :except, []) ++ @exclude_fields 40 41 fields = source_type.fields |> Enum.reject(&(&1.identifier in rejections)) 42 43 fields = 44 case Keyword.fetch(opts, :only) do 45 {:ok, selections} -> 46 Enum.filter(fields, &(&1.identifier in selections)) 47 48 _ -> 49 fields 50 end 51 52 %{type | fields: fields ++ type.fields} 53 end) 54 end 55 56 def import_fields(type, _), do: type 57 end