Skip to content

Commit

Permalink
Merge pull request #3 from CargoSense/resolution-inside-execution
Browse files Browse the repository at this point in the history
Cleanup Resolution function signatures
  • Loading branch information
bruce committed Dec 17, 2015
2 parents 0a9bc61 + 50f0c5a commit c2f7f32
Show file tree
Hide file tree
Showing 22 changed files with 214 additions and 216 deletions.
8 changes: 4 additions & 4 deletions lib/ex_graphql/adapter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ defmodule ExGraphQL.Adapter do
end

# Rename a AST node and traverse children
defp load_ast_node(%{__struct__: Language.OperationDefinition, name: name, selection_set: selection_set} = node) do
defp load_ast_node(%Language.OperationDefinition{name: name, selection_set: selection_set} = node) do
%{node | name: name |> to_internal_name(:operation), selection_set: load_ast_node(selection_set)}
end
defp load_ast_node(%{__struct__: Language.SelectionSet, selections: selections} = node) do
defp load_ast_node(%Language.SelectionSet{selections: selections} = node) do
%{node | selections: selections |> Enum.map(&load_ast_node/1)}
end
defp load_ast_node(%{__struct__: Language.Field, arguments: args, name: name, selection_set: selection_set} = node) do
defp load_ast_node(%Language.Field{arguments: args, name: name, selection_set: selection_set} = node) do
%{node | name: name |> to_internal_name(:field), selection_set: load_ast_node(selection_set), arguments: args |> Enum.map(&load_ast_node/1)}
end
defp load_ast_node(%{__struct__: Language.Argument, name: name} = node) do
defp load_ast_node(%Language.Argument{name: name} = node) do
%{node | name: name |> to_internal_name(:argument)}
end
defp load_ast_node(nil) do
Expand Down
15 changes: 8 additions & 7 deletions lib/ex_graphql/execution.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ defmodule ExGraphQL.Execution do
@typedoc "The canonical result representation of an execution"
@type result_t :: %{data: %{binary => any}, errors: [error_t]}

@type t :: %{schema: Type.Schema.t, document: Language.Document.t, variables: map, validate: boolean, selected_operation: ExGraphQL.Type.ObjectType.t, operation_name: atom, errors: [error_t], categorized: boolean, strategy: atom, adapter: atom}
defstruct schema: nil, document: nil, variables: %{}, fragments: %{}, operations: %{}, validate: true, selected_operation: nil, operation_name: nil, errors: [], categorized: false, strategy: nil, adapter: nil
@type t :: %{schema: Type.Schema.t, document: Language.Document.t, variables: map, validate: boolean, selected_operation: ExGraphQL.Type.ObjectType.t, operation_name: atom, errors: [error_t], categorized: boolean, strategy: atom, adapter: atom, resolution: Execution.Resolution.t}
defstruct schema: nil, document: nil, variables: %{}, fragments: %{}, operations: %{}, validate: true, selected_operation: nil, operation_name: nil, errors: [], categorized: false, strategy: nil, adapter: nil, resolution: nil

def run(execution, options \\ []) do
raw = execution |> Map.merge(options |> Enum.into(%{}))
Expand All @@ -28,6 +28,7 @@ defmodule ExGraphQL.Execution do
end
end

@spec prepare(t) :: t
def prepare(execution) do
defined = execution
|> add_configured_adapter
Expand Down Expand Up @@ -76,17 +77,17 @@ defmodule ExGraphQL.Execution do
end

@spec resolve_type(t, t, t) :: t | nil
def resolve_type(target, nil = _child_type, %{__struct__: Type.Union} = parent_type) do
def resolve_type(target, nil = _child_type, %Type.Union{} = parent_type) do
parent_type
|> Type.Union.resolve_type(target)
end
def resolve_type(_target, nil = _child_type, _parent_type) do
nil
end
def resolve_type(_target, %{__struct__: Type.Union} = child_type, parent_type) do
def resolve_type(_target, %Type.Union{} = child_type, parent_type) do
child_type |> Type.Union.member?(parent_type) || nil
end
def resolve_type(target, %{__struct__: Type.InterfaceType} = _child_type, _parent_type) do
def resolve_type(target, %Type.InterfaceType{} = _child_type, _parent_type) do
target
|> Type.InterfaceType.resolve_type
end
Expand Down Expand Up @@ -125,10 +126,10 @@ defmodule ExGraphQL.Execution do
defp categorize_definitions(execution, []) do
execution
end
defp categorize_definitions(%{operations: operations} = execution, [%{__struct__: ExGraphQL.Language.OperationDefinition, name: name} = definition | rest]) do
defp categorize_definitions(%{operations: operations} = execution, [%ExGraphQL.Language.OperationDefinition{name: name} = definition | rest]) do
categorize_definitions(%{execution | operations: operations |> Map.put(name, definition)}, rest)
end
defp categorize_definitions(%{fragments: fragments} = execution, [%{__struct__: ExGraphQL.Language.FragmentDefinition, name: name} = definition | rest]) do
defp categorize_definitions(%{fragments: fragments} = execution, [%ExGraphQL.Language.FragmentDefinition{name: name} = definition | rest]) do
categorize_definitions(%{execution | fragments: fragments |> Map.put(name, definition)}, rest)
end

