Class: Tina4::GraphQLExecutor

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/graphql.rb

Overview

─── Executor ─────────────────────────────────────────────────────────

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(schema, max_depth: 50) ⇒ GraphQLExecutor

Returns a new instance of GraphQLExecutor.



603
604
605
606
# File 'lib/tina4/graphql.rb', line 603

def initialize(schema, max_depth: 50)
  @schema = schema
  @max_depth = max_depth
end

Instance Attribute Details

#max_depthObject

max_depth bounds selection-set nesting (DoS / stack-overflow guard). Threaded down from the owning GraphQL instance; <= 0 disables the guard.



601
602
603
# File 'lib/tina4/graphql.rb', line 601

def max_depth
  @max_depth
end

Instance Method Details

#execute(document, variables: {}, context: {}, operation_name: nil) ⇒ Object

Raises:



608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
# File 'lib/tina4/graphql.rb', line 608

def execute(document, variables: {}, context: {}, operation_name: nil)
  # Collect fragments
  fragments = {}
  operations = []

  document[:definitions].each do |defn|
    case defn[:kind]
    when :fragment
      fragments[defn[:name]] = defn
    when :operation
      operations << defn
    end
  end

  # Pick the operation
  operation = if operation_name
                operations.find { |op| op[:name] == operation_name }
              elsif operations.length == 1
                operations.first
              else
                raise GraphQLError, "Must provide operation name when multiple operations exist"
              end

  raise GraphQLError, "Unknown operation: #{operation_name}" unless operation

  # Resolve variables
  resolved_vars = resolve_variables(operation[:variables], variables)

  # Choose root fields
  root_fields = case operation[:operation]
                when :query    then @schema.queries
                when :mutation then @schema.mutations
                else raise GraphQLError, "Unsupported operation: #{operation[:operation]}"
                end

  # Execute selection set
  data = {}
  errors = []

  # Top-level selections start at depth 1. Depth is incremented on every
  # recursive entry (sub-selections, fragment spreads, inline fragments) so
  # an over-deep query OR a circular fragment is caught before the
  # interpreter stack overflows.
  operation[:selection_set].each do |selection|
    resolve_selection(selection, root_fields, nil, resolved_vars, context, fragments, data, errors, 1)
  end

  result = { "data" => data }
  result["errors"] = errors unless errors.empty?
  result
end