graphql-stitching 1.4.1 → 1.4.3
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/README.md +12 -6
- data/docs/mechanics.md +2 -2
- data/lib/graphql/stitching/composer/validate_resolvers.rb +4 -2
- data/lib/graphql/stitching/composer.rb +2 -2
- data/lib/graphql/stitching/{shaper.rb → executor/shaper.rb} +2 -2
- data/lib/graphql/stitching/executor.rb +2 -1
- data/lib/graphql/stitching/plan.rb +1 -1
- data/lib/graphql/stitching/{planner_step.rb → planner/step.rb} +3 -3
- data/lib/graphql/stitching/planner.rb +8 -4
- data/lib/graphql/stitching/resolver/keys.rb +1 -1
- data/lib/graphql/stitching/resolver.rb +1 -1
- data/lib/graphql/stitching/supergraph.rb +5 -1
- data/lib/graphql/stitching/version.rb +1 -1
- data/lib/graphql/stitching.rb +1 -3
- metadata +4 -4
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: a72adc399f618790fc1aefe1b6dca07709d45f10cc2936f5c3978d75b5d3f8c2
         | 
| 4 | 
            +
              data.tar.gz: d45d7b73045755a750d6d4334e00e30f33c5124f83c849c24669c98f7912ca92
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 5302083cb9047ad77aa5e6276d02e3bdac8256ef328edb8c72b9248efbb279c48bb3e34b8e220f131d3efa541fdaa1b682fe4622501900defe797217cbc365c8
         | 