Expand Down
26 changes: 26 additions & 0 deletions lib/ex_graphql/execution/arguments.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule ExGraphQL.Execution.Arguments do

alias ExGraphQL.Execution.Literal

def build(ast_arguments, schema_arguments, variables) do
schema_arguments
|> Enum.reduce(%{}, fn ({name, definition}, acc) ->
schema_arg_name = name |> to_string
ast_arg = ast_arguments |> Enum.find(&(&1.name == schema_arg_name))
if ast_arg do
ast_value = if ast_arg.value do
Literal.coerce(definition.type, ast_arg.value, variables)
else
nil
end
variable_value = variables[ast_arg.name]
default_value = definition.default_value
acc
|> Map.put(name, ast_value || variable_value || default_value)
else
acc
end
end)
end

end
40 changes: 40 additions & 0 deletions lib/ex_graphql/execution/literal.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
defmodule ExGraphQL.Execution.Literal do

alias ExGraphQL.Type
alias ExGraphQL.Language

def coerce(input_type, input_value, variables) do
input_type
|> Type.unwrap
|> coerce_unwrapped(input_value, variables)
end

defp coerce_unwrapped(%Type.Scalar{} = scalar, %{value: internal_value}, _variables) do
internal_value
|> scalar.parse_value.()
end
defp coerce_unwrapped(definition_type, %Language.Variable{name: name}, variables) do
variable_value = variables |> Map.get(name)
coerce(definition_type, variable_value, variables)
end
defp coerce_unwrapped(%Type.Scalar{} = scalar, bare, _variables) do
bare
|> to_string
|> scalar.parse_value.()
end

defp coerce_unwrapped(%Type.InputObjectType{fields: thunked_schema_fields}, %{fields: input_fields}, variables) do
schema_fields = thunked_schema_fields |> Type.unthunk
input_fields
|> Enum.reduce(%{}, fn (%{name: name, value: input_value}, acc) ->
case schema_fields |> Map.get(name |> String.to_existing_atom) do
nil -> acc
field -> acc |> Map.put(name |> to_string, coerce(field.type, input_value, variables))
end
end)
end
defp coerce_unwrapped(%Type.Enum{values: enum_values}, %{value: raw_value}, _variables) do
enum_values |> Map.get(raw_value)
end

end
61 changes: 0 additions & 61 deletions lib/ex_graphql/execution/literal_input.ex

This file was deleted.

5 changes: 2 additions & 3 deletions lib/ex_graphql/execution/resolution.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ defprotocol ExGraphQL.Execution.Resolution do
@type t :: %{target: any, parent_type: Type.t, type: Type.t, ast_node: Language.t}
defstruct target: nil, parent_type: nil, type: nil, ast_node: nil

@doc "Returns `true` if `data` is considered blank/empty"
@spec resolve(ExGraphQL.Language.t, ExGraphQL.Execution.Resolution.t, ExGraphQL.Execution.t) :: {:ok, any} | {:error, any}
def resolve(ast_node, resolution, execution)
@spec resolve(ExGraphQL.Language.t, ExGraphQL.Execution.t) :: {:ok, any, ExGraphQL.Execution.t} | {:error, any}
def resolve(ast_node, execution)

end
31 changes: 14 additions & 17 deletions lib/ex_graphql/execution/resolution/field.ex
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Language.Field do

alias ExGraphQL.Execution
alias ExGraphQL.Execution.Resolution
alias ExGraphQL.Type

@spec resolve(ExGraphQL.Language.Field.t,
ExGraphQL.Resolution.t,
ExGraphQL.Execution.t) :: {:ok, map} | {:error, any}
def resolve(%{name: name} = ast_node, %{parent_type: parent_type, target: target} = resolution, %{errors: errors, variables: variables, strategy: :serial} = execution) do
def resolve(%{name: name} = ast_node, %{errors: errors, variables: variables, strategy: :serial, resolution: %{parent_type: parent_type, target: target}} = execution) do
field = Type.field(parent_type, ast_node.name)
if field do
arguments = Execution.LiteralInput.arguments(ast_node.arguments, field.args, variables)
arguments = Execution.Arguments.build(ast_node.arguments, field.args, variables)
case field do
%{resolve: nil} ->
target |> Map.get(name |> String.to_atom) |> result(ast_node, field, resolution, execution)
target |> Map.get(name |> String.to_atom) |> result(ast_node, field, execution)
%{resolve: resolver} ->
resolver.(arguments, execution, resolution)
|> process_raw_result(ast_node, field, resolution, execution)
resolver.(arguments, execution)
|> process_raw_result(ast_node, field, execution)
end
else
error_info = %{name: ast_node.name, role: :field, value: "Not present in schema"}
Expand All @@ -24,11 +24,11 @@ defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Language.Field do
end
end

