class GraphQL::Subscriptions
Attributes
Returns
-
Booleanβ Used when fields donβt havebroadcastable:explicitly set
Public Class Methods
# File lib/graphql/subscriptions.rb, line 46 def initialize(schema:, validate_update: true, broadcast: false, default_broadcastable: false, **rest) if broadcast schema.query_analyzer(Subscriptions::BroadcastAnalyzer) end @default_broadcastable = default_broadcastable @schema = schema @validate_update = validate_update end
Parameters
-
schema(Class) β theGraphQLschema this manager belongs to -
validate_update(Boolean) β If false, then validation is skipped when executing updates
Source
# File lib/graphql/subscriptions.rb, line 26 def self.use(defn, options = {}) schema = defn.is_a?(Class) ? defn : defn.target if schema.subscriptions(inherited: false) raise ArgumentError, "Can't reinstall subscriptions. #{schema} is using #{schema.subscriptions}, can't also add #{self}" end options[:schema] = schema schema.subscriptions = self.new(**options) schema.add_subscription_extension_if_necessary nil end
See GraphQL::Subscriptions for the base options; concrete implementations may add options.
Public Instance Methods
# File lib/graphql/subscriptions.rb, line 332 def broadcastable?(query_str, **query_options) query = @schema.query_class.new(@schema, query_str, **query_options) if !query.valid? raise "Invalid query: #{query.validation_errors.map(&:to_h).inspect}" end GraphQL::Analysis.analyze_query(query, @schema.query_analyzers) query.context.namespace(:subscriptions)[:subscription_broadcastable] end
Returns
-
Booleanβ if true, then a query like this one would be broadcasted
Source
# File lib/graphql/subscriptions.rb, line 302 def build_id SecureRandom.uuid end
Returns
-
Stringβ A new unique identifier for a subscription
# File lib/graphql/subscriptions.rb, line 292 def delete_subscription(subscription_id) raise GraphQL::RequiredImplementationMissingError end
A subscription was terminated server-side. Clean up the database.
Parameters
-
subscription_id(String)
Returns
-
Objectβ void.
# File lib/graphql/subscriptions.rb, line 257 def deliver(subscription_id, result) raise GraphQL::RequiredImplementationMissingError end
A subscription query was re-evaluated, returning result. The result should be send to subscription_id.
Parameters
-
subscription_id(String) -
result(Hash)
Returns
-
void
# File lib/graphql/subscriptions.rb, line 194 def execute(subscription_id, event, object) res = execute_update(subscription_id, event, object) if !res.nil? deliver(subscription_id, res) if res.context.namespace(:subscriptions)[:unsubscribed] # `unsubscribe` was called, clean up on our side # The transport should also send `{more: false}` to client delete_subscription(subscription_id) end end end
Run the update query for this subscription and deliver it See execute_update See deliver
Returns
-
void
# File lib/graphql/subscriptions.rb, line 222 def execute_all(event, object) raise GraphQL::RequiredImplementationMissingError end
Event event occurred on object, Update all subscribers.
Parameters
-
event(Subscriptions::Event) -
object(Object)
Returns
-
void
# File lib/graphql/subscriptions.rb, line 129 def execute_update(subscription_id, event, object) # Lookup the saved data for this subscription query_data = read_subscription(subscription_id) if query_data.nil? delete_subscription(subscription_id) return nil end # Fetch the required keys from the saved data query_string = query_data.fetch(:query_string) variables = query_data.fetch(:variables) context = query_data.fetch(:context) operation_name = query_data.fetch(:operation_name) execute_options = { query: query_string, context: context, subscription_topic: event.topic, operation_name: operation_name, variables: variables, root_value: object, } # merge event's and query's context together context.merge!(event.context) unless event.context.nil? || context.nil? execute_options[:validate] = validate_update?(**execute_options) result = @schema.execute(**execute_options) subscriptions_context = result.context.namespace(:subscriptions) if subscriptions_context[:no_update] result = nil end if subscriptions_context[:unsubscribed] && !subscriptions_context[:final_update] # `unsubscribe` was called, clean up on our side # The transport should also send `{more: false}` to client delete_subscription(subscription_id) result = nil end result end
event was triggered on object, and subscription_id was subscribed, so it should be updated.
Load subscription_idβs GraphQL data, re-evaluate the query and return the result.
Parameters
-
subscription_id(String) -
event(GraphQL::Subscriptions::Event) β The event which was triggered -
object(Object) β The value for the subscription field
Returns
Source
# File lib/graphql/subscriptions.rb, line 379 def finalizer Finalizer.new(self) end
# File lib/graphql/subscriptions.rb, line 372 def finish_subscriptions(query) if (events = query.context.namespace(:subscriptions)[:events]) && !events.empty? write_subscription(query, events) end nil end
Called during execution when a subscription operation has finished
Parameters
-
query(GraphQL::Query)
Returns
-
void
# File lib/graphql/subscriptions.rb, line 353 def initialize_subscriptions(query) subs_namespace = query.context.namespace(:subscriptions) subs_namespace[:events] = [] subs_namespace[:subscriptions] = {} nil end
Called during execution when a new subscription ... operation is received
Parameters
-
query(GraphQL::Query)
Returns
-
void
# File lib/graphql/subscriptions.rb, line 322 def normalize_name(event_or_arg_name) Schema::Member::BuildType.camelize(event_or_arg_name.to_s) end
Convert a user-provided event name or argument to the equivalent in GraphQL.
By default, it converts the identifier to camelcase. Override this in a subclass to change the transformation.
Parameters
-
event_or_arg_name(String, Symbol)
Returns
-
String
# File lib/graphql/subscriptions.rb, line 239 def read_subscription(subscription_id) raise GraphQL::RequiredImplementationMissingError end
The system wants to send an update to this subscription. Read its data and return it.
Parameters
-
subscription_id(String)
Returns
-
Hashβ Containing required keys
# File lib/graphql/subscriptions.rb, line 77 def trigger(event_name, args, object, scope: nil, context: {}) # Make something as context-like as possible, even though there isn't a current query: dummy_query = @schema.query_class.new(@schema, "{ __typename }", validate: false, context: context) context = dummy_query.context event_name = event_name.to_s # Try with the verbatim input first: field = dummy_query.types.field(@schema.subscription, event_name) # rubocop:disable Development/ContextIsPassedCop if field.nil? # And if it wasn't found, normalize it: normalized_event_name = normalize_name(event_name) field = dummy_query.types.field(@schema.subscription, normalized_event_name) # rubocop:disable Development/ContextIsPassedCop if field.nil? raise InvalidTriggerError, "No subscription matching trigger: #{event_name} (looked for #{@schema.subscription.graphql_name}.#{normalized_event_name})" end else # Since we found a field, the original input was already normalized normalized_event_name = event_name end # Normalize symbol-keyed args to strings, try camelizing them # Should this accept a real context somehow? normalized_args = normalize_arguments(normalized_event_name, field, args, @schema.null_context) event = Subscriptions::Event.new( name: normalized_event_name, arguments: normalized_args, field: field, scope: scope, context: context, ) execute_all(event, object) end
Fetch subscriptions matching this field + arguments pair And pass them off to the queue.
Parameters
-
event_name(String) -
args(Hash<String, Symbol => Object>) β Arguments passed to the subscription resolver -
object(Object) -
scope(Symbol, String) -
context(Hash)
Returns
-
void
# File lib/graphql/subscriptions.rb, line 180 def validate_update?(query:, context:, root_value:, subscription_topic:, operation_name:, variables:) @validate_update end
Define this method to customize whether to validate this subscription when executing an update.
Returns
-
Booleanβ defaults totrue, or false ifvalidate: falseis provided.
# File lib/graphql/subscriptions.rb, line 275 def write_subscription(query, events) raise GraphQL::RequiredImplementationMissingError end
query was executed and found subscriptions to events. Update the database to reflect this new state.
Parameters
-
query(GraphQL::Query) -
events(Array<GraphQL::Subscriptions::Event>)
Returns
-
void