graphql-stitching 1.5.0 → 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/.github/workflows/ci.yml +6 -8
 - data/Gemfile +1 -0
 - data/README.md +60 -20
 - data/docs/client.md +6 -0
 - data/docs/composer.md +7 -6
 - data/docs/federation_entities.md +1 -1
 - data/docs/mechanics.md +1 -43
 - data/docs/request.md +10 -10
 - data/docs/subscriptions.md +11 -11
 - data/docs/supergraph.md +5 -5
 - data/docs/{resolver.md → type_resolver.md} +3 -3
 - data/examples/subscriptions/app/graphql/subscriptions_schema.rb +3 -3
 - data/gemfiles/graphql_2.0.0.gemfile +4 -1
 - data/gemfiles/graphql_2.1.0.gemfile +4 -1
 - data/gemfiles/graphql_2.2.0.gemfile +4 -1
 - data/gemfiles/graphql_2.3.0.gemfile +9 -0
 - data/graphql-stitching.gemspec +1 -1
 - data/lib/graphql/stitching/client.rb +5 -7
 - data/lib/graphql/stitching/composer/{resolver_config.rb → type_resolver_config.rb} +2 -2
 - data/lib/graphql/stitching/composer/{validate_resolvers.rb → validate_type_resolvers.rb} +1 -1
 - data/lib/graphql/stitching/composer.rb +28 -20
 - data/lib/graphql/stitching/executor/shaper.rb +4 -4
 - data/lib/graphql/stitching/executor/{resolver_source.rb → type_resolver_source.rb} +4 -4
 - data/lib/graphql/stitching/executor.rb +5 -5
 - data/lib/graphql/stitching/planner/step.rb +1 -1
 - data/lib/graphql/stitching/planner.rb +16 -20
 - data/lib/graphql/stitching/request/skip_include.rb +1 -1
 - data/lib/graphql/stitching/request.rb +3 -7
 - data/lib/graphql/stitching/supergraph/to_definition.rb +3 -3
 - data/lib/graphql/stitching/supergraph.rb +1 -6
 - data/lib/graphql/stitching/{resolver → type_resolver}/arguments.rb +6 -6
 - data/lib/graphql/stitching/{resolver → type_resolver}/keys.rb +1 -1
 - data/lib/graphql/stitching/{resolver.rb → type_resolver.rb} +4 -4
 - data/lib/graphql/stitching/version.rb +1 -1
 - data/lib/graphql/stitching.rb +20 -3
 - metadata +12 -12
 - data/gemfiles/graphql_1.13.9.gemfile +0 -6
 
| 
         @@ -2,8 +2,8 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require_relative "composer/base_validator"
         
     | 
| 
       4 
4 
     | 
    
         
             
            require_relative "composer/validate_interfaces"
         
     | 
| 
       5 
     | 
    
         
            -
            require_relative "composer/ 
     | 
| 
       6 
     | 
    
         
            -
            require_relative "composer/ 
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative "composer/validate_type_resolvers"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "composer/type_resolver_config"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module GraphQL
         
     | 
| 
       9 
9 
     | 
    
         
             
              module Stitching
         
     | 
| 
         @@ -31,7 +31,7 @@ module GraphQL 
     | 
|
| 
       31 
31 
     | 
    
         
             
                  # @api private
         
     | 
| 
       32 
32 
     | 
    
         
             
                  COMPOSITION_VALIDATORS = [
         
     | 
| 
       33 
33 
     | 
    
         
             
                    ValidateInterfaces,
         
     | 
| 
       34 
     | 
    
         
            -
                     
     | 
| 
      
 34 
     | 
    
         
            +
                    ValidateTypeResolvers,
         
     | 
| 
       35 
35 
     | 
    
         
             
                  ].freeze
         
     | 
| 
       36 
36 
     | 
    
         | 
| 
       37 
37 
     | 
    
         
             
                  # @return [String] name of the Query type in the composed schema.
         
     | 
| 
         @@ -168,7 +168,7 @@ module GraphQL 
     | 
|
| 
       168 
168 
     | 
    
         
             
                    end
         
     | 
| 
       169 
169 
     | 
    
         | 
| 
       170 
170 
     | 
    
         
             
                    select_root_field_locations(schema)
         
     | 
| 
       171 
     | 
    
         
            -
                    expand_abstract_resolvers(schema)
         
     | 
| 
      
 171 
     | 
    
         
            +
                    expand_abstract_resolvers(schema, schemas)
         
     | 
| 
       172 
172 
     | 
    
         | 
| 
       173 