| 7 | 
            +
              data.tar.gz: 4e238de4607764406ac52634daafc293c1b5fe672457106ff1070e77bc4d52cdc1ace02ce46ca4cacbcde7648d8a4f2bb8cc0321157dfb3c85c3ec40d5f82e43
         | 
    
        data/README.md
    CHANGED
    
    | @@ -101,7 +101,7 @@ This directive (or [static configuration](#sdl-based-schemas)) is applied to roo | |
| 101 101 |  | 
| 102 102 | 
             
            ```ruby
         | 
| 103 103 | 
             
            products_schema = <<~GRAPHQL
         | 
| 104 | 
            -
              directive @stitch(key: String | 
| 104 | 
            +
              directive @stitch(key: String!, arguments: String) repeatable on FIELD_DEFINITION
         | 
| 105 105 |  | 
| 106 106 | 
             
              type Product {
         | 
| 107 107 | 
             
                id: ID!
         | 
| @@ -114,7 +114,7 @@ products_schema = <<~GRAPHQL | |
| 114 114 | 
             
            GRAPHQL
         | 
| 115 115 |  | 
| 116 116 | 
             
            catalog_schema = <<~GRAPHQL
         | 
| 117 | 
            -
              directive @stitch(key: String | 
| 117 | 
            +
              directive @stitch(key: String!, arguments: String) repeatable on FIELD_DEFINITION
         | 
| 118 118 |  | 
| 119 119 | 
             
              type Product {
         | 
| 120 120 | 
             
                id: ID!
         | 
| @@ -226,7 +226,7 @@ type Query { | |
| 226 226 | 
             
            }
         | 
| 227 227 | 
             
            ```
         | 
| 228 228 |  | 
| 229 | 
            -
            Key insertions are prefixed by `$` and specify a dot-notation path to any selections made by the resolver  | 
| 229 | 
            +
            Key insertions are prefixed by `$` and specify a dot-notation path to any selections made by the resolver key, or `__typename`. This syntax allows sending multiple arguments that intermix stitching keys with complex input shapes and other static values:
         | 
| 230 230 |  | 
| 231 231 | 
             
            ```graphql
         | 
| 232 232 | 
             
            type Product {
         | 
| @@ -237,10 +237,14 @@ input EntityKey { | |
| 237 237 | 
             
              id: ID!
         | 
| 238 238 | 
             
              type: String!
         | 
| 239 239 | 
             
            }
         | 
| 240 | 
            +
            enum EntitySource {
         | 
| 241 | 
            +
              DATABASE
         | 
| 242 | 
            +
              CACHE
         | 
| 243 | 
            +
            }
         | 
| 240 244 |  | 
| 241 245 | 
             
            type Query {
         | 
| 242 | 
            -
              entities(keys: [EntityKey!]!, source:  | 
| 243 | 
            -
                @stitch(key: "id", arguments: "keys: { id: $.id, type: $.__typename }, source:  | 
| 246 | 
            +
              entities(keys: [EntityKey!]!, source: EntitySource = DATABASE): [Entity]!
         | 
| 247 | 
            +
                @stitch(key: "id", arguments: "keys: { id: $.id, type: $.__typename }, source: CACHE")
         | 
| 244 248 | 
             
            }
         | 
| 245 249 | 
             
            ```
         | 
| 246 250 |  | 
| @@ -265,6 +269,7 @@ input CustomFieldLookup { | |
| 265 269 | 
             
              ownerType: String!
         | 
| 266 270 | 
             
              key: String!
         | 
| 267 271 | 
             
            }
         | 
| 272 | 
            +
             | 
| 268 273 | 
             
            type Query {
         | 
| 269 274 | 
             
              customFields(lookups: [CustomFieldLookup!]!): [CustomField]! @stitch(
         | 
| 270 275 | 
             
                key: "owner { id type } key",
         | 
| @@ -320,6 +325,7 @@ class StitchingResolver < GraphQL::Schema::Directive | |
| 320 325 | 
             
              locations FIELD_DEFINITION
         | 
| 321 326 | 
             
              repeatable true
         | 
| 322 327 | 
             
              argument :key, String, required: true
         | 
| 328 | 
            +
              argument :arguments, String, required: false
         | 
| 323 329 | 
             
            end
         | 
| 324 330 |  | 
| 325 331 | 
             
            class Query < GraphQL::Schema::Object
         | 
| @@ -354,7 +360,7 @@ supergraph = GraphQL::Stitching::Composer.new.perform({ | |
| 354 360 | 
             
                executable: ->() { ... },
         | 
| 355 361 | 
             
                stitch: [
         | 
| 356 362 | 
             
                  { field_name: "productById", key: "id" },
         | 
| 357 | 
            -
                  { field_name: "productBySku", key: "sku" },
         | 
| 363 | 
            +
                  { field_name: "productBySku", key: "sku", arguments: "mySku: $.sku" },
         | 
| 358 364 | 
             
                ]
         | 
| 359 365 | 
             
              },
         | 
| 360 366 | 
             
              # ...
         | 
    
        data/docs/mechanics.md
    CHANGED
    
    | @@ -90,7 +90,7 @@ class GraphQlController | |
| 90 90 | 
             
                  variables: params[:variables],
         | 
| 91 91 | 
             
                  operation_name: params[:operation_name]
         | 
| 92 92 | 
             
                )
         | 
| 93 | 
            -
              end | 
| 93 | 
            +
              end
         | 
| 94 94 | 
             
            end
         | 
| 95 95 | 
             
            ```
         | 
| 96 96 |  | 
| @@ -345,4 +345,4 @@ type Query { | |
| 345 345 | 
             
            }
         | 
| 346 346 | 
             
            ```
         | 
| 347 347 |  | 
| 348 | 
            -
            In this graph, `Widget` is a merged type without a resolver query in location C. This works because all of its fields are resolvable in other locations; that means location C can provide outbound representations of this type without ever needing to resolve inbound requests for it. Outbound types do still require a shared key field (such as `id` above) that allow them to join with data in other resolver locations (such as `price` above).
         | 
| 348 | 
            +
            In this graph, `Widget` is a merged type without a resolver query in location C. This works because all of its fields are resolvable in other locations; that means location C can provide outbound representations of this type without ever needing to resolve inbound requests for it. Outbound types do still require a shared key field (such as `id` above) that allow them to join with data in other resolver locations (such as `price` above). Support for this pattern is limited to single-field keys, [composite keys](../README.md#composite-type-keys) require a resolver definition.
         | 
| @@ -55,8 +55,10 @@ module GraphQL::Stitching | |
| 55 55 | 
             
                    end
         | 
| 56 56 |  | 
| 57 57 | 
             
                    # All locations of a merged type must include at least one resolver key
         | 
| 58 | 
            -
                    supergraph.fields_by_type_and_location[type.graphql_name]. | 
| 59 | 
            -
                       | 
| 58 | 
            +
                    supergraph.fields_by_type_and_location[type.graphql_name].each do |location, field_names|
         | 
| 59 | 
            +
                      has_resolver_key = resolver_keys.any? { _1.locations.include?(location) }
         | 
| 60 | 
            +
                      has_primitive_match = resolver_keys.any? { field_names.include?(_1.primitive_name) }
         | 
| 61 | 
            +
                      unless has_resolver_key || has_primitive_match
         | 
| 60 62 | 
             
                        raise ValidationError, "A resolver key is required for `#{type.graphql_name}` in #{location} to join with other locations."
         | 
| 61 63 | 
             
                      end
         | 
| 62 64 | 
             
                    end
         | 
| @@ -557,7 +557,7 @@ module GraphQL | |
| 557 557 | 
             
                            argument = if subgraph_field.arguments.size == 1
         | 
| 558 558 | 
             
                              subgraph_field.arguments.values.first
         | 
| 559 559 | 
             
                            else
         | 
| 560 | 
            -
                              subgraph_field.arguments[key. | 
| 560 | 
            +
                              subgraph_field.arguments[key.primitive_name]
         | 
| 561 561 | 
             
                            end
         | 
| 562 562 |  | 
| 563 563 | 
             
                            unless argument
         | 
| @@ -565,7 +565,7 @@ module GraphQL | |
| 565 565 | 
             
                                "An argument mapping is required for unmatched names and composite keys."
         | 
| 566 566 | 
             
                            end
         | 
| 567 567 |  | 
| 568 | 
            -
                            "#{argument.graphql_name}: $.#{key. | 
| 568 | 
            +
                            "#{argument.graphql_name}: $.#{key.primitive_name}"
         | 
| 569 569 | 
             
                          end
         | 
| 570 570 |  | 
| 571 571 | 
             
                          arguments = Resolver.parse_arguments_with_field(arguments_format, subgraph_field)
         | 
| @@ -1,8 +1,8 @@ | |
| 1 1 | 
             
            # typed: false
         | 
| 2 2 | 
             
            # frozen_string_literal: true
         | 
| 3 3 |  | 
| 4 | 
            -
            module GraphQL
         | 
| 5 | 
            -
               | 
| 4 | 
            +
            module GraphQL::Stitching
         | 
| 5 | 
            +
              class Executor
         | 
| 6 6 | 
             
                # Shapes the final results payload to the request selection and schema definition.
         | 
| 7 7 | 
             
                # This eliminates unrequested export selections and applies null bubbling.
         | 
| 8 8 | 
             
                # @api private
         | 
| @@ -3,6 +3,7 @@ | |
| 3 3 | 
             
            require "json"
         | 
| 4 4 | 
             
            require_relative "./executor/resolver_source"
         | 
| 5 5 | 
             
            require_relative "./executor/root_source"
         | 
| 6 | 
            +
            require_relative "./executor/shaper"
         | 
| 6 7 |  | 
| 7 8 | 
             
            module GraphQL
         | 
| 8 9 | 
             
              module Stitching
         | 
| @@ -33,7 +34,7 @@ module GraphQL | |
| 33 34 | 
             
                    result = {}
         | 
| 34 35 |  | 
| 35 36 | 
             
                    if @data && @data.length > 0
         | 
| 36 | 
            -
                      result["data"] = raw ? @data :  | 
| 37 | 
            +
                      result["data"] = raw ? @data : Shaper.new(@request).perform!(@data)
         | 
| 37 38 | 
             
                    end
         | 
| 38 39 |  | 
| 39 40 | 
             
                    if @errors.length > 0
         | 
| @@ -1,11 +1,11 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            module GraphQL
         | 
| 4 | 
            -
               | 
| 3 | 
            +
            module GraphQL::Stitching
         | 
| 4 | 
            +
              class Planner
         | 
| 5 5 | 
             
                # A planned step in the sequence of stitching entrypoints together.
         | 
| 6 6 | 
             
                # This is a mutable object that may change throughout the planning process.
         | 
| 7 7 | 
             
                # It ultimately builds an immutable Plan::Op at the end of planning.
         | 
| 8 | 
            -
                class  | 
| 8 | 
            +
                class Step
         | 
| 9 9 | 
             
                  GRAPHQL_PRINTER = GraphQL::Language::Printer.new
         | 
| 10 10 |  | 
| 11 11 | 
             
                  attr_reader :index, :location, :parent_type, :operation_type, :path
         | 
| @@ -1,5 +1,7 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            require_relative "./planner/step"
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            module GraphQL
         | 
| 4 6 | 
             
              module Stitching
         | 
| 5 7 | 
             
                class Planner
         | 
| @@ -85,7 +87,7 @@ module GraphQL | |
| 85 87 | 
             
                    end
         | 
| 86 88 |  | 
| 87 89 | 
             
                    if step.nil?
         | 
| 88 | 
            -
                      @steps_by_entrypoint[entrypoint] =  | 
| 90 | 
            +
                      @steps_by_entrypoint[entrypoint] = Step.new(
         | 
| 89 91 | 
             
                        index: next_index,
         | 
| 90 92 | 
             
                        after: parent_index,
         | 
| 91 93 | 
             
                        location: location,
         | 
| @@ -261,7 +263,7 @@ module GraphQL | |
| 261 263 |  | 
| 262 264 | 
             
                    # B.4) Add a `__typename` export to abstracts and types that implement
         | 
| 263 265 | 
             
                    # fragments so that resolved type information is available during execution.
         | 
| 264 | 
            -
                    if requires_typename
         | 
| 266 | 
            +
                    if requires_typename && !locale_selections.include?(Resolver::TYPENAME_EXPORT_NODE)
         | 
| 265 267 | 
             
                      locale_selections << Resolver::TYPENAME_EXPORT_NODE
         | 
| 266 268 | 
             
                    end
         | 
| 267 269 |  | 
| @@ -277,6 +279,10 @@ module GraphQL | |
| 277 279 | 
             
                        route.reduce(locale_selections) do |parent_selections, resolver|
         | 
| 278 280 | 
             
                          # E.1) Add the key of each resolver query into the prior location's selection set.
         | 
| 279 281 | 
             
                          parent_selections.push(*resolver.key.export_nodes) if resolver.key
         | 
| 282 | 
            +
                          parent_selections.uniq! do |node|
         | 
| 283 | 
            +
                            export_node = node.is_a?(GraphQL::Language::Nodes::Field) && Resolver.export_key?(node.alias)
         | 
| 284 | 
            +
                            export_node ? node.alias : node
         | 
| 285 | 
            +
                          end
         | 
| 280 286 |  | 
| 281 287 | 
             
                          # E.2) Add a planner step for each new entrypoint location.
         | 
| 282 288 | 
             
                          add_step(
         | 
| @@ -289,8 +295,6 @@ module GraphQL | |
| 289 295 | 
             
                          ).selections
         | 
| 290 296 | 
             
                        end
         | 
| 291 297 | 
             
                      end
         | 
| 292 | 
            -
             | 
| 293 | 
            -
                      locale_selections.uniq! { _1.alias || _1.name }
         | 
| 294 298 | 
             
                    end
         | 
| 295 299 |  | 
| 296 300 | 
             
                    locale_selections
         | 
| @@ -147,7 +147,11 @@ module GraphQL | |
| 147 147 | 
             
                  def possible_keys_for_type_and_location(type_name, location)
         | 
| 148 148 | 
             
                    possible_keys_by_type = @possible_keys_by_type_and_location[type_name] ||= {}
         | 
| 149 149 | 
             
                    possible_keys_by_type[location] ||= possible_keys_for_type(type_name).select do |key|
         | 
| 150 | 
            -
                      key.locations.include?(location)
         | 
| 150 | 
            +
                      next true if key.locations.include?(location)
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                      # Outbound-only locations without resolver queries may dynamically match primitive keys
         | 
| 153 | 
            +
                      location_fields = fields_by_type_and_location[type_name][location] || GraphQL::Stitching::EMPTY_ARRAY
         | 
| 154 | 
            +
                      location_fields.include?(key.primitive_name)
         | 
| 151 155 | 
             
                    end
         | 
| 152 156 | 
             
                  end
         | 
| 153 157 |  | 
    
        data/lib/graphql/stitching.rb
    CHANGED
    
    | @@ -26,16 +26,14 @@ module GraphQL | |
| 26 26 | 
             
            end
         | 
| 27 27 |  | 
| 28 28 | 
             
            require_relative "stitching/supergraph"
         | 
| 29 | 
            -
            require_relative "stitching/resolver"
         | 
| 30 29 | 
             
            require_relative "stitching/client"
         | 
| 31 30 | 
             
            require_relative "stitching/composer"
         | 
| 32 31 | 
             
            require_relative "stitching/executor"
         | 
| 33 32 | 
             
            require_relative "stitching/http_executable"
         | 
| 34 33 | 
             
            require_relative "stitching/plan"
         | 
| 35 | 
            -
            require_relative "stitching/planner_step"
         | 
| 36 34 | 
             
            require_relative "stitching/planner"
         | 
| 37 35 | 
             
            require_relative "stitching/request"
         | 
| 38 | 
            -
            require_relative "stitching/ | 
| 36 | 
            +
            require_relative "stitching/resolver"
         | 
| 39 37 | 
             
            require_relative "stitching/skip_include"
         | 
| 40 38 | 
             
            require_relative "stitching/util"
         | 
| 41 39 | 
             
            require_relative "stitching/version"
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: graphql-stitching
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 1.4. | 
| 4 | 
            +
              version: 1.4.3
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Greg MacWilliam
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2024-07- | 
| 11 | 
            +
            date: 2024-07-05 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: graphql
         | 
| @@ -120,15 +120,15 @@ files: | |
| 120 120 | 
             
            - lib/graphql/stitching/executor.rb
         | 
| 121 121 | 
             
            - lib/graphql/stitching/executor/resolver_source.rb
         | 
| 122 122 | 
             
            - lib/graphql/stitching/executor/root_source.rb
         | 
| 123 | 
            +
            - lib/graphql/stitching/executor/shaper.rb
         | 
| 123 124 | 
             
            - lib/graphql/stitching/http_executable.rb
         | 
| 124 125 | 
             
            - lib/graphql/stitching/plan.rb
         | 
| 125 126 | 
             
            - lib/graphql/stitching/planner.rb
         | 
| 126 | 
            -
            - lib/graphql/stitching/ | 
| 127 | 
            +
            - lib/graphql/stitching/planner/step.rb
         | 
| 127 128 | 
             
            - lib/graphql/stitching/request.rb
         | 
| 128 129 | 
             
            - lib/graphql/stitching/resolver.rb
         | 
| 129 130 | 
             
            - lib/graphql/stitching/resolver/arguments.rb
         | 
| 130 131 | 
             
            - lib/graphql/stitching/resolver/keys.rb
         | 
| 131 | 
            -
            - lib/graphql/stitching/shaper.rb
         | 
| 132 132 | 
             
            - lib/graphql/stitching/skip_include.rb
         | 
| 133 133 | 
             
            - lib/graphql/stitching/supergraph.rb
         | 
| 134 134 | 
             
            - lib/graphql/stitching/supergraph/key_directive.rb
         |