Current section
Files
Jump to
Current section
Files
lib/graphql_ops.ex
defmodule Grapix.GraphqlOps do
@moduledoc """
Utilities for manipulating GraphQL documents.
"""
alias Grapix.QuerySpec
alias Absinthe.{Pipeline, Phase}
require Logger
@default_opts [vars: %{}, context: %{}]
@doc """
Execute an executable GraphQL document against the specified schema. As a convenience,
atom keys in the vars map are morphified into string keys.
"""
@spec execute(Grapix.QuerySpec.t(), [keyword()]) :: {:ok | :error, any}
def execute(
%QuerySpec{doc: doc, op_name: op_name, selection: selection, schema: schema},
opts \\ []
) do
%{vars: vars, context: context} = Keyword.merge(@default_opts, opts) |> Enum.into(%{})
# Logger.warn "[graphql_ops/execute] #{inspect(%{doc: doc, op_name: op_name, selection: sel})}"
Absinthe.run(doc, schema,
operation_name: op_name,
variables: Morphix.stringmorphify!(vars),
context: context
)
|> extract_result(selection)
end
# Absinthe runner doesn't signal parsing errors at the top-level status
defp extract_result({:ok, %{errors: errors}}, selection) do
Logger.error("[graphql_ops/extract_result '#{selection}'] #{inspect(errors, pretty: true)} ")
{:error, errors}
end
defp extract_result({:ok, gql_result}, selection) do
# Logger.warn "[graphql_ops/extract_result '#{selection}'] #{inspect(gql_result, pretty: true)} "
{:ok, get_in(gql_result, [:data, selection])}
end
@doc """
Validates an executable GraphQL document against the specified schema. Validation
includes verifying the presence and types of input variables.
"""
@spec validate_query_spec(Grapix.QuerySpec.t(), %{}) :: {:ok | :error, any}
def validate_query_spec(%QuerySpec{doc: doc, op_name: op_name, schema: schema}, vars \\ %{}) do
options = [operation_name: op_name, variables: vars]
pipeline =
schema
|> Pipeline.for_document(options)
# |> IO.inspect(label: "[graphql_ops/validate_query_spec pipeline]", pretty: true)
|> Pipeline.without(Phase.Subscription.SubscribeSelf)
|> Pipeline.without(Phase.Document.Execution.Resolution)
|> Pipeline.insert_before(Phase.Document.Result, Grapix.AbsintheFakeResult)
# |> IO.inspect(label: "[graphql_ops/validate_query_spec pipeline]", pretty: true)
case Pipeline.run(doc, pipeline) do
{:ok, %{execution: %{validation_errors: []}}, _} -> {:ok, []}
{:ok, %{execution: %{validation_errors: validation_errors}}, _} -> {:error, validation_errors}
other -> {:error, other}
end
end
end
# TODO: Excise this when Absinthe 1.5 ships.
defmodule Grapix.AbsintheFakeResult do
def run(blueprint, _) do
blueprint = put_in(blueprint.execution.result, %{value: nil})
{:ok, blueprint}
end
end