173 
     | 
    
         
             
                    supergraph = Supergraph.new(
         
     | 
| 
       174 
174 
     | 
    
         
             
                      schema: schema,
         
     | 
| 
         @@ -199,8 +199,8 @@ module GraphQL 
     | 
|
| 
       199 
199 
     | 
    
         
             
                        raise CompositionError, "The schema for `#{location}` location must be a GraphQL::Schema class."
         
     | 
| 
       200 
200 
     | 
    
         
             
                      end
         
     | 
| 
       201 
201 
     | 
    
         | 
| 
       202 
     | 
    
         
            -
                      @resolver_configs.merge!( 
     | 
| 
       203 
     | 
    
         
            -
                      @resolver_configs.merge!( 
     | 
| 
      
 202 
     | 
    
         
            +
                      @resolver_configs.merge!(TypeResolverConfig.extract_directive_assignments(schema, location, input[:stitch]))
         
     | 
| 
      
 203 
     | 
    
         
            +
                      @resolver_configs.merge!(TypeResolverConfig.extract_federation_entities(schema, location))
         
     | 
| 
       204 
204 
     | 
    
         | 
| 
       205 
205 
     | 
    
         
             
                      schemas[location.to_s] = schema
         
     | 
| 
       206 
206 
     | 
    
         
             
                      executables[location.to_s] = input[:executable] || schema
         
     | 
| 
         @@ -403,8 +403,13 @@ module GraphQL 
     | 
|
| 
       403 
403 
     | 
    
         
             
                        next
         
     | 
| 
       404 
404 
     | 
    
         
             
                      end
         
     | 
| 
       405 
405 
     | 
    
         | 
| 
       406 
     | 
    
         
            -
                      # Getting double args sometimes 
     | 
| 
       407 
     | 
    
         
            -
                       
     | 
| 
      
 406 
     | 
    
         
            +
                      # Getting double args sometimes... why?
         
     | 
| 
      
 407 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 408 
     | 
    
         
            +
                        next if owner.arguments(GraphQL::Query::NullContext.instance, false).key?(argument_name)
         
     | 
| 
      
 409 
     | 
    
         
            +
                      rescue ArgumentError
         
     | 
| 
      
 410 
     | 
    
         
            +
                        # pre- graphql v2.4.5
         
     | 
| 
      
 411 
     | 
    
         
            +
                        next if owner.arguments.key?(argument_name)
         
     | 
| 
      
 412 
     | 
    
         
            +
                      end
         
     | 
| 
       408 
413 
     | 
    
         | 
| 
       409 
414 
     | 
    
         
             
                      kwargs = {}
         
     | 
| 
       410 
415 
     | 
    
         
             
                      default_values_by_location = arguments_by_location.each_with_object({}) do |(location, argument), memo|
         
     | 
| 
         @@ -546,13 +551,13 @@ module GraphQL 
     | 
|
| 
       546 
551 
     | 
    
         | 
| 
       547 
552 
     | 
    
         
             
                        subgraph_field.directives.each do |directive|
         
     | 
| 
       548 
553 
     | 
    
         
             
                          next unless directive.graphql_name == GraphQL::Stitching.stitch_directive
         
     | 
| 
       549 
     | 
    
         
            -
                          resolver_configs <<  
     | 
| 
      
 554 
     | 
    
         
            +
                          resolver_configs << TypeResolverConfig.from_kwargs(directive.arguments.keyword_arguments)
         
     | 
| 
       550 
555 
     | 
    
         
             
                        end
         
     | 
| 
       551 
556 
     | 
    
         | 
| 
       552 
557 
     | 
    
         
             
                        resolver_configs.each do |config|
         
     | 
| 
       553 
558 
     | 
    
         
             
                          resolver_type_name = if config.type_name
         
     | 
| 
       554 
559 
     | 
    
         
             
                            if !resolver_type.kind.abstract?
         
     | 
| 
       555 
     | 
    
         
            -
                              raise CompositionError, " 
     | 
| 
      
 560 
     | 
    
         
            +
                              raise CompositionError, "Type resolver config may only specify a type name for abstract resolvers."
         
     | 
| 
       556 
561 
     | 
    
         
             
                            elsif !resolver_type.possible_types.find { _1.graphql_name == config.type_name }
         
     | 
| 
       557 
562 
     | 
    
         
             
                              raise CompositionError, "Type `#{config.type_name}` is not a possible return type for query `#{field_name}`."
         
     | 
| 
       558 
563 
     | 
    
         
             
                            end
         
     | 
| 
         @@ -561,7 +566,7 @@ module GraphQL 
     | 
|
| 
       561 
566 
     | 
    
         
             
                            resolver_type.graphql_name
         
     | 
| 
       562 
567 
     | 
    
         
             
                          end
         
     | 
| 
       563 
568 
     | 
    
         | 
| 
       564 
     | 
    
         
            -
                          key =  
     | 
| 
      
 569 
     | 
    
         
            +
                          key = TypeResolver.parse_key_with_types(
         
     | 
| 
       565 
570 
     | 
    
         
             
                            config.key,
         
     | 
| 
       566 
571 
     | 
    
         
             
                            @subgraph_types_by_name_and_location[resolver_type_name],
         
     | 
| 
       567 
572 
     | 
    
         
             
                          )
         
     | 
| 
         @@ -581,11 +586,11 @@ module GraphQL 
     | 
|
| 
       581 
586 
     | 
    
         
             
                            "#{argument.graphql_name}: $.#{key.primitive_name}"
         
     | 
| 
       582 
587 
     | 
    
         
             
                          end
         
     | 
| 
       583 
588 
     | 
    
         | 
| 
       584 
     | 
    
         
            -
                          arguments =  
     | 
| 
      
 589 
     | 
    
         
            +
                          arguments = TypeResolver.parse_arguments_with_field(arguments_format, subgraph_field)
         
     | 
| 
       585 
590 
     | 
    
         
             
                          arguments.each { _1.verify_key(key) }
         
     | 
| 
       586 
591 
     | 
    
         | 
| 
       587 
592 
     | 
    
         
             
                          @resolver_map[resolver_type_name] ||= []
         
     | 
| 
       588 
     | 
    
         
            -
                          @resolver_map[resolver_type_name] <<  
     | 
| 
      
 593 
     | 
    
         
            +
                          @resolver_map[resolver_type_name] << TypeResolver.new(
         
     | 
| 
       589 
594 
     | 
    
         
             
                            location: location,
         
     | 
| 
       590 
595 
     | 
    
         
             
                            type_name: resolver_type_name,
         
     | 
| 
       591 
596 
     | 
    
         
             
                            field: subgraph_field.name,
         
     | 
| 
         @@ -620,15 +625,18 @@ module GraphQL 
     | 
|
| 
       620 
625 
     | 
    
         | 
| 
       621 
626 
     | 
    
         
             
                  # @!scope class
         
     | 
| 
       622 
627 
     | 
    
         
             
                  # @!visibility private
         
     | 
| 
       623 
     | 
    
         
            -
                  def expand_abstract_resolvers( 
     | 
| 
      
 628 
     | 
    
         
            +
                  def expand_abstract_resolvers(composed_schema, schemas_by_location)
         
     | 
| 
       624 
629 
     | 
    
         
             
                    @resolver_map.keys.each do |type_name|
         
     | 
| 
       625 
     | 
    
         
            -
                       
     | 
| 
       626 
     | 
    
         
            -
             
     | 
| 
      
 630 
     | 
    
         
            +
                      next unless composed_schema.get_type(type_name).kind.abstract?
         
     | 
| 
      
 631 
     | 
    
         
            +
             
     | 
| 
      
 632 
     | 
    
         
            +
                      @resolver_map[type_name].each do |resolver|
         
     | 
| 
      
 633 
     | 
    
         
            +
                        abstract_type = @subgraph_types_by_name_and_location[type_name][resolver.location]
         
     | 
| 
      
 634 
     | 
    
         
            +
                        expanded_types = Util.expand_abstract_type(schemas_by_location[resolver.location], abstract_type)
         
     | 
| 
       627 
635 
     | 
    
         | 
| 
       628 
     | 
    
         
            -
             
     | 
| 
       629 
     | 
    
         
            -
             
     | 
| 
       630 
     | 
    
         
            -
             
     | 
| 
       631 
     | 
    
         
            -
                         
     | 
| 
      
 636 
     | 
    
         
            +
                        expanded_types.select { @subgraph_types_by_name_and_location[_1.graphql_name].length > 1 }.each do |impl_type|
         
     | 
| 
      
 637 
     | 
    
         
            +
                          @resolver_map[impl_type.graphql_name] ||= []
         
     | 
| 
      
 638 
     | 
    
         
            +
                          @resolver_map[impl_type.graphql_name].push(resolver)
         
     | 
| 
      
 639 
     | 
    
         
            +
                        end
         
     | 
| 
       632 
640 
     | 
    
         
             
                      end
         
     | 
| 
       633 
641 
     | 
    
         
             
                    end
         
     | 
| 
       634 
642 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -23,8 +23,8 @@ module GraphQL::Stitching 
     | 
|
| 
       23 
23 
     | 
    
         
             
                  def resolve_object_scope(raw_object, parent_type, selections, typename = nil)
         
     | 
| 
       24 
24 
     | 
    
         
             
                    return nil if raw_object.nil?
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
                    typename ||= raw_object[ 
     | 
| 
       27 
     | 
    
         
            -
                    raw_object.reject! { |key, _v|  
     | 
| 
      
 26 
     | 
    
         
            +
                    typename ||= raw_object[TypeResolver::TYPENAME_EXPORT_NODE.alias]
         
     | 
| 
      
 27 
     | 
    
         
            +
                    raw_object.reject! { |key, _v| TypeResolver.export_key?(key) }
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
                    selections.each do |node|
         
     | 
| 
       30 
30 
     | 
    
         
             
                      case node
         
     | 
| 
         @@ -64,7 +64,7 @@ module GraphQL::Stitching 
     | 
|
| 
       64 
64 
     | 
    
         
             
                        return nil if result.nil?
         
     | 
| 
       65 
65 
     | 
    
         | 
| 
       66 
66 
     | 
    
         
             
                      else
         
     | 
| 
       67 
     | 
    
         
            -
                        raise  
     | 
| 
      
 67 
     | 
    
         
            +
                        raise DocumentError.new("selection node type")
         
     | 
| 
       68 
68 
     | 
    
         
             
                      end
         
     | 
| 
       69 
69 
     | 
    
         
             
                    end
         
     | 
| 
       70 
70 
     | 
    
         | 
| 
         @@ -118,7 +118,7 @@ module GraphQL::Stitching 
     | 
|
| 
       118 
118 
     | 
    
         
             
                  def typename_in_type?(typename, type)
         
     | 
| 
       119 
119 
     | 
    
         
             
                    return true if type.graphql_name == typename
         
     | 
| 
       120 
120 
     | 
    
         | 
| 
       121 
     | 
    
         
            -
                    type.kind.abstract? && @ 
     | 
| 
      
 121 
     | 
    
         
            +
                    type.kind.abstract? && @supergraph.schema.possible_types(type).any? do |t|
         
     | 
| 
       122 
122 
     | 
    
         
             
                      t.graphql_name == typename
         
     | 
| 
       123 
123 
     | 
    
         
             
                    end
         
     | 
| 
       124 
124 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -2,7 +2,7 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module GraphQL::Stitching
         
     | 
| 
       4 
4 
     | 
    
         
             
              class Executor
         
     | 
| 
       5 
     | 
    
         
            -
                class  
     | 
| 
      
 5 
     | 
    
         
            +
                class TypeResolverSource < GraphQL::Dataloader::Source
         
     | 
| 
       6 
6 
     | 
    
         
             
                  def initialize(executor, location)
         
     | 
| 
       7 
7 
     | 
    
         
             
                    @executor = executor
         
     | 
| 
       8 
8 
     | 
    
         
             
                    @location = location
         
     | 
| 
         @@ -10,14 +10,14 @@ module GraphQL::Stitching 
     | 
|
| 
       10 
10 
     | 
    
         
             
                  end
         
     | 
| 
       11 
11 
     | 
    
         | 
| 
       12 
12 
     | 
    
         
             
                  def fetch(ops)
         
     | 
| 
       13 
     | 
    
         
            -
                    origin_sets_by_operation = ops.each_with_object({}) do |op, memo|
         
     | 
| 
      
 13 
     | 
    
         
            +
                    origin_sets_by_operation = ops.each_with_object({}.compare_by_identity) do |op, memo|
         
     | 
| 
       14 
14 
     | 
    
         
             
                      origin_set = op.path.reduce([@executor.data]) do |set, path_segment|
         
     | 
| 
       15 
15 
     | 
    
         
             
                        set.flat_map { |obj| obj && obj[path_segment] }.tap(&:compact!)
         
     | 
| 
       16 
16 
     | 
    
         
             
                      end
         
     | 
| 
       17 
17 
     | 
    
         | 
| 
       18 
18 
     | 
    
         
             
                      if op.if_type
         
     | 
| 
       19 
19 
     | 
    
         
             
                        # operations planned around unused fragment conditions should not trigger requests
         
     | 
| 
       20 
     | 
    
         
            -
                        origin_set.select! { _1[ 
     | 
| 
      
 20 
     | 
    
         
            +
                        origin_set.select! { _1[TypeResolver::TYPENAME_EXPORT_NODE.alias] == op.if_type }
         
     | 
| 
       21 
21 
     | 
    
         
             
                      end
         
     | 
| 
       22 
22 
     | 
    
         | 
| 
       23 
23 
     | 
    
         
             
                      memo[op] = origin_set if origin_set.any?
         
     | 
| 
         @@ -86,7 +86,7 @@ module GraphQL::Stitching 
     | 
|
| 
       86 
86 
     | 
    
         
             
                      end
         
     | 
| 
       87 
87 
     | 
    
         
             
                    end
         
     | 
| 
       88 
88 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
                    doc = String.new( 
     | 
| 
      
 89 
     | 
    
         
            +
                    doc = String.new(QUERY_OP) # << resolver fulfillment always uses query
         
     | 
| 
       90 
90 
     | 
    
         | 
| 
       91 
91 
     | 
    
         
             
                    if operation_name
         
     | 
| 
       92 
92 
     | 
    
         
             
                      doc << " #{operation_name}"
         
     | 
| 
         @@ -1,8 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require "json"
         
     | 
| 
       4 
     | 
    
         
            -
            require_relative "executor/resolver_source"
         
     | 
| 
       5 
4 
     | 
    
         
             
            require_relative "executor/root_source"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative "executor/type_resolver_source"
         
     | 
| 
       6 
6 
     | 
    
         
             
            require_relative "executor/shaper"
         
     | 
| 
       7 
7 
     | 
    
         | 
| 
       8 
8 
     | 
    
         
             
            module GraphQL
         
     | 
| 
         @@ -27,7 +27,7 @@ module GraphQL 
     | 
|
| 
       27 
27 
     | 
    
         
             
                  # Builds a new executor.
         
     | 
| 
       28 
28 
     | 
    
         
             
                  # @param request [Request] the stitching request to execute.
         
     | 
| 
       29 
29 
     | 
    
         
             
                  # @param nonblocking [Boolean] specifies if the dataloader should use async concurrency.
         
     | 
| 
       30 
     | 
    
         
            -
                  def initialize(request, data: {}, errors: [], after:  
     | 
| 
      
 30 
     | 
    
         
            +
                  def initialize(request, data: {}, errors: [], after: Planner::ROOT_INDEX, nonblocking: false)
         
     | 
| 
       31 
31 
     | 
    
         
             
                    @request = request
         
     | 
| 
       32 
32 
     | 
    
         
             
                    @data = data
         
     | 
| 
       33 
33 
     | 
    
         
             
                    @errors = errors
         
     | 
| 
         @@ -38,7 +38,7 @@ module GraphQL 
     | 
|
| 
       38 
38 
     | 
    
         
             
                  end
         
     | 
| 
       39 
39 
     | 
    
         | 
| 
       40 
40 
     | 
    
         
             
                  def perform(raw: false)
         
     | 
| 
       41 
     | 
    
         
            -
                    exec!
         
     | 
| 
      
 41 
     | 
    
         
            +
                    exec!([@after])
         
     | 
| 
       42 
42 
     | 
    
         
             
                    result = {}
         
     | 
| 
       43 
43 
     | 
    
         | 
| 
       44 
44 
     | 
    
         
             
                    if @data && @data.length > 0
         
     | 
| 
         @@ -54,7 +54,7 @@ module GraphQL 
     | 
|
| 
       54 
54 
     | 
    
         | 
| 
       55 
55 
     | 
    
         
             
                  private
         
     | 
| 
       56 
56 
     | 
    
         | 
| 
       57 
     | 
    
         
            -
                  def exec!(next_steps 
     | 
| 
      
 57 
     | 
    
         
            +
                  def exec!(next_steps)
         
     | 
| 
       58 
58 
     | 
    
         
             
                    if @exec_cycles > @request.plan.ops.length
         
     | 
| 
       59 
59 
     | 
    
         
             
                      # sanity check... if we've exceeded queue size, then something went wrong.
         
     | 
| 
       60 
60 
     | 
    
         
             
                      raise StitchingError, "Too many execution requests attempted."
         
     | 
| 
         @@ -66,7 +66,7 @@ module GraphQL 
     | 
|
| 
       66 
66 
     | 
    
         
             
                        .select { next_steps.include?(_1.after) }
         
     | 
| 
       67 
67 
     | 
    
         
             
                        .group_by { [_1.location, _1.resolver.nil?] }
         
     | 
| 
       68 
68 
     | 
    
         
             
                        .map do |(location, root_source), ops|
         
     | 
| 
       69 
     | 
    
         
            -
                          source_class = root_source ? RootSource :  
     | 
| 
      
 69 
     | 
    
         
            +
                          source_class = root_source ? RootSource : TypeResolverSource
         
     | 
| 
       70 
70 
     | 
    
         
             
                          @dataloader.with(source_class, self, location).request_all(ops)
         
     | 
| 
       71 
71 
     | 
    
         
             
                        end
         
     | 
| 
       72 
72 
     | 
    
         | 
| 
         @@ -20,7 +20,7 @@ module GraphQL 
     | 
|
| 
       20 
20 
     | 
    
         
             
                  def perform
         
     | 
| 
       21 
21 
     | 
    
         
             
                    build_root_entrypoints
         
     | 
| 
       22 
22 
     | 
    
         
             
                    expand_abstract_resolvers
         
     | 
| 
       23 
     | 
    
         
            -
                    Plan.new(ops: steps.map(&:to_plan_op))
         
     | 
| 
      
 23 
     | 
    
         
            +
                    Plan.new(ops: steps.map!(&:to_plan_op))
         
     | 
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                  def steps
         
     | 
| 
         @@ -35,6 +35,7 @@ module GraphQL 
     | 
|
| 
       35 
35 
     | 
    
         
             
                  # A) Group all root selections by their preferred entrypoint locations.
         
     | 
| 
       36 
36 
     | 
    
         
             
                  # A.1) Group query fields by location for parallel execution.
         
     | 
| 
       37 
37 
     | 
    
         
             
                  # A.2) Partition mutation fields by consecutive location for serial execution.
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # A.3) Permit exactly one subscription field.
         
     | 
| 
       38 
39 
     | 
    
         
             
                  #
         
     | 
| 
       39 
40 
     | 
    
         
             
                  # B) Extract contiguous selections for each entrypoint location.
         
     | 
| 
       40 
41 
     | 
    
         
             
                  # B.1) Selections on interface types that do not belong to the interface at the
         
     | 
| 
         @@ -75,9 +76,7 @@ module GraphQL 
     | 
|
| 
       75 
76 
     | 
    
         
             
                    resolver: nil
         
     | 
| 
       76 
77 
     | 
    
         
             
                  )
         
     | 
| 
       77 
78 
     | 
    
         
             
                    # coalesce repeat parameters into a single entrypoint
         
     | 
| 
       78 
     | 
    
         
            -
                    entrypoint =  
     | 
| 
       79 
     | 
    
         
            -
                    path.each { entrypoint << "/#{_1}" }
         
     | 
| 
       80 
     | 
    
         
            -
             
     | 
| 
      
 79 
     | 
    
         
            +
                    entrypoint = [parent_index, location, parent_type.graphql_name, resolver&.key&.to_definition, "#", *path].join("/")
         
     | 
| 
       81 
80 
     | 
    
         
             
                    step = @steps_by_entrypoint[entrypoint]
         
     | 
| 
       82 
81 
     | 
    
         
             
                    next_index = step ? parent_index : @planning_index += 1
         
     | 
| 
       83 
82 
     | 
    
         | 
| 
         @@ -107,11 +106,11 @@ module GraphQL 
     | 
|
| 
       107 
106 
     | 
    
         | 
| 
       108 
107 
     | 
    
         
             
                  # A) Group all root selections by their preferred entrypoint locations.
         
     | 
| 
       109 
108 
     | 
    
         
             
                  def build_root_entrypoints
         
     | 
| 
      
 109 
     | 
    
         
            +
                    parent_type = @supergraph.schema.root_type_for_operation(@request.operation.operation_type)
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
       110 
111 
     | 
    
         
             
                    case @request.operation.operation_type
         
     | 
| 
       111 
112 
     | 
    
         
             
                    when QUERY_OP
         
     | 
| 
       112 
113 
     | 
    
         
             
                      # A.1) Group query fields by location for parallel execution.
         
     | 
| 
       113 
     | 
    
         
            -
                      parent_type = @supergraph.schema.query
         
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
114 
     | 
    
         
             
                      selections_by_location = {}
         
     | 
| 
       116 
115 
     | 
    
         
             
                      each_field_in_scope(parent_type, @request.operation.selections) do |node|
         
     | 
| 
       117 
116 
     | 
    
         
             
                        locations = @supergraph.locations_by_type_and_field[parent_type.graphql_name][node.name] || SUPERGRAPH_LOCATIONS
         
     | 
| 
         @@ -131,8 +130,6 @@ module GraphQL 
     | 
|
| 
       131 
130 
     | 
    
         | 
| 
       132 
131 
     | 
    
         
             
                    when MUTATION_OP
         
     | 
| 
       133 
132 
     | 
    
         
             
                      # A.2) Partition mutation fields by consecutive location for serial execution.
         
     | 
| 
       134 
     | 
    
         
            -
                      parent_type = @supergraph.schema.mutation
         
     | 
| 
       135 
     | 
    
         
            -
             
     | 
| 
       136 
133 
     | 
    
         
             
                      partitions = []
         
     | 
| 
       137 
134 
     | 
    
         
             
                      each_field_in_scope(parent_type, @request.operation.selections) do |node|
         
     | 
| 
       138 
135 
     | 
    
         
             
                        next_location = @supergraph.locations_by_type_and_field[parent_type.graphql_name][node.name].first
         
     | 
| 
         @@ -155,10 +152,9 @@ module GraphQL 
     | 
|
| 
       155 
152 
     | 
    
         
             
                      end
         
     | 
| 
       156 
153 
     | 
    
         | 
| 
       157 
154 
     | 
    
         
             
                    when SUBSCRIPTION_OP
         
     | 
| 
       158 
     | 
    
         
            -
                       
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
      
 155 
     | 
    
         
            +
                      # A.3) Permit exactly one subscription field.
         
     | 
| 
       160 
156 
     | 
    
         
             
                      each_field_in_scope(parent_type, @request.operation.selections) do |node|
         
     | 
| 
       161 
     | 
    
         
            -
                        raise  
     | 
| 
      
 157 
     | 
    
         
            +
                        raise DocumentError.new("root field") unless @steps_by_entrypoint.empty?
         
     | 
| 
       162 
158 
     | 
    
         | 
| 
       163 
159 
     | 
    
         
             
                        locations = @supergraph.locations_by_type_and_field[parent_type.graphql_name][node.name] || SUPERGRAPH_LOCATIONS
         
     | 
| 
       164 
160 
     | 
    
         
             
                        add_step(
         
     | 
| 
         @@ -171,7 +167,7 @@ module GraphQL 
     | 
|
| 
       171 
167 
     | 
    
         
             
                      end
         
     | 
| 
       172 
168 
     | 
    
         | 
| 
       173 
169 
     | 
    
         
             
                    else
         
     | 
| 
       174 
     | 
    
         
            -
                      raise  
     | 
| 
      
 170 
     | 
    
         
            +
                      raise DocumentError.new("operation type")
         
     | 
| 
       175 
171 
     | 
    
         
             
                    end
         
     | 
| 
       176 
172 
     | 
    
         
             
                  end
         
     | 
| 
       177 
173 
     | 
    
         | 
| 
         @@ -191,7 +187,7 @@ module GraphQL 
     | 
|
| 
       191 
187 
     | 
    
         
             
                        each_field_in_scope(parent_type, fragment.selections, &block)
         
     | 
| 
       192 
188 
     | 
    
         | 
| 
       193 
189 
     | 
    
         
             
                      else
         
     | 
| 
       194 
     | 
    
         
            -
                        raise  
     | 
| 
      
 190 
     | 
    
         
            +
                        raise DocumentError.new("selection node type")
         
     | 
| 
       195 
191 
     | 
    
         
             
                      end
         
     | 
| 
       196 
192 
     | 
    
         
             
                    end
         
     | 
| 
       197 
193 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -217,8 +213,8 @@ module GraphQL 
     | 
|
| 
       217 
213 
     | 
    
         
             
                    input_selections.each do |node|
         
     | 
| 
       218 
214 
     | 
    
         
             
                      case node
         
     | 
| 
       219 
215 
     | 
    
         
             
                      when GraphQL::Language::Nodes::Field
         
     | 
| 
       220 
     | 
    
         
            -
                        if node.alias&.start_with?( 
     | 
| 
       221 
     | 
    
         
            -
                          raise StitchingError, %(Alias "#{node.alias}" is not allowed because "#{ 
     | 
| 
      
 216 
     | 
    
         
            +
                        if node.alias&.start_with?(TypeResolver::EXPORT_PREFIX)
         
     | 
| 
      
 217 
     | 
    
         
            +
                          raise StitchingError, %(Alias "#{node.alias}" is not allowed because "#{TypeResolver::EXPORT_PREFIX}" is a reserved prefix.)
         
     | 
| 
       222 
218 
     | 
    
         
             
                        elsif node.name == TYPENAME
         
     | 
| 
       223 
219 
     | 
    
         
             
                          locale_selections << node
         
     | 
| 
       224 
220 
     | 
    
         
             
                          next
         
     | 
| 
         @@ -273,14 +269,14 @@ module GraphQL 
     | 
|
| 
       273 
269 
     | 
    
         
             
                        end
         
     | 
| 
       274 
270 
     | 
    
         | 
| 
       275 
271 
     | 
    
         
             
                      else
         
     | 
| 
       276 
     | 
    
         
            -
                        raise  
     | 
| 
      
 272 
     | 
    
         
            +
                        raise DocumentError.new("selection node type")
         
     | 
| 
       277 
273 
     | 
    
         
             
                      end
         
     | 
| 
       278 
274 
     | 
    
         
             
                    end
         
     | 
| 
       279 
275 
     | 
    
         | 
| 
       280 
276 
     | 
    
         
             
                    # B.4) Add a `__typename` export to abstracts and types that implement
         
     | 
| 
       281 
277 
     | 
    
         
             
                    # fragments so that resolved type information is available during execution.
         
     | 
| 
       282 
     | 
    
         
            -
                    if requires_typename && !locale_selections.include?( 
     | 
| 
       283 
     | 
    
         
            -
                      locale_selections <<  
     | 
| 
      
 278 
     | 
    
         
            +
                    if requires_typename && !locale_selections.include?(TypeResolver::TYPENAME_EXPORT_NODE)
         
     | 
| 
      
 279 
     | 
    
         
            +
                      locale_selections << TypeResolver::TYPENAME_EXPORT_NODE
         
     | 
| 
       284 
280 
     | 
    
         
             
                    end
         
     | 
| 
       285 
281 
     | 
    
         | 
| 
       286 
282 
     | 
    
         
             
                    if remote_selections
         
     | 
| 
         @@ -296,7 +292,7 @@ module GraphQL 
     | 
|
| 
       296 
292 
     | 
    
         
             
                          # E.1) Add the key of each resolver query into the prior location's selection set.
         
     | 
| 
       297 
293 
     | 
    
         
             
                          parent_selections.push(*resolver.key.export_nodes) if resolver.key
         
     | 
| 
       298 
294 
     | 
    
         
             
                          parent_selections.uniq! do |node|
         
     | 
| 
       299 
     | 
    
         
            -
                            export_node = node.is_a?(GraphQL::Language::Nodes::Field) &&  
     | 
| 
      
 295 
     | 
    
         
            +
                            export_node = node.is_a?(GraphQL::Language::Nodes::Field) && TypeResolver.export_key?(node.alias)
         
     | 
| 
       300 
296 
     | 
    
         
             
                            export_node ? node.alias : node.object_id
         
     | 
| 
       301 
297 
     | 
    
         
             
                          end
         
     | 
| 
       302 
298 
     | 
    
         | 
| 
         @@ -335,7 +331,7 @@ module GraphQL 
     | 
|
| 
       335 
331 
     | 
    
         
             
                    end
         
     | 
| 
       336 
332 
     | 
    
         | 
| 
       337 
333 
     | 
    
         
             
                    if expanded_selections
         
     | 
| 
       338 
     | 
    
         
            -
                      @ 
     | 
| 
      
 334 
     | 
    
         
            +
                      @supergraph.schema.possible_types(parent_type).each do |possible_type|
         
     | 
| 
       339 
335 
     | 
    
         
             
                        next unless @supergraph.locations_by_type[possible_type.graphql_name].include?(current_location)
         
     | 
| 
       340 
336 
     | 
    
         | 
| 
       341 
337 
     | 
    
         
             
                        type_name = GraphQL::Language::Nodes::TypeName.new(name: possible_type.graphql_name)
         
     | 
| 
         @@ -26,9 +26,6 @@ module GraphQL 
     | 
|
| 
       26 
26 
     | 
    
         
             
                  # @return [Hash] contextual object passed through resolver flows.
         
     | 
| 
       27 
27 
     | 
    
         
             
                  attr_reader :context
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
     | 
    
         
            -
                  # @return [GraphQL::Schema::Warden] a visibility warden for this request.
         
     | 
| 
       30 
     | 
    
         
            -
                  attr_reader :warden
         
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
       32 
29 
     | 
    
         
             
                  # Creates a new supergraph request.
         
     | 
| 
       33 
30 
     | 
    
         
             
                  # @param supergraph [Supergraph] supergraph instance that resolves the request.
         
     | 
| 
       34 
31 
     | 
    
         
             
                  # @param document [String, GraphQL::Language::Nodes::Document] the request string or parsed AST.
         
     | 
| 
         @@ -58,7 +55,6 @@ module GraphQL 
     | 
|
| 
       58 
55 
     | 
    
         
             
                    @variables = variables || {}
         
     | 
| 
       59 
56 
     | 
    
         | 
| 
       60 
57 
     | 
    
         
             
                    @query = GraphQL::Query.new(@supergraph.schema, document: @document, context: context)
         
     | 
| 
       61 
     | 
    
         
            -
                    @warden = @query.warden
         
     | 
| 
       62 
58 
     | 
    
         
             
                    @context = @query.context
         
     | 
| 
       63 
59 
     | 
    
         
             
                    @context[:request] = self
         
     | 
| 
       64 
60 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -75,12 +71,12 @@ module GraphQL 
     | 
|
| 
       75 
71 
     | 
    
         | 
| 
       76 
72 
     | 
    
         
             
                  # @return [String] a digest of the original document string. Generally faster but less consistent.
         
     | 
| 
       77 
73 
     | 
    
         
             
                  def digest
         
     | 
| 
       78 
     | 
    
         
            -
                    @digest ||=  
     | 
| 
      
 74 
     | 
    
         
            +
                    @digest ||= Stitching.digest.call("#{Stitching::VERSION}/#{string}")
         
     | 
| 
       79 
75 
     | 
    
         
             
                  end
         
     | 
| 
       80 
76 
     | 
    
         | 
| 
       81 
77 
     | 
    
         
             
                  # @return [String] a digest of the normalized document string. Slower but more consistent.
         
     | 
| 
       82 
78 
     | 
    
         
             
                  def normalized_digest
         
     | 
| 
       83 
     | 
    
         
            -
                    @normalized_digest ||=  
     | 
| 
      
 79 
     | 
    
         
            +
                    @normalized_digest ||= Stitching.digest.call("#{Stitching::VERSION}/#{normalized_string}")
         
     | 
| 
       84 
80 
     | 
    
         
             
                  end
         
     | 
| 
       85 
81 
     | 
    
         | 
| 
       86 
82 
     | 
    
         
             
                  # @return [GraphQL::Language::Nodes::OperationDefinition] The selected root operation for the request.
         
     | 
| 
         @@ -141,7 +137,7 @@ module GraphQL 
     | 
|
| 
       141 
137 
     | 
    
         
             
                  # Validates the request using the combined supergraph schema.
         
     | 
| 
       142 
138 
     | 
    
         
             
                  # @return [Array<GraphQL::ExecutionError>] an array of static validation errors
         
     | 
| 
       143 
139 
     | 
    
         
             
                  def validate
         
     | 
| 
       144 
     | 
    
         
            -
                    result = @supergraph.static_validator.validate(@query)
         
     | 
| 
      
 140 
     | 
    
         
            +
                    result = @supergraph.schema.static_validator.validate(@query)
         
     | 
| 
       145 
141 
     | 
    
         
             
                    result[:errors]
         
     | 
| 
       146 
142 
     | 
    
         
             
                  end
         
     | 
| 
       147 
143 
     | 
    
         | 
| 
         @@ -32,7 +32,7 @@ module GraphQL::Stitching 
     | 
|
| 
       32 
32 
     | 
    
         
             
                      end
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
34 
     | 
    
         
             
                      key_definitions = locations_by_key.each_with_object({}) do |(key, locations), memo|
         
     | 
| 
       35 
     | 
    
         
            -
                        memo[key] =  
     | 
| 
      
 35 
     | 
    
         
            +
                        memo[key] = TypeResolver.parse_key(key, locations)
         
     | 
| 
       36 
36 
     | 
    
         
             
                      end
         
     | 
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
                      # Collect/build resolver definitions for each type
         
     | 
| 
         @@ -41,13 +41,13 @@ module GraphQL::Stitching 
     | 
|
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
                        kwargs = directive.arguments.keyword_arguments
         
     | 
| 
       43 
43 
     | 
    
         
             
                        resolver_map[type_name] ||= []
         
     | 
| 
       44 
     | 
    
         
            -
                        resolver_map[type_name] <<  
     | 
| 
      
 44 
     | 
    
         
            +
                        resolver_map[type_name] << TypeResolver.new(
         
     | 
| 
       45 
45 
     | 
    
         
             
                          location: kwargs[:location],
         
     | 
| 
       46 
46 
     | 
    
         
             
                          type_name: kwargs.fetch(:type_name, type_name),
         
     | 
| 
       47 
47 
     | 
    
         
             
                          field: kwargs[:field],
         
     | 
| 
       48 
48 
     | 
    
         
             
                          list: kwargs[:list] || false,
         
     | 
| 
       49 
49 
     | 
    
         
             
                          key: key_definitions[kwargs[:key]],
         
     | 
| 
       50 
     | 
    
         
            -
                          arguments:  
     | 
| 
      
 50 
     | 
    
         
            +
                          arguments: TypeResolver.parse_arguments_with_type_defs(kwargs[:arguments], kwargs[:argument_types]),
         
     | 
| 
       51 
51 
     | 
    
         
             
                        )
         
     | 
| 
       52 
52 
     | 
    
         
             
                      end
         
     | 
| 
       53 
53 
     | 
    
         | 
| 
         @@ -50,11 +50,6 @@ module GraphQL 
     | 
|
| 
       50 
50 
     | 
    
         
             
                    end.freeze
         
     | 
| 
       51 
51 
     | 
    
         
             
                  end
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                  # @return [GraphQL::StaticValidation::Validator] static validator for the supergraph schema.
         
     | 
| 
       54 
     | 
    
         
            -
                  def static_validator
         
     | 
| 
       55 
     | 
    
         
            -
                    @static_validator ||= @schema.static_validator
         
     | 
| 
       56 
     | 
    
         
            -
                  end
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
53 
     | 
    
         
             
                  def resolvers_by_version
         
     | 
| 
       59 
54 
     | 
    
         
             
                    @resolvers_by_version ||= resolvers.values.tap(&:flatten!).each_with_object({}) do |resolver, memo|
         
     | 
| 
       60 
55 
     | 
    
         
             
                      memo[resolver.version] = resolver
         
     | 
| 
         @@ -166,7 +161,7 @@ module GraphQL 
     | 
|
| 
       166 
161 
     | 
    
         
             
                    if key_count.zero?
         
     | 
| 
       167 
162 
     | 
    
         
             
                      # nested root scopes have no resolver keys and just return a location
         
     | 
| 
       168 
163 
     | 
    
         
             
                      goal_locations.each_with_object({}) do |goal_location, memo|
         
     | 
| 
       169 
     | 
    
         
            -
                        memo[goal_location] = [ 
     | 
| 
      
 164 
     | 
    
         
            +
                        memo[goal_location] = [TypeResolver.new(location: goal_location)]
         
     | 
| 
       170 
165 
     | 
    
         
             
                      end
         
     | 
| 
       171 
166 
     | 
    
         | 
| 
       172 
167 
     | 
    
         
             
                    elsif key_count > 1
         
     | 
| 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            module GraphQL::Stitching
         
     | 
| 
       4 
     | 
    
         
            -
              class  
     | 
| 
      
 4 
     | 
    
         
            +
              class TypeResolver
         
     | 
| 
       5 
5 
     | 
    
         
             
                # Defines a single resolver argument structure
         
     | 
| 
       6 
6 
     | 
    
         
             
                # @api private
         
     | 
| 
       7 
7 
     | 
    
         
             
                class Argument
         
     | 
| 
         @@ -129,9 +129,9 @@ module GraphQL::Stitching 
     | 
|
| 
       129 
129 
     | 
    
         
             
                  end
         
     | 
| 
       130 
130 
     | 
    
         | 
| 
       131 
131 
     | 
    
         
             
                  def verify_key(arg, key)
         
     | 
| 
       132 
     | 
    
         
            -
                    key_field = value.reduce( 
     | 
| 
      
 132 
     | 
    
         
            +
                    key_field = value.reduce(TypeResolver::KeyField.new("", inner: key)) do |field, ns|
         
     | 
| 
       133 
133 
     | 
    
         
             
                      if ns == TYPENAME
         
     | 
| 
       134 
     | 
    
         
            -
                         
     | 
| 
      
 134 
     | 
    
         
            +
                        TypeResolver::KeyField.new(TYPENAME)
         
     | 
| 
       135 
135 
     | 
    
         
             
                      elsif field
         
     | 
| 
       136 
136 
     | 
    
         
             
                        field.inner.find { _1.name == ns }
         
     | 
| 
       137 
137 
     | 
    
         
             
                      end
         
     | 
| 
         @@ -146,7 +146,7 @@ module GraphQL::Stitching 
     | 
|
| 
       146 
146 
     | 
    
         | 
| 
       147 
147 
     | 
    
         
             
                  def build(origin_obj)
         
     | 
| 
       148 
148 
     | 
    
         
             
                    value.each_with_index.reduce(origin_obj) do |obj, (ns, idx)|
         
     | 
| 
       149 
     | 
    
         
            -
                      obj[idx.zero? ?  
     | 
| 
      
 149 
     | 
    
         
            +
                      obj[idx.zero? ? TypeResolver.export_key(ns) : ns]
         
     | 
| 
       150 
150 
     | 
    
         
             
                    end
         
     | 
| 
       151 
151 
     | 
    
         
             
                  end
         
     | 
| 
       152 
152 
     | 
    
         | 
| 
         @@ -174,7 +174,7 @@ module GraphQL::Stitching 
     | 
|
| 
       174 
174 
     | 
    
         
             
                  # Parses an argument template string into resolver arguments via schema casting.
         
     | 
| 
       175 
175 
     | 
    
         
             
                  # @param template [String] the template string to parse.
         
     | 
| 
       176 
176 
     | 
    
         
             
                  # @param field_def [GraphQL::Schema::FieldDefinition] a field definition providing arguments schema.
         
     | 
| 
       177 
     | 
    
         
            -
                  # @return [[GraphQL::Stitching:: 
     | 
| 
      
 177 
     | 
    
         
            +
                  # @return [[GraphQL::Stitching::TypeResolver::Argument]] an array of resolver arguments.
         
     | 
| 
       178 
178 
     | 
    
         
             
                  def parse_arguments_with_field(template, field_def)
         
     | 
| 
       179 
179 
     | 
    
         
             
                    ast = parse_arg_defs(template)
         
     | 
| 
       180 
180 
     | 
    
         
             
                    args = build_argument_set(ast, field_def.arguments)
         
     | 
| 
         @@ -196,7 +196,7 @@ module GraphQL::Stitching 
     | 
|
| 
       196 
196 
     | 
    
         
             
                  # Parses an argument template string into resolver arguments via SDL casting.
         
     | 
| 
       197 
197 
     | 
    
         
             
                  # @param template [String] the template string to parse.
         
     | 
| 
       198 
198 
     | 
    
         
             
                  # @param type_defs [String] the type definition string declaring argument types.
         
     | 
| 
       199 
     | 
    
         
            -
                  # @return [[GraphQL::Stitching:: 
     | 
| 
      
 199 
     | 
    
         
            +
                  # @return [[GraphQL::Stitching::TypeResolver::Argument]] an array of resolver arguments.
         
     | 
| 
       200 
200 
     | 
    
         
             
                  def parse_arguments_with_type_defs(template, type_defs)
         
     | 
| 
       201 
201 
     | 
    
         
             
                    type_map = parse_type_defs(type_defs)
         
     | 
| 
       202 
202 
     | 
    
         
             
                    parse_arg_defs(template).map { build_argument(_1, type_struct: type_map[_1.name]) }
         
     | 
| 
         @@ -1,12 +1,12 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # frozen_string_literal: true
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            require_relative " 
     | 
| 
       4 
     | 
    
         
            -
            require_relative " 
     | 
| 
      
 3 
     | 
    
         
            +
            require_relative "type_resolver/arguments"
         
     | 
| 
      
 4 
     | 
    
         
            +
            require_relative "type_resolver/keys"
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
6 
     | 
    
         
             
            module GraphQL
         
     | 
| 
       7 
7 
     | 
    
         
             
              module Stitching
         
     | 
| 
       8 
8 
     | 
    
         
             
                # Defines a type resolver query that provides direct access to an entity type.
         
     | 
| 
       9 
     | 
    
         
            -
                class  
     | 
| 
      
 9 
     | 
    
         
            +
                class TypeResolver
         
     | 
| 
       10 
10 
     | 
    
         
             
                  extend ArgumentsParser
         
     | 
| 
       11 
11 
     | 
    
         
             
                  extend KeysParser
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
         @@ -47,7 +47,7 @@ module GraphQL 
     | 
|
| 
       47 
47 
     | 
    
         
             
                  end
         
     | 
| 
       48 
48 
     | 
    
         | 
| 
       49 
49 
     | 
    
         
             
                  def version
         
     | 
| 
       50 
     | 
    
         
            -
                    @version ||=  
     | 
| 
      
 50 
     | 
    
         
            +
                    @version ||= Stitching.digest.call("#{Stitching::VERSION}/#{as_json.to_json}")
         
     | 
| 
       51 
51 
     | 
    
         
             
                  end
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
       53 
53 
     | 
    
         
             
                  def ==(other)
         
     | 
    
        data/lib/graphql/stitching.rb
    CHANGED
    
    | 
         @@ -25,14 +25,31 @@ module GraphQL 
     | 
|
| 
       25 
25 
     | 
    
         
             
                class StitchingError < StandardError; end
         
     | 
| 
       26 
26 
     | 
    
         
             
                class CompositionError < StitchingError; end
         
     | 
| 
       27 
27 
     | 
    
         
             
                class ValidationError < CompositionError; end
         
     | 
| 
      
 28 
     | 
    
         
            +
                class DocumentError < StandardError
         
     | 
| 
      
 29 
     | 
    
         
            +
                  def initialize(element)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    super("Invalid #{element} encountered in document")
         
     | 
| 
      
 31 
     | 
    
         
            +
                  end
         
     | 
| 
      
 32 
     | 
    
         
            +
                end
         
     | 
| 
       28 
33 
     | 
    
         | 
| 
       29 
34 
     | 
    
         
             
                class << self
         
     | 
| 
      
 35 
     | 
    
         
            +
                  attr_writer :stitch_directive
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  # Proc used to compute digests; uses SHA2 by default.
         
     | 
| 
      
 38 
     | 
    
         
            +
                  # @returns [Proc] proc used to compute digests.
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def digest(&block)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    if block_given?
         
     | 
| 
      
 41 
     | 
    
         
            +
                      @digest = block
         
     | 
| 
      
 42 
     | 
    
         
            +
                    else
         
     | 
| 
      
 43 
     | 
    
         
            +
                      @digest ||= ->(str) { Digest::SHA2.hexdigest(str) }
         
     | 
| 
      
 44 
     | 
    
         
            +
                    end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                  # Name of the directive used to mark type resolvers.
         
     | 
| 
      
 48 
     | 
    
         
            +
                  # @returns [String] name of the type resolver directive.
         
     | 
| 
       30 
49 
     | 
    
         
             
                  def stitch_directive
         
     | 
| 
       31 
50 
     | 
    
         
             
                    @stitch_directive ||= "stitch"
         
     | 
| 
       32 
51 
     | 
    
         
             
                  end
         
     | 
| 
       33 
52 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
                  attr_writer :stitch_directive
         
     | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
53 
     | 
    
         
             
                  # Names of stitching directives to omit from the composed supergraph.
         
     | 
| 
       37 
54 
     | 
    
         
             
                  # @returns [Array<String>] list of stitching directive names.
         
     | 
| 
       38 
55 
     | 
    
         
             
                  def stitching_directive_names
         
     | 
| 
         @@ -50,6 +67,6 @@ require_relative "stitching/http_executable" 
     | 
|
| 
       50 
67 
     | 
    
         
             
            require_relative "stitching/plan"
         
     | 
| 
       51 
68 
     | 
    
         
             
            require_relative "stitching/planner"
         
     | 
| 
       52 
69 
     | 
    
         
             
            require_relative "stitching/request"
         
     | 
| 
       53 
     | 
    
         
            -
            require_relative "stitching/ 
     | 
| 
      
 70 
     | 
    
         
            +
            require_relative "stitching/type_resolver"
         
     | 
| 
       54 
71 
     | 
    
         
             
            require_relative "stitching/util"
         
     | 
| 
       55 
72 
     | 
    
         
             
            require_relative "stitching/version"
         
     |