zf

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

query.ex (5397B)


      1 defmodule Absinthe.Plug.Request.Query do
      2   @moduledoc false
      3 
      4   # A struct containing, among a bunch of config params,
      5   # the raw GraphQL document and variables that make up the meat
      6   # of a GraphQL request. A GraphQL request can contain multiple Queries.
      7   # Queries are fed through a DocumentProvider, and then passed into
      8   # the pipeline(s) for processing.
      9 
     10   @enforce_keys [
     11     :document,
     12     :operation_name,
     13     :root_value,
     14     :variables,
     15     :raw_options,
     16     :params
     17   ]
     18 
     19   defstruct [
     20     :document,
     21     :operation_name,
     22     :root_value,
     23     :variables,
     24     :raw_options,
     25     :params,
     26     :adapter,
     27     :context,
     28     :schema,
     29     document_provider_key: nil,
     30     pipeline: [],
     31     document_provider: nil
     32   ]
     33 
     34   @type t :: %__MODULE__{
     35           operation_name: nil | String.t(),
     36           root_value: any,
     37           variables: map,
     38           raw_options: Keyword.t(),
     39           document: nil | String.t() | Absinthe.Blueprint.t(),
     40           document_provider_key: any,
     41           pipeline: Absinthe.Pipeline.t(),
     42           document_provider: nil | Absinthe.Plug.DocumentProvider.t(),
     43           params: map,
     44           adapter: Absinthe.Adapter.t(),
     45           context: map,
     46           schema: Absinthe.Schema.t()
     47         }
     48 
     49   def parse(body, params, config) do
     50     # either from
     51     with raw_document <- extract_raw_document(body, params),
     52          {:ok, variables} <- extract_variables(params, config),
     53          operation_name <- extract_operation_name(params) do
     54       %__MODULE__{
     55         document: raw_document,
     56         operation_name: operation_name,
     57         raw_options: config.raw_options,
     58         variables: variables,
     59         context: config.context,
     60         adapter: config.adapter,
     61         root_value: config.root_value,
     62         schema: config.schema_mod,
     63         params: params
     64       }
     65       |> provide_document(config)
     66     end
     67   end
     68 
     69   def add_pipeline(query, conn_info, config) do
     70     config = Map.merge(config, conn_info)
     71     opts = query |> to_pipeline_opts
     72 
     73     {module, fun} = config.pipeline
     74     pipeline = apply(module, fun, [config, opts])
     75 
     76     pipeline =
     77       %{query | pipeline: pipeline}
     78       |> Absinthe.Plug.DocumentProvider.pipeline()
     79 
     80     %{query | pipeline: pipeline}
     81   end
     82 
     83   #
     84   # OPERATION NAME
     85   #
     86 
     87   @spec extract_operation_name(map) :: nil | String.t()
     88   defp extract_operation_name(params) do
     89     params["operationName"]
     90     |> decode_operation_name
     91   end
     92 
     93   # GraphQL.js treats an empty operation name as no operation name.
     94   @spec decode_operation_name(nil | String.t()) :: nil | String.t()
     95   defp decode_operation_name(""), do: nil
     96   defp decode_operation_name(name), do: name
     97 
     98   #
     99   # VARIABLES
    100   #
    101 
    102   @spec extract_variables(map, map) :: {:ok, map} | {:input_error, String.t()}
    103   defp extract_variables(params, %{json_codec: json_codec}) do
    104     Map.get(params, "variables", "{}")
    105     |> decode_variables(json_codec)
    106   end
    107 
    108   defp extract_variables(_, _) do
    109     {:error, "No json_codec available"}
    110   end
    111 
    112   @spec decode_variables(any, map) :: {:ok, map} | {:input_error, String.t()}
    113   defp decode_variables(%{} = variables, _), do: {:ok, variables}
    114   defp decode_variables("", _), do: {:ok, %{}}
    115   defp decode_variables("null", _), do: {:ok, %{}}
    116   defp decode_variables(nil, _), do: {:ok, %{}}
    117 
    118   defp decode_variables(variables, codec) when is_binary(variables) do
    119     case codec.module.decode(variables) do
    120       {:ok, results} ->
    121         {:ok, results}
    122 
    123       _ ->
    124         {:input_error, "The variable values could not be decoded"}
    125     end
    126   end
    127 
    128   defp decode_variables(_variables, _),
    129     do: {:input_error, "Variables must be a map."}
    130 
    131   #
    132   # DOCUMENT
    133   #
    134 
    135   @spec extract_raw_document(nil | String.t(), map) :: nil | String.t()
    136   defp extract_raw_document(body, params) do
    137     Map.get(params, "query", body)
    138     |> normalize_raw_document
    139   end
    140 
    141   @spec normalize_raw_document(nil | String.t()) :: nil | String.t()
    142   defp normalize_raw_document(""), do: nil
    143   defp normalize_raw_document(doc), do: doc
    144 
    145   #
    146   # DOCUMENT PROVIDERS
    147   #
    148 
    149   @spec calculate_document_providers(map) :: [Absinthe.Plug.DocumentProvider.t(), ...]
    150   defp calculate_document_providers(%{document_providers: {module, fun}} = config)
    151        when is_atom(fun) do
    152     apply(module, fun, [config])
    153   end
    154 
    155   defp calculate_document_providers(%{document_providers: simple_value}) do
    156     List.wrap(simple_value)
    157   end
    158 
    159   @spec ensure_document_providers!([] | providers) :: providers | no_return
    160         when providers: [Absinthe.Plug.DocumentProvider.t(), ...]
    161   defp ensure_document_providers!([]) do
    162     raise "No document providers found to process request"
    163   end
    164 
    165   defp ensure_document_providers!(providers) do
    166     providers
    167   end
    168 
    169   @spec provide_document(t, map) :: t
    170   defp provide_document(query, config) do
    171     calculate_document_providers(config)
    172     |> ensure_document_providers!()
    173     |> Absinthe.Plug.DocumentProvider.process(query)
    174   end
    175 
    176   @spec to_pipeline_opts(t) :: Keyword.t()
    177   def to_pipeline_opts(query) do
    178     {with_raw_options, opts} =
    179       query
    180       |> Map.from_struct()
    181       |> Map.to_list()
    182       |> Keyword.split([:raw_options])
    183 
    184     Keyword.merge(opts, with_raw_options[:raw_options])
    185   end
    186 
    187   #
    188   # LOGGING
    189   #
    190 
    191   @doc false
    192   @spec log(t, Logger.level()) :: :ok
    193   def log(query, level) do
    194     Absinthe.Logger.log_run(level, {
    195       query.document,
    196       query.schema,
    197       query.pipeline,
    198       to_pipeline_opts(query)
    199     })
    200   end
    201 end