class GraphQL::Subscriptions::BroadcastAnalyzer

Detect whether the current operation:

Assign the result to `context.namespace(:subscriptions)` @api private @see Subscriptions#broadcastable? for a public API

Public Class Methods

new(subject) click to toggle source
Calls superclass method GraphQL::Analysis::AST::Analyzer::new
# File lib/graphql/subscriptions/broadcast_analyzer.rb, line 13
def initialize(subject)
  super
  @default_broadcastable = subject.schema.subscriptions.default_broadcastable
  # Maybe this will get set to false while analyzing
  @subscription_broadcastable = true
end

Public Instance Methods

analyze?() click to toggle source

Only analyze subscription operations

# File lib/graphql/subscriptions/broadcast_analyzer.rb, line 21
def analyze?
  @query.subscription?
end
on_enter_field(node, parent, visitor) click to toggle source
# File lib/graphql/subscriptions/broadcast_analyzer.rb, line 25
def on_enter_field(node, parent, visitor)
  if (@subscription_broadcastable == false) || visitor.skipping?
    return
  end

  current_field = visitor.field_definition
  apply_broadcastable(current_field)

  current_type = visitor.parent_type_definition
  if current_type.kind.interface?
    pt = @query.possible_types(current_type)
    pt.each do |object_type|
      ot_field = @query.get_field(object_type, current_field.graphql_name)
      # Inherited fields would be exactly the same object;
      # only check fields that are overrides of the inherited one
      if ot_field && ot_field != current_field
        apply_broadcastable(ot_field)
      end
    end
  end
end
result() click to toggle source

Assign the result to context. (This method is allowed to return an error, but we don't need to) @return [void]

# File lib/graphql/subscriptions/broadcast_analyzer.rb, line 50
def result
  query.context.namespace(:subscriptions)[:subscription_broadcastable] = @subscription_broadcastable
  nil
end

Private Instance Methods

apply_broadcastable(field_defn) click to toggle source

Modify `@subscription_broadcastable` based on `field_defn`'s configuration (and/or the default value)

# File lib/graphql/subscriptions/broadcast_analyzer.rb, line 58
def apply_broadcastable(field_defn)
  current_field_broadcastable = field_defn.introspection? || field_defn.broadcastable?
  case current_field_broadcastable
  when nil
    # If the value wasn't set, mix in the default value:
    # - If the default is false and the current value is true, make it false
    # - If the default is true and the current value is true, it stays true
    # - If the default is false and the current value is false, keep it false
    # - If the default is true and the current value is false, keep it false
    @subscription_broadcastable = @subscription_broadcastable && @default_broadcastable
  when false
    # One non-broadcastable field is enough to make the whole subscription non-broadcastable
    @subscription_broadcastable = false
  when true
    # Leave `@broadcastable_query` true if it's already true,
    # but don't _set_ it to true if it was set to false by something else.
    # Actually, just leave it!
  else
    raise ArgumentError, "Unexpected `.broadcastable?` value for #{field_defn.path}: #{current_field_broadcastable}"
  end
end