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
|