lib/graphql/execution/execute.rb in graphql-1.5.15 vs lib/graphql/execution/execute.rb in graphql-1.6.0
- old
+ new
@@ -2,11 +2,14 @@
module GraphQL
module Execution
# A valid execution strategy
# @api private
class Execute
- PROPAGATE_NULL = :__graphql_propagate_null__
+ # @api private
+ SKIP = Object.new
+ # @api private
+ PROPAGATE_NULL = Object.new
def execute(ast_operation, root_type, query)
result = resolve_selection(
query.root_value,
root_type,
@@ -18,202 +21,213 @@
GraphQL::Execution::Lazy.resolve(result)
result.to_h
end
- private
+ # @api private
+ module ExecutionFunctions
+ module_function
- def resolve_selection(object, current_type, selection, query_ctx, mutation: false )
- selection_result = SelectionResult.new
+ def resolve_selection(object, current_type, selection, query_ctx, mutation: false )
+ selection_result = SelectionResult.new
- selection.typed_children[current_type].each do |name, subselection|
- field_result = resolve_field(
- selection_result,
- subselection,
- current_type,
- subselection.definition,
- object,
- query_ctx
- )
+ selection.typed_children[current_type].each do |name, subselection|
+ field_result = resolve_field(
+ selection_result,
+ subselection,
+ current_type,
+ subselection.definition,
+ object,
+ query_ctx
+ )
- if mutation
- GraphQL::Execution::Lazy.resolve(field_result)
- end
+ if field_result == SKIP
+ next
+ end
- selection_result.set(name, field_result)
+ if mutation
+ GraphQL::Execution::Lazy.resolve(field_result)
+ end
- # If the last subselection caused a null to propagate to _this_ selection,
- # then we may as well quit executing fields because they
- # won't be in the response
- if selection_result.invalid_null?
- break
+ selection_result.set(name, field_result)
+
+ # If the last subselection caused a null to propagate to _this_ selection,
+ # then we may as well quit executing fields because they
+ # won't be in the response
+ if selection_result.invalid_null?
+ break
+ end
end
- end
- selection_result
- end
-
- def resolve_field(owner, selection, parent_type, field, object, query_ctx)
- query = query_ctx.query
- field_ctx = query_ctx.spawn(
- parent_type: parent_type,
- field: field,
- key: selection.name,
- selection: selection,
- )
-
- arguments = query.arguments_for(selection, field)
- raw_value = begin
- query_ctx.schema.middleware.invoke([parent_type, object, field, arguments, field_ctx])
- rescue GraphQL::ExecutionError => err
- err
+ selection_result
end
- result = if query.schema.lazy?(raw_value)
- field.prepare_lazy(raw_value, arguments, field_ctx).then { |inner_value|
- continue_resolve_field(owner, selection, parent_type, field, inner_value, field_ctx)
- }
- elsif raw_value.is_a?(GraphQL::Execution::Lazy)
- # It came from a connection resolve, assume it was already instrumented
- raw_value.then { |inner_value|
- continue_resolve_field(owner, selection, parent_type, field, inner_value, field_ctx)
- }
- else
- continue_resolve_field(owner, selection, parent_type, field, raw_value, field_ctx)
- end
-
- case result
- when PROPAGATE_NULL, GraphQL::Execution::Lazy, SelectionResult
- FieldResult.new(
- owner: owner,
- type: field.type,
- value: result,
+ def resolve_field(owner, selection, parent_type, field, object, query_ctx)
+ query = query_ctx.query
+ field_ctx = query_ctx.spawn(
+ parent_type: parent_type,
+ field: field,
+ key: selection.name,
+ selection: selection,
)
- else
- result
- end
- end
- def continue_resolve_field(owner, selection, parent_type, field, raw_value, field_ctx)
- query = field_ctx.query
-
- case raw_value
- when GraphQL::ExecutionError
- raw_value.ast_node = field_ctx.ast_node
- raw_value.path = field_ctx.path
- query.context.errors.push(raw_value)
- when Array
- list_errors = raw_value.each_with_index.select { |value, _| value.is_a?(GraphQL::ExecutionError) }
- if list_errors.any?
- list_errors.each do |error, index|
- error.ast_node = field_ctx.ast_node
- error.path = field_ctx.path + [index]
- query.context.errors.push(error)
- end
+ arguments = query.arguments_for(selection, field)
+ raw_value = begin
+ query_ctx.schema.middleware.invoke([parent_type, object, field, arguments, field_ctx])
+ rescue GraphQL::ExecutionError => err
+ err
end
- end
- resolve_value(
- owner,
- parent_type,
- field,
- field.type,
- raw_value,
- selection,
- field_ctx,
- )
- end
-
- def resolve_value(owner, parent_type, field_defn, field_type, value, selection, field_ctx)
- if value.nil?
- if field_type.kind.non_null?
- type_error = GraphQL::InvalidNullError.new(parent_type, field_defn, value)
- field_ctx.schema.type_error(type_error, field_ctx)
- PROPAGATE_NULL
+ result = if query.schema.lazy?(raw_value)
+ field.prepare_lazy(raw_value, arguments, field_ctx).then { |inner_value|
+ continue_resolve_field(owner, selection, parent_type, field, inner_value, field_ctx)
+ }
+ elsif raw_value.is_a?(GraphQL::Execution::Lazy)
+ # It came from a connection resolve, assume it was already instrumented
+ raw_value.then { |inner_value|
+ continue_resolve_field(owner, selection, parent_type, field, inner_value, field_ctx)
+ }
else
- nil
+ continue_resolve_field(owner, selection, parent_type, field, raw_value, field_ctx)
end
- elsif value.is_a?(GraphQL::ExecutionError)
- if field_type.kind.non_null?
- PROPAGATE_NULL
+
+ case result
+ when PROPAGATE_NULL, GraphQL::Execution::Lazy, SelectionResult
+ FieldResult.new(
+ owner: owner,
+ type: field.type,
+ value: result,
+ )
else
- nil
+ result
end
- else
- case field_type.kind
- when GraphQL::TypeKinds::SCALAR
- field_type.coerce_result(value, field_ctx)
- when GraphQL::TypeKinds::ENUM
- field_type.coerce_result(value, field_ctx)
- when GraphQL::TypeKinds::LIST
- inner_type = field_type.of_type
- i = 0
- result = []
- value.each do |inner_value|
- inner_ctx = field_ctx.spawn(
- key: i,
- selection: selection,
- parent_type: parent_type,
- field: field_defn,
- )
+ end
- inner_result = resolve_value(
- owner,
- parent_type,
- field_defn,
- inner_type,
- inner_value,
- selection,
- inner_ctx,
- )
+ def continue_resolve_field(owner, selection, parent_type, field, raw_value, field_ctx)
+ query = field_ctx.query
- result << GraphQL::Execution::FieldResult.new(type: inner_type, owner: owner, value: inner_result)
- i += 1
+ case raw_value
+ when GraphQL::ExecutionError
+ raw_value.ast_node = field_ctx.ast_node
+ raw_value.path = field_ctx.path
+ query.context.errors.push(raw_value)
+ when Array
+ list_errors = raw_value.each_with_index.select { |value, _| value.is_a?(GraphQL::ExecutionError) }
+ if list_errors.any?
+ list_errors.each do |error, index|
+ error.ast_node = field_ctx.ast_node
+ error.path = field_ctx.path + [index]
+ query.context.errors.push(error)
+ end
end
- result
- when GraphQL::TypeKinds::NON_NULL
- wrapped_type = field_type.of_type
- resolve_value(
- owner,
- parent_type,
- field_defn,
- wrapped_type,
- value,
- selection,
- field_ctx,
- )
- when GraphQL::TypeKinds::OBJECT
- resolve_selection(
- value,
- field_type,
- selection,
- field_ctx
- )
- when GraphQL::TypeKinds::UNION, GraphQL::TypeKinds::INTERFACE
- query = field_ctx.query
- resolved_type = query.resolve_type(value)
- possible_types = query.possible_types(field_type)
+ end
- if !possible_types.include?(resolved_type)
- type_error = GraphQL::UnresolvedTypeError.new(value, field_defn, parent_type, resolved_type, possible_types)
+ resolve_value(
+ owner,
+ parent_type,
+ field,
+ field.type,
+ raw_value,
+ selection,
+ field_ctx,
+ )
+ end
+
+ def resolve_value(owner, parent_type, field_defn, field_type, value, selection, field_ctx)
+ if value.nil?
+ if field_type.kind.non_null?
+ type_error = GraphQL::InvalidNullError.new(parent_type, field_defn, value)
field_ctx.schema.type_error(type_error, field_ctx)
PROPAGATE_NULL
else
+ nil
+ end
+ elsif value.is_a?(GraphQL::ExecutionError)
+ if field_type.kind.non_null?
+ PROPAGATE_NULL
+ else
+ nil
+ end
+ elsif value == SKIP
+ value
+ else
+ case field_type.kind
+ when GraphQL::TypeKinds::SCALAR
+ field_type.coerce_result(value, field_ctx)
+ when GraphQL::TypeKinds::ENUM
+ field_type.coerce_result(value, field_ctx)
+ when GraphQL::TypeKinds::LIST
+ inner_type = field_type.of_type
+ i = 0
+ result = []
+ value.each do |inner_value|
+ inner_ctx = field_ctx.spawn(
+ key: i,
+ selection: selection,
+ parent_type: parent_type,
+ field: field_defn,
+ )
+
+ inner_result = resolve_value(
+ owner,
+ parent_type,
+ field_defn,
+ inner_type,
+ inner_value,
+ selection,
+ inner_ctx,
+ )
+
+ result << GraphQL::Execution::FieldResult.new(type: inner_type, owner: owner, value: inner_result)
+ i += 1
+ end
+ result
+ when GraphQL::TypeKinds::NON_NULL
+ wrapped_type = field_type.of_type
resolve_value(
owner,
parent_type,
field_defn,
- resolved_type,
+ wrapped_type,
value,
selection,
field_ctx,
)
+ when GraphQL::TypeKinds::OBJECT
+ resolve_selection(
+ value,
+ field_type,
+ selection,
+ field_ctx
+ )
+ when GraphQL::TypeKinds::UNION, GraphQL::TypeKinds::INTERFACE
+ query = field_ctx.query
+ resolved_type = query.resolve_type(value)
+ possible_types = query.possible_types(field_type)
+
+ if !possible_types.include?(resolved_type)
+ type_error = GraphQL::UnresolvedTypeError.new(value, field_defn, parent_type, resolved_type, possible_types)
+ field_ctx.schema.type_error(type_error, field_ctx)
+ PROPAGATE_NULL
+ else
+ resolve_value(
+ owner,
+ parent_type,
+ field_defn,
+ resolved_type,
+ value,
+ selection,
+ field_ctx,
+ )
+ end
+ else
+ raise("Unknown type kind: #{field_type.kind}")
end
- else
- raise("Unknown type kind: #{field_type.kind}")
end
end
end
+
+ include ExecutionFunctions
# A `.call`-able suitable to be the last step in a middleware chain
module FieldResolveStep
# Execute the field's resolve method
def self.call(_parent_type, parent_object, field_definition, field_args, context, _next = nil)