defp process_raw_result({:ok, value}, ast_node, field, resolution, execution) do
defp process_raw_result({:ok, value}, ast_node, field, execution) do
value
|> result(ast_node, field, resolution, execution)
|> result(ast_node, field, execution)
end
defp process_raw_result({:error, error}, ast_node, _field, _resolution, execution) do
defp process_raw_result({:error, error}, ast_node, _field, execution) do
new_errors = error
|> List.wrap
|> Enum.map(fn (value) ->
Expand All @@ -37,7 +37,7 @@ defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Language.Field do
end)
{:skip, %{execution | errors: new_errors ++ execution.errors }}
end
defp process_raw_result(_other, ast_node, _field, _resolution, execution) do
defp process_raw_result(_other, ast_node, _field, execution) do
error_info = %{
name: ast_node.name,
role: :field,
Expand All @@ -47,16 +47,13 @@ defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Language.Field do
{:skip, %{execution | errors: [error|execution.errors]}}
end

defp result(nil, _ast_node, _field, _resolution, execution) do
defp result(nil, _ast_node, _field, execution) do
{:ok, nil, execution}
end
defp result(value, ast_node, field, _resolution, execution) do
defp result(value, ast_node, field, execution) do
resolved_type = Type.resolve_type(field.type, value)
Execution.Resolution.resolve(
resolved_type,
%Execution.Resolution{type: resolved_type, ast_node: ast_node, target: value},
execution
)
next_resolution = %Resolution{type: resolved_type, ast_node: ast_node, target: value}
Resolution.resolve(resolved_type, %{execution | resolution: next_resolution})
end

end
6 changes: 3 additions & 3 deletions lib/ex_graphql/execution/resolution/list.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Type.List do

alias ExGraphQL.Execution.Resolution

def resolve(%{of_type: wrapped_type}, %{ast_node: %{selection_set: selection_set}, target: target}, execution) do
def resolve(%{of_type: wrapped_type}, %{resolution: %{ast_node: %{selection_set: selection_set}, target: target}} = execution) do
%{values: values_to_return, execution: execution_to_return} = target
|> Enum.reduce(%{values: [], execution: execution}, fn (value_to_resolve, %{values: values_before, execution: current_execution}) ->
this_resolution = %Resolution{type: wrapped_type, target: value_to_resolve}
{:ok, result, next_execution} = Resolution.resolve(
selection_set,
%Resolution{type: wrapped_type, target: value_to_resolve},
current_execution
%{current_execution | resolution: this_resolution}
)
%{values: [result|values_before], execution: next_execution}
end)
Expand Down
6 changes: 3 additions & 3 deletions lib/ex_graphql/execution/resolution/object_type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Type.ObjectType do

alias ExGraphQL.Execution.Resolution

def resolve(object_type, %{ast_node: %{selection_set: selection_set}, target: target}, execution) do
def resolve(object_type, %{resolution: %{ast_node: %{selection_set: selection_set}, target: target}} = execution) do
deeper_resolution = %Resolution{type: object_type, target: target}
Resolution.resolve(
selection_set,
%Resolution{type: object_type, target: target},
execution
%{execution | resolution: deeper_resolution}
)
end

Expand Down
6 changes: 3 additions & 3 deletions lib/ex_graphql/execution/resolution/operation_definition.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Language.OperationDefinit

alias ExGraphQL.Execution.Resolution

def resolve(operation, resolution, execution) do
def resolve(operation, %{resolution: %{target: target}} = execution) do
deeper_resolution = %Resolution{type: target}
Resolution.resolve(
operation.selection_set,
%Resolution{type: resolution.target},
execution
%{execution | resolution: deeper_resolution}
)
end

Expand Down
2 changes: 1 addition & 1 deletion lib/ex_graphql/execution/resolution/scalar.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
defimpl ExGraphQL.Execution.Resolution, for: ExGraphQL.Type.Scalar do

def resolve(%{parse_value: parse_value}, %{target: target}, execution) do
def resolve(%{parse_value: parse_value}, %{resolution: %{target: target}} = execution) do
{:ok, parse_value.(target), execution}
end

Expand Down
Loading

0 comments on commit c2f7f32

Please sign in to comment.