Packages
absinthe
1.1.1
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
Current section
Files
Jump to
Current section
Files
lib/absinthe/execution/resolution/field.ex
defimpl Absinthe.Execution.Resolution, for: Absinthe.Language.Field do
alias Absinthe.Execution
alias Absinthe.Execution.Resolution
alias Absinthe.Type
alias Absinthe.Flag
alias Absinthe.Language
alias Absinthe.Introspection
@spec resolve(Absinthe.Language.Field.t,
Absinthe.Execution.t) :: {:ok, map} | {:error, any}
def resolve(%{name: name} = ast_node, %{strategy: :serial, resolution: %{parent_type: parent_type, target: target}, schema: schema} = execution) do
field = find_field(ast_node, execution)
case {field, schema.__absinthe_custom_default_resolve__} do
{%{resolve: nil}, nil} ->
# No custom default resolve function, we can skip arguments
case target do
%{} ->
{:ok, Map.get(target, name |> String.to_existing_atom)}
_ ->
{:ok, nil}
end
|> process_raw_result(ast_node, field, execution)
{%{}, _} ->
case Execution.Arguments.build(ast_node, field.args, execution) do
{:ok, args, exe} ->
Type.Field.resolve(field, args, field_info(field, ast_node, execution))
|> process_raw_result(ast_node, field, exe)
{:error, missing, invalid, exe} ->
exe
|> skip_as(:missing, missing, name, ast_node)
|> skip_as(:invalid, invalid, name, ast_node)
|> Flag.as(:skip)
end
{nil, _} ->
if Introspection.type?(parent_type) do
{:skip, execution}
else
execution
|> Execution.put_error(:field, ast_node.name, "Not present in schema", at: ast_node)
|> Flag.as(:skip)
end
end
end
# Find the current field, keeping in mind rules for abstract types
@spec find_field(Language.Field.t, Execution.t) :: Type.t | nil
defp find_field(%{name: "__" <> _} = ast_node, execution) do
Type.field(execution.resolution.parent_type, ast_node.name)
end
defp find_field(ast_node, %{resolution: %{target: target, parent_type: parent_type}} = execution) do
case parent_type do
%Type.Interface{} ->
if Type.field(parent_type, ast_node.name) do
concrete = Execution.concrete_type(parent_type, target, execution)
Type.field(concrete, ast_node.name)
end
%Type.Union{} ->
nil
_ ->
Type.field(parent_type, ast_node.name)
end
end
# Build a `Absinthe.Execution.Field` struct containing the resolution environment
# of the field
@spec field_info(Type.Field.t, Language.t, Execution.t) :: Execution.Field.t
defp field_info(field, ast_node, execution) do
%Execution.Field{
adapter: execution.adapter,
ast_node: ast_node,
context: execution.context,
definition: field,
parent_type: execution.resolution.parent_type,
root_value: execution.root_value,
schema: execution.schema,
source: execution.resolution.target
}
end
def skip_as(execution, _reason, [], _name, _ast_node) do
execution
end
def skip_as(execution, reason, collected, name, ast_node) do
execution
|> Execution.put_error(:field, name, describe(collected, reason), at: ast_node)
end
@reasons %{missing: %{prefix: "required argument", suffix: "not provided"},
invalid: %{prefix: "badly formed argument", suffix: "provided"}}
# Generate a detailed error message for a list of missing arguments
@spec describe([binary], atom) :: binary
defp describe(collected, reason) do
{msg, listing} = do_describe(collected, reason)
msg <> " (" <> listing <> ") " <> @reasons[reason].suffix
end
# Determine the error message parts
@spec do_describe([binary], :atom) :: {binary, binary}
defp do_describe(collected, reason) do
quote_it = &"`#{&1}'"
prefix = @reasons[reason].prefix
case collected do
[item] -> {"1 #{prefix}", quote_it.(item)}
_ -> {"#{length(collected)} #{prefix}s", collected |> Enum.map(quote_it) |> Enum.join(", ")}
end
end
defp process_raw_result({:ok, value}, ast_node, field, execution) do
exe_with_deprecation = add_field_deprecation(execution, field, ast_node)
value
|> result(ast_node, field, exe_with_deprecation)
end
defp process_raw_result({:error, errors}, ast_node, field, execution) do
errors
|> List.wrap
|> Enum.reduce(execution, fn
value, exe -> Execution.put_error(exe, :field, ast_node.name, value, at: ast_node)
end)
|> add_field_deprecation(field, ast_node)
|> Flag.as(:skip)
end
defp process_raw_result(_other, ast_node, field, execution) do
execution
|> add_field_deprecation(field, ast_node)
|> Execution.put_error(:field, ast_node.name, "Did not resolve to match {:ok, _} or {:error, _}", at: ast_node)
|> Flag.as(:skip)
end
defp add_field_deprecation(execution, %{deprecation: nil}, _ast_node) do
execution
end
defp add_field_deprecation(execution, %{name: name, deprecation: %{reason: reason}}, ast_node) do
details = if reason, do: "; #{reason}", else: ""
execution
|> Execution.put_error(:field, name, "Deprecated" <> details, at: ast_node)
end
defp result(nil, _ast_node, _field, execution) do
{:ok, nil, execution}
end
defp result(value, ast_node, field, execution) do
resolved_type = Type.resolve_type(field.type, value)
next_resolution = %Resolution{type: resolved_type, ast_node: ast_node, target: value}
Resolution.resolve(resolved_type, %{execution | resolution: next_resolution})
end
end