Packages
absinthe
1.7.5
1.11.0
1.10.2
1.10.1
1.10.0
1.9.1
1.9.0
1.8.0
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.8
1.6.7
retired
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.6.0-rc.1
1.6.0-rc.0
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.5.0-rc.5
1.5.0-rc.4
1.5.0-rc.3
1.5.0-rc.2
1.5.0-rc.1
1.5.0-rc.0
1.5.0-beta.2
1.5.0-beta.1
1.5.0-beta.0
1.5.0-alpha.4
1.5.0-alpha.3
1.5.0-alpha.2
1.5.0-alpha.1
1.5.0-alpha.0
1.4.16
1.4.15
1.4.14
1.4.13
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
retired
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.4.0-rc.3
1.4.0-rc.2
1.4.0-rc.1
1.4.0-rc.0
1.4.0-beta.5
1.4.0-beta.4
1.4.0-beta.3
1.4.0-beta.2
1.4.0-beta.1
1.3.2
1.3.1
1.3.0
1.3.0-rc.0
1.3.0-beta.2
1.3.0-beta.1
1.3.0-beta.0
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.2.0-rc.0
1.2.0-beta.0
1.2.0-alpha0
1.2.0-alpha.2
1.2.0-alpha.1
1.1.11
1.1.10
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.0
0.5.2
0.5.1
0.5.0
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.2.3
0.2.2
0.2.1
0.1.0
GraphQL for Elixir
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/absinthe/phase/document/result.ex
defmodule Absinthe.Phase.Document.Result do
@moduledoc false
# Produces data fit for external encoding from annotated value tree
alias Absinthe.{Blueprint, Phase, Type}
use Absinthe.Phase
@spec run(Blueprint.t() | Phase.Error.t(), Keyword.t()) :: {:ok, map}
def run(%Blueprint{} = bp, options \\ []) do
result = Map.merge(bp.result, process(bp, options))
{:ok, %{bp | result: result}}
end
defp process(blueprint, opts) do
result =
case blueprint.execution do
%{validation_errors: [], result: nil} ->
{:ok, data(%{value: nil}, [])}
%{validation_errors: [], result: result} ->
{:ok, data(result, [])}
%{validation_errors: errors} ->
{:validation_failed, errors}
end
format_result(result, opts)
end
defp format_result({:ok, {data, []}}, _) do
%{data: data}
end
defp format_result({:ok, {data, errors}}, opts) do
errors = errors |> Enum.uniq() |> Enum.map(&format_error(&1, opts))
%{data: data, errors: errors}
end
defp format_result({:validation_failed, errors}, opts) do
errors = errors |> Enum.uniq() |> Enum.map(&format_error(&1, opts))
%{errors: errors}
end
defp data(%{errors: [_ | _] = field_errors}, errors), do: {nil, field_errors ++ errors}
# Leaf
defp data(%{value: nil}, errors), do: {nil, errors}
defp data(%{value: value, emitter: emitter}, errors) do
value =
case Type.unwrap(emitter.schema_node.type) do
%Type.Scalar{} = schema_node ->
try do
Type.Scalar.serialize(schema_node, value)
rescue
_e in [Absinthe.SerializationError, Protocol.UndefinedError] ->
raise(
Absinthe.SerializationError,
"""
Could not serialize term #{inspect(value)} as type #{schema_node.name}
When serializing the field:
#{emitter.parent_type.name}.#{emitter.schema_node.name} (#{emitter.schema_node.__reference__.location.file}:#{emitter.schema_node.__reference__.location.line})
"""
)
end
%Type.Enum{} = schema_node ->
Type.Enum.serialize(schema_node, value)
end
{value, errors}
end
# Object
defp data(%{fields: fields}, errors), do: field_data(fields, errors)
# List
defp data(%{values: values}, errors), do: list_data(values, errors)
defp list_data(fields, errors, acc \\ [])
defp list_data([], errors, acc), do: {:lists.reverse(acc), errors}
defp list_data([%{errors: errs} = field | fields], errors, acc) do
{value, errors} = data(field, errors)
list_data(fields, errs ++ errors, [value | acc])
end
defp field_data(fields, errors, acc \\ [])
defp field_data([], errors, acc), do: {Map.new(acc), errors}
defp field_data([%Absinthe.Resolution{} = res | _], _errors, _acc) do
raise """
Found unresolved resolution struct!
You probably forgot to run the resolution phase again.
#{inspect(res)}
"""
end
defp field_data([field | fields], errors, acc) do
{value, errors} = data(field, errors)
field_data(fields, errors, [{field_name(field.emitter), value} | acc])
end
defp field_name(%{alias: nil, name: name}), do: name
defp field_name(%{alias: name}), do: name
defp field_name(%{name: name}), do: name
defp format_error(%Phase.Error{locations: []} = error, opts) do
error_object = %{message: error.message}
merge_error_extensions(error_object, error.extra, opts)
end
defp format_error(%Phase.Error{} = error, opts) do
error_object = %{
message: error.message,
locations: Enum.flat_map(error.locations, &format_location/1)
}
error_object =
case error.path do
[] -> error_object
path -> Map.put(error_object, :path, path)
end
merge_error_extensions(error_object, error.extra, opts)
end
defp merge_error_extensions(error_object, extra, _opts) when extra == %{} do
error_object
end
defp merge_error_extensions(error_object, extra, opts) do
if opts[:spec_compliant_errors] do
Map.merge(%{extensions: extra}, error_object)
else
Map.merge(extra, error_object)
end
end
defp format_location(%{line: line, column: col}) do
[%{line: line || 0, column: col || 0}]
end
defp format_location(_), do: []
end