class GraphQL::Schema::Subscription
Also, ‘#unsubscribe` terminates the subscription.
- `#update`: called for subsequent update
- `#subscribe`: called for the initial subscription
- `#authorized?`: called before initial subscription and subsequent updates
It provides hooks for the different parts of the subscription lifecycle:
This class can be extended to create fields on your subscription root.
def self.subscription_scope(new_scope = NOT_CONFIGURED, optional: false)
-
(Symbol)
-
Parameters:
-
optional
(Boolean
) -- If true, then don't require `scope:` to be provided to updates to this subscription. -
new_scope
(Symbol
) --
def self.subscription_scope(new_scope = NOT_CONFIGURED, optional: false) if new_scope != NOT_CONFIGURED @subscription_scope = new_scope @subscription_scope_optional = optional elsif defined?(@subscription_scope) @subscription_scope else find_inherited_value(:subscription_scope) end end
def self.subscription_scope_optional?
def self.subscription_scope_optional? if defined?(@subscription_scope_optional) @subscription_scope_optional else find_inherited_value(:subscription_scope_optional, false) end end
def self.topic_for(arguments:, field:, scope:)
-
(String)
- An identifier corresponding to a stream of updates
Parameters:
-
scope
(Object, nil
) -- A value corresponding to `.trigger(... scope:)` (for updates) or the `subscription_scope` found in `context` (for initial subscriptions). -
field
(GraphQL::Schema::Field
) -- -
arguments
(Hash
) -- The arguments for this topic, in GraphQL-style (camelized strings)Object>
Other tags:
- See: {#update} - for how to skip updates when an event comes with a matching topic.
def self.topic_for(arguments:, field:, scope:) Subscriptions::Serialize.dump_recursive([scope, field.graphql_name, arguments]) end
def event
-
(Subscriptions::Event)
- This object is used as a representation of this subscription for the backend
def event @event ||= Subscriptions::Event.new( name: field.name, arguments: @original_arguments, context: context, field: field, ) end
def initialize(object:, context:, field:)
- Api: - private
def initialize(object:, context:, field:) super # Figure out whether this is an update or an initial subscription @mode = context.query.subscription_update? ? :update : :subscribe @subscription_written = false @original_arguments = nil if (subs_ns = context.namespace(:subscriptions)) && (sub_insts = subs_ns[:subscriptions]) sub_insts[context.current_path] = self end end
def load_application_object_failed(err)
remove this subscription (assuming that the object was deleted in the meantime,
If an argument is flagged with `loads:` and no object is found for it,
def load_application_object_failed(err) if @mode == :update unsubscribe end super end
def resolve(**args)
You can implement this if you want code to run for _both_ the initial subscription
Implement the {Resolve} API.
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
def resolve_subscribe(**args)
- Api: - private
def resolve_subscribe(**args) ret_val = !args.empty? ? subscribe(**args) : subscribe if ret_val == :no_response context.skip else ret_val end end
def resolve_update(**args)
- Api: - private
def resolve_update(**args) ret_val = !args.empty? ? update(**args) : update if ret_val == NO_UPDATE context.namespace(:subscriptions)[:no_update] = true context.skip else ret_val end end
def resolve_with_support(**args)
- Api: - private
def resolve_with_support(**args) @original_arguments = args # before `loads:` have been run result = nil unsubscribed = true unsubscribed_result = catch :graphql_subscription_unsubscribed do result = super unsubscribed = false end if unsubscribed if unsubscribed_result context.namespace(:subscriptions)[:final_update] = true unsubscribed_result else context.skip end else result end end
def subscribe(args = {})
Override it to return an object or
The default implementation returns nothing on subscribe.
def subscribe(args = {}) :no_response end
def subscription_written?
-
(Boolean)
- `true` if {#write_subscription} was called already
def subscription_written? @subscription_written end
def unsubscribe(update_value = nil)
-
(void)
-
Parameters:
-
update_value
(Object
) -- if present, deliver this update before unsubscribing
def unsubscribe(update_value = nil) context.namespace(:subscriptions)[:unsubscribed] = true throw :graphql_subscription_unsubscribed, update_value end
def update(args = {})
Override it to return {NO_UPDATE} if you want to
The default implementation returns the root object.
def update(args = {}) object end
def write_subscription
-
(void)
-
def write_subscription if subscription_written? raise GraphQL::Error, "`write_subscription` was called but `#{self.class}#subscription_written?` is already true. Remove a call to `write subscription`." else @subscription_written = true context.schema.subscriptions.write_subscription(context.query, [event]) end nil end