zf

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

blueprint.ex (6251B)


      1 defmodule Absinthe.Blueprint do
      2   @moduledoc """
      3   Represents the graphql document to be executed.
      4 
      5   Please see the code itself for more information on individual blueprint sub
      6   modules.
      7   """
      8 
      9   alias __MODULE__
     10 
     11   defstruct operations: [],
     12             directives: [],
     13             fragments: [],
     14             name: nil,
     15             schema_definitions: [],
     16             schema: nil,
     17             prototype_schema: nil,
     18             adapter: nil,
     19             initial_phases: [],
     20             # Added by phases
     21             telemetry: %{},
     22             flags: %{},
     23             errors: [],
     24             input: nil,
     25             source: nil,
     26             execution: %Blueprint.Execution{},
     27             result: %{}
     28 
     29   @type t :: %__MODULE__{
     30           operations: [Blueprint.Document.Operation.t()],
     31           schema_definitions: [Blueprint.Schema.SchemaDefinition.t()],
     32           directives: [Blueprint.Schema.DirectiveDefinition.t()],
     33           name: nil | String.t(),
     34           fragments: [Blueprint.Document.Fragment.Named.t()],
     35           schema: nil | Absinthe.Schema.t(),
     36           prototype_schema: nil | Absinthe.Schema.t(),
     37           adapter: nil | Absinthe.Adapter.t(),
     38           # Added by phases
     39           telemetry: map,
     40           errors: [Absinthe.Phase.Error.t()],
     41           flags: flags_t,
     42           input: nil | Absinthe.Language.Document.t(),
     43           source: nil | String.t() | Absinthe.Language.Source.t(),
     44           execution: Blueprint.Execution.t(),
     45           result: result_t,
     46           initial_phases: [Absinthe.Phase.t()]
     47         }
     48 
     49   @type result_t :: %{
     50           optional(:data) => term,
     51           optional(:errors) => [term],
     52           optional(:extensions) => term
     53         }
     54 
     55   @type node_t ::
     56           t()
     57           | Blueprint.Directive.t()
     58           | Blueprint.Document.t()
     59           | Blueprint.Schema.t()
     60           | Blueprint.Input.t()
     61           | Blueprint.TypeReference.t()
     62 
     63   @type use_t ::
     64           Blueprint.Document.Fragment.Named.Use.t()
     65           | Blueprint.Input.Variable.Use.t()
     66 
     67   @type flags_t :: %{atom => module}
     68 
     69   defdelegate prewalk(blueprint, fun), to: Absinthe.Blueprint.Transform
     70   defdelegate prewalk(blueprint, acc, fun), to: Absinthe.Blueprint.Transform
     71   defdelegate postwalk(blueprint, fun), to: Absinthe.Blueprint.Transform
     72   defdelegate postwalk(blueprint, acc, fun), to: Absinthe.Blueprint.Transform
     73 
     74   def find(blueprint, fun) do
     75     {_, found} =
     76       Blueprint.prewalk(blueprint, nil, fn
     77         node, nil ->
     78           if fun.(node) do
     79             {node, node}
     80           else
     81             {node, nil}
     82           end
     83 
     84         node, found ->
     85           # Already found
     86           {node, found}
     87       end)
     88 
     89     found
     90   end
     91 
     92   @doc false
     93   # This is largely a debugging tool which replaces `schema_node` struct values
     94   # with just the type identifier, rendering the blueprint tree much easier to read
     95   def __compress__(blueprint) do
     96     prewalk(blueprint, fn
     97       %{schema_node: %{identifier: id}} = node ->
     98         %{node | schema_node: id}
     99 
    100       node ->
    101         node
    102     end)
    103   end
    104 
    105   @spec fragment(t, String.t()) :: nil | Blueprint.Document.Fragment.Named.t()
    106   def fragment(blueprint, name) do
    107     Enum.find(blueprint.fragments, &(&1.name == name))
    108   end
    109 
    110   @doc """
    111   Add a flag to a node.
    112   """
    113   @spec put_flag(node_t, atom, module) :: node_t
    114   def put_flag(node, flag, mod) do
    115     update_in(node.flags, &Map.put(&1, flag, mod))
    116   end
    117 
    118   @doc """
    119   Determine whether a flag has been set on a node.
    120   """
    121   @spec flagged?(node_t, atom) :: boolean
    122   def flagged?(node, flag) do
    123     Map.has_key?(node.flags, flag)
    124   end
    125 
    126   @doc """
    127   Get the currently selected operation.
    128   """
    129   @spec current_operation(t) :: nil | Blueprint.Document.Operation.t()
    130   def current_operation(blueprint) do
    131     Enum.find(blueprint.operations, &(&1.current == true))
    132   end
    133 
    134   @doc """
    135   Update the current operation.
    136   """
    137   @spec update_current(t, (Blueprint.Document.Operation.t() -> Blueprint.Document.Operation.t())) ::
    138           t
    139   def update_current(blueprint, change) do
    140     ops =
    141       Enum.map(blueprint.operations, fn
    142         %{current: true} = op ->
    143           change.(op)
    144 
    145         other ->
    146           other
    147       end)
    148 
    149     %{blueprint | operations: ops}
    150   end
    151 
    152   @doc """
    153   Append the given field or fields to the given type
    154   """
    155   def extend_fields(blueprint = %Blueprint{}, ext_blueprint = %Blueprint{}) do
    156     ext_types = types_by_name(ext_blueprint)
    157 
    158     schema_defs =
    159       for schema_def = %{type_definitions: type_defs} <- blueprint.schema_definitions do
    160         type_defs =
    161           for type_def <- type_defs do
    162             case ext_types[type_def.name] do
    163               nil ->
    164                 type_def
    165 
    166               %{fields: new_fields} ->
    167                 %{type_def | fields: type_def.fields ++ new_fields}
    168             end
    169           end
    170 
    171         %{schema_def | type_definitions: type_defs}
    172       end
    173 
    174     %{blueprint | schema_definitions: schema_defs}
    175   end
    176 
    177   def extend_fields(blueprint, ext_blueprint) when is_atom(ext_blueprint) do
    178     extend_fields(blueprint, ext_blueprint.__absinthe_blueprint__())
    179   end
    180 
    181   def add_field(blueprint = %Blueprint{}, type_def_name, new_field) do
    182     schema_defs =
    183       for schema_def = %{type_definitions: type_defs} <- blueprint.schema_definitions do
    184         type_defs =
    185           for type_def <- type_defs do
    186             if type_def.name == type_def_name do
    187               %{type_def | fields: type_def.fields ++ List.wrap(new_field)}
    188             else
    189               type_def
    190             end
    191           end
    192 
    193         %{schema_def | type_definitions: type_defs}
    194       end
    195 
    196     %{blueprint | schema_definitions: schema_defs}
    197   end
    198 
    199   def find_field(%{fields: fields}, name) do
    200     Enum.find(fields, fn %{name: field_name} -> field_name == name end)
    201   end
    202 
    203   @doc """
    204   Index the types by their name
    205   """
    206   def types_by_name(blueprint = %Blueprint{}) do
    207     for %{type_definitions: type_defs} <- blueprint.schema_definitions,
    208         type_def <- type_defs,
    209         into: %{} do
    210       {type_def.name, type_def}
    211     end
    212   end
    213 
    214   def types_by_name(module) when is_atom(module) do
    215     types_by_name(module.__absinthe_blueprint__())
    216   end
    217 
    218   defimpl Inspect do
    219     defdelegate inspect(term, options),
    220       to: Absinthe.Schema.Notation.SDL.Render
    221   end
    222 end