class GraphQL::Schema::Subscription

This class can be extended to create fields on your subscription root.

It provides hooks for the different parts of the subscription lifecycle:

Also, `#unsubscribe` terminates the subscription.

Constants

NO_UPDATE
READING_SCOPE

Public Class Methods

field_options() click to toggle source

Overriding Resolver#field_options to include subscription_scope

# File lib/graphql/schema/subscription.rb, line 148
def self.field_options
  super.merge(
    subscription_scope: subscription_scope
  )
end
new(object:, context:, field:) click to toggle source
Calls superclass method GraphQL::Schema::Resolver::new
# File lib/graphql/schema/subscription.rb, line 22
def initialize(object:, context:, field:)
  super
  # Figure out whether this is an update or an initial subscription
  @mode = context.query.subscription_update? ? :update : :subscribe
end
subscription_scope(new_scope = READING_SCOPE, optional: false) click to toggle source

Call this method to provide a new subscription_scope; OR call it without an argument to get the subscription_scope @param new_scope [Symbol] @param optional [Boolean] If true, then don't require `scope:` to be provided to updates to this subscription. @return [Symbol]

# File lib/graphql/schema/subscription.rb, line 108
def self.subscription_scope(new_scope = READING_SCOPE, optional: false)
  if new_scope != READING_SCOPE
    @subscription_scope = new_scope
    @subscription_scope_optional = optional
  elsif defined?(@subscription_scope)
    @subscription_scope
  else
    find_inherited_value(:subscription_scope)
  end
end
subscription_scope_optional?() click to toggle source
# File lib/graphql/schema/subscription.rb, line 119
def self.subscription_scope_optional?
  if defined?(@subscription_scope_optional)
    @subscription_scope_optional
  else
    find_inherited_value(:subscription_scope_optional, false)
  end
end
topic_for(arguments:, field:, scope:) click to toggle source

This is called during initial subscription to get a “name” for this subscription. Later, when `.trigger` is called, this will be called again to build another “name”. Any subscribers with matching topic will begin the update flow.

The default implementation creates a string using the field name, subscription scope, and argument keys and values. In that implementation, only `.trigger` calls with _exact matches_ result in updates to subscribers.

To implement a filtered stream-type subscription flow, override this method to return a string with field name and subscription scope. Then, implement {#update} to compare its arguments to the current `object` and return {NO_UPDATE} when an update should be filtered out.

@see {#update} for how to skip updates when an event comes with a matching topic. @param arguments [Hash<String => Object>] The arguments for this topic, in GraphQL-style (camelized strings) @param field [GraphQL::Schema::Field] @param scope [Object, nil] A value corresponding to `.trigger(… scope:)` (for updates) or the `subscription_scope` found in `context` (for initial subscriptions). @return [String] An identifier corresponding to a stream of updates

# File lib/graphql/schema/subscription.rb, line 143
def self.topic_for(arguments:, field:, scope:)
  Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments])
end

Public Instance Methods

load_application_object_failed(err) click to toggle source

If an argument is flagged with `loads:` and no object is found for it, remove this subscription (assuming that the object was deleted in the meantime, or that it became inaccessible).

Calls superclass method
# File lib/graphql/schema/subscription.rb, line 89
def load_application_object_failed(err)
  if @mode == :update
    unsubscribe
  end
  super
end
resolve(**args) click to toggle source

Implement the {Resolve} API

# File lib/graphql/schema/subscription.rb, line 45
def resolve(**args)
  # Dispatch based on `@mode`, which will raise a `NoMethodError` if we ever
  # have an unexpected `@mode`
  public_send("resolve_#{@mode}", **args)
end
resolve_subscribe(**args) click to toggle source

Wrap the user-defined `#subscribe` hook

# File lib/graphql/schema/subscription.rb, line 52
def resolve_subscribe(**args)
  ret_val = args.any? ? subscribe(**args) : subscribe
  if ret_val == :no_response
    context.skip
  else
    ret_val
  end
end
resolve_update(**args) click to toggle source

Wrap the user-provided `#update` hook

# File lib/graphql/schema/subscription.rb, line 69
def resolve_update(**args)
  ret_val = args.any? ? update(**args) : update
  if ret_val == NO_UPDATE
    context.namespace(:subscriptions)[:no_update] = true
    context.skip
  else
    ret_val
  end
end
resolve_with_support(**args) click to toggle source
# File lib/graphql/schema/subscription.rb, line 28
def resolve_with_support(**args)
  result = nil
  unsubscribed = true
  catch :graphql_subscription_unsubscribed do
    result = super
    unsubscribed = false
  end


  if unsubscribed
    context.skip
  else
    result
  end
end
subscribe(args = {}) click to toggle source

The default implementation returns nothing on subscribe. Override it to return an object or `:no_response` to (explicitly) return nothing.

# File lib/graphql/schema/subscription.rb, line 64
def subscribe(args = {})
  :no_response
end
unsubscribe() click to toggle source

Call this to halt execution and remove this subscription from the system

# File lib/graphql/schema/subscription.rb, line 97
def unsubscribe
  context.namespace(:subscriptions)[:unsubscribed] = true
  throw :graphql_subscription_unsubscribed
end
update(args = {}) click to toggle source

The default implementation returns the root object. Override it to return {NO_UPDATE} if you want to skip updates sometimes. Or override it to return a different object.

# File lib/graphql/schema/subscription.rb, line 82
def update(args = {})
  object
end