class GraphQL::Subscriptions::Event
This thing can be:
-
Subscribed to by ‘subscription { … }`
-
Triggered by ‘MySchema.subscriber.trigger(name, arguments, obj)`
Attributes
arguments[R]
@return [GraphQL::Execution::Interpreter::Arguments]
context[R]
@return [GraphQL::Query::Context]
name[R]
@return [String] Corresponds to the Subscription root field name
topic[R]
@return [String] An opaque string which identifies this event, derived from ‘name` and `arguments`
Public Class Methods
new(name:, arguments:, field: nil, context: nil, scope: nil)
click to toggle source
# File lib/graphql/subscriptions/event.rb, line 21 def initialize(name:, arguments:, field: nil, context: nil, scope: nil) @name = name @arguments = arguments @context = context field ||= context.field scope_key = field.subscription_scope scope_val = scope || (context && scope_key && context[scope_key]) if scope_key && (subscription = field.resolver) && (subscription.respond_to?(:subscription_scope_optional?)) && !subscription.subscription_scope_optional? && scope_val.nil? raise Subscriptions::SubscriptionScopeMissingError, "#{field.path} (#{subscription}) requires a `scope:` value to trigger updates (Set `subscription_scope ..., optional: true` to disable this requirement)" end @topic = self.class.serialize(name, arguments, field, scope: scope_val, context: context) end
serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext)
click to toggle source
@return [String] an identifier for this unit of subscription
# File lib/graphql/subscriptions/event.rb, line 40 def self.serialize(_name, arguments, field, scope:, context: GraphQL::Query::NullContext) subscription = field.resolver || GraphQL::Schema::Subscription normalized_args = stringify_args(field, arguments.to_h, context) subscription.topic_for(arguments: normalized_args, field: field, scope: scope) end
Private Class Methods
deep_sort_array_hashes(array_to_inspect)
click to toggle source
# File lib/graphql/subscriptions/event.rb, line 81 def deep_sort_array_hashes(array_to_inspect) raise ArgumentError.new("Argument must be an Array") unless array_to_inspect.is_a?(Array) array_to_inspect.map do |v| if v.is_a?(Hash) deep_sort_hash_keys(v) elsif v.is_a?(Array) deep_sort_array_hashes(v) else v end end end
deep_sort_hash_keys(hash_to_sort)
click to toggle source
This method does not support cyclic references in the Hash, nor does it support Hashes whose keys are not sortable with respect to their peers ( cases where a <=> b might throw an error )
# File lib/graphql/subscriptions/event.rb, line 68 def deep_sort_hash_keys(hash_to_sort) raise ArgumentError.new("Argument must be a Hash") unless hash_to_sort.is_a?(Hash) hash_to_sort.keys.sort.map do |k| if hash_to_sort[k].is_a?(Hash) [k, deep_sort_hash_keys(hash_to_sort[k])] elsif hash_to_sort[k].is_a?(Array) [k, deep_sort_array_hashes(hash_to_sort[k])] else [k, hash_to_sort[k]] end end.to_h end
get_arg_definition(arg_owner, arg_name, context)
click to toggle source
# File lib/graphql/subscriptions/event.rb, line 138 def get_arg_definition(arg_owner, arg_name, context) arg_owner.get_argument(arg_name, context) || arg_owner.arguments(context).each_value.find { |v| v.keyword.to_s == arg_name } end
stringify_args(arg_owner, args, context)
click to toggle source
# File lib/graphql/subscriptions/event.rb, line 94 def stringify_args(arg_owner, args, context) arg_owner = arg_owner.respond_to?(:unwrap) ? arg_owner.unwrap : arg_owner # remove list and non-null wrappers case args when Hash next_args = {} args.each do |k, v| arg_name = k.to_s camelized_arg_name = GraphQL::Schema::Member::BuildType.camelize(arg_name) arg_defn = get_arg_definition(arg_owner, camelized_arg_name, context) if arg_defn normalized_arg_name = camelized_arg_name else normalized_arg_name = arg_name arg_defn = get_arg_definition(arg_owner, normalized_arg_name, context) end arg_base_type = arg_defn.type.unwrap # In the case where the value being emitted is seen as a "JSON" # type, treat the value as one atomic unit of serialization is_json_definition = arg_base_type && arg_base_type <= GraphQL::Types::JSON if is_json_definition sorted_value = if v.is_a?(Hash) deep_sort_hash_keys(v) elsif v.is_a?(Array) deep_sort_array_hashes(v) else v end next_args[normalized_arg_name] = sorted_value.respond_to?(:to_json) ? sorted_value.to_json : sorted_value else next_args[normalized_arg_name] = stringify_args(arg_base_type, v, context) end end # Make sure they're deeply sorted next_args.sort.to_h when Array args.map { |a| stringify_args(arg_owner, a, context) } when GraphQL::Schema::InputObject stringify_args(arg_owner, args.to_h, context) else args end end
Public Instance Methods
fingerprint()
click to toggle source
@return [String] a logical identifier for this event. (Stable when the query is broadcastable.)
# File lib/graphql/subscriptions/event.rb, line 47 def fingerprint @fingerprint ||= begin # When this query has been flagged as broadcastable, # use a generalized, stable fingerprint so that # duplicate subscriptions can be evaluated and distributed in bulk. # (`@topic` includes field, args, and subscription scope already.) if @context.namespace(:subscriptions)[:subscription_broadcastable] "#{@topic}/#{@context.query.fingerprint}" else # not broadcastable, build a unique ID for this event @context.schema.subscriptions.build_id end end end