zf

zenflows testing
git clone https://s.sonu.ch/~srfsh/zf.git
Log | Files | Refs | Submodules | README | LICENSE

apply_declaration.ex (3663B)


      1 defmodule Absinthe.Phase.Schema.ApplyDeclaration do
      2   @moduledoc false
      3 
      4   use Absinthe.Phase
      5   alias Absinthe.Blueprint
      6 
      7   @type operation :: :query | :mutation | :subscription
      8 
      9   @type root_mappings :: %{operation() => Blueprint.TypeReference.Name.t()}
     10 
     11   def run(blueprint, _opts) do
     12     blueprint = process(blueprint)
     13     {:ok, blueprint}
     14   end
     15 
     16   # Apply schema declaration to each schema definition
     17   @spec process(blueprint :: Blueprint.t()) :: Blueprint.t()
     18   defp process(blueprint = %Blueprint{}) do
     19     %{
     20       blueprint
     21       | schema_definitions: Enum.map(blueprint.schema_definitions, &process_schema_definition/1)
     22     }
     23   end
     24 
     25   # Strip the schema declaration out of the schema's type definitions and apply it
     26   @spec process_schema_definition(schema_definition :: Blueprint.Schema.SchemaDefinition.t()) ::
     27           Blueprint.Schema.SchemaDefinition.t()
     28   defp process_schema_definition(schema_definition) do
     29     {declarations, type_defs} =
     30       Enum.split_with(
     31         schema_definition.type_definitions,
     32         &match?(%Blueprint.Schema.SchemaDeclaration{}, &1)
     33       )
     34 
     35     # Remove declaration
     36     schema_definition = %{schema_definition | type_definitions: type_defs}
     37 
     38     case declarations do
     39       [declaration] ->
     40         root_mappings =
     41           declaration
     42           |> extract_root_mappings
     43 
     44         %{
     45           schema_definition
     46           | type_definitions:
     47               Enum.map(schema_definition.type_definitions, &maybe_mark_root(&1, root_mappings)),
     48             schema_declaration: declaration
     49         }
     50 
     51       [] ->
     52         schema_definition
     53 
     54       [_first | extra_declarations] ->
     55         extra_declarations
     56         |> Enum.reduce(schema_definition, fn declaration, acc ->
     57           acc
     58           |> put_error(error(declaration))
     59         end)
     60     end
     61   end
     62 
     63   # Generate an error for extraneous schema declarations
     64   @spec error(declaration :: Blueprint.Schema.SchemaDeclaration.t()) :: Absinthe.Phase.Error.t()
     65   defp error(declaration) do
     66     %Absinthe.Phase.Error{
     67       message:
     68         "More than one schema declaration found. Only one instance of `schema' should be present in SDL.",
     69       locations: [declaration.__reference__.location],
     70       phase: __MODULE__
     71     }
     72   end
     73 
     74   # Extract the declared root type names
     75   @spec extract_root_mappings(declaration :: Blueprint.Schema.SchemaDeclaration.t()) ::
     76           root_mappings()
     77   defp extract_root_mappings(declaration) do
     78     for field_def <- declaration.field_definitions,
     79         field_def.identifier in ~w(query mutation subscription)a,
     80         into: %{} do
     81       {field_def.identifier, field_def.type}
     82     end
     83   end
     84 
     85   # If the type definition is declared as a root type, set the identifier appropriately
     86   @spec maybe_mark_root(type_def :: Blueprint.Schema.t(), root_mappings :: root_mappings()) ::
     87           Blueprint.Schema.t()
     88   defp maybe_mark_root(%Blueprint.Schema.ObjectTypeDefinition{} = type_def, root_mappings) do
     89     case operation_root_identifier(type_def, root_mappings) do
     90       nil ->
     91         type_def
     92 
     93       identifier ->
     94         %{type_def | identifier: identifier}
     95     end
     96   end
     97 
     98   defp maybe_mark_root(type_def, _root_mappings), do: type_def
     99 
    100   # Determine which, if any, root identifier should be applied to an object type definition
    101   @spec operation_root_identifier(
    102           type_def :: Blueprint.Schema.ObjectTypeDefinition.t(),
    103           root_mappings :: root_mappings()
    104         ) :: nil | operation()
    105   defp operation_root_identifier(type_def, root_mappings) do
    106     match_name = type_def.name
    107 
    108     Enum.find_value(root_mappings, fn
    109       {ident, %{name: ^match_name}} ->
    110         ident
    111 
    112       _ ->
    113         false
    114     end)
    115   end
    116 end