diff --git a/lib/graphql/execution/execute.rb b/lib/graphql/execution/execute.rb index e75e366aa4..029101117d 100644 --- a/lib/graphql/execution/execute.rb +++ b/lib/graphql/execution/execute.rb @@ -4,7 +4,10 @@ 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( @@ -25,14 +28,8 @@ def execute(ast_operation, root_type, query) def resolve_selection(object, current_type, selection, query_ctx, mutation: false, subscription_update: false) selection_result = SelectionResult.new - query = query_ctx.query selection.typed_children[current_type].each do |name, subselection| - # Can't `break` because technically multiple fields could match - if subscription_update && query.subscription_key != subselection.subscription_key - next - end - field_result = resolve_field( selection_result, subselection, @@ -42,6 +39,10 @@ def resolve_selection(object, current_type, selection, query_ctx, mutation: fals query_ctx ) + if field_result == SKIP + next + end + if mutation GraphQL::Execution::Lazy.resolve(field_result) end @@ -145,6 +146,8 @@ def resolve_value(owner, parent_type, field_defn, field_type, value, selection, else nil end + elsif value == SKIP + value else case field_type.kind when GraphQL::TypeKinds::SCALAR diff --git a/lib/graphql/query/context.rb b/lib/graphql/query/context.rb index a037c2a361..d27d1ee6ce 100644 --- a/lib/graphql/query/context.rb +++ b/lib/graphql/query/context.rb @@ -71,6 +71,12 @@ def spawn(key:, selection:, parent_type:, field:) ) end + # Return this value to tell the runtime + # to exclude this field from the response altogether + def skip + GraphQL::Execution::Execute::SKIP + end + class FieldResolutionContext extend Forwardable @@ -87,7 +93,8 @@ def initialize(context:, path:, selection:, field:, parent_type:) def_delegators :@context, :[], :[]=, :to_h, :key?, :fetch, :spawn, :query, :schema, - :warden, :errors, :execution_strategy, :strategy + :warden, :errors, :execution_strategy, :strategy, + :skip # @return [GraphQL::Language::Nodes::Field] The AST node for the currently-executing field def ast_node diff --git a/lib/graphql/subscriptions/instrumentation.rb b/lib/graphql/subscriptions/instrumentation.rb index 1d438f177d..c4710a79c9 100644 --- a/lib/graphql/subscriptions/instrumentation.rb +++ b/lib/graphql/subscriptions/instrumentation.rb @@ -58,10 +58,8 @@ def call(obj, args, ctx) # The root object is _already_ the subscription update: obj else - # It should only: - # - Register the selection (first condition) - # - Pass `obj` to the child selection (second condition) - raise "An unselected subscription field should never be called" + # This is a subscription update, but this event wasn't triggered. + ctx.skip end end end