@apollo/gateway 0.43.1 → 2.0.0-alpha.1
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.
- package/CHANGELOG.md +2 -4
- package/LICENSE +95 -0
- package/dist/executeQueryPlan.d.ts +2 -3
- package/dist/executeQueryPlan.d.ts.map +1 -1
- package/dist/executeQueryPlan.js +2 -27
- package/dist/executeQueryPlan.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -41
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
- package/src/__tests__/build-query-plan.feature +34 -24
- package/src/__tests__/buildQueryPlan.test.ts +76 -840
- package/src/__tests__/executeQueryPlan.test.ts +543 -537
- package/src/__tests__/execution-utils.ts +20 -26
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +26 -4
- package/src/__tests__/gateway/reporting.test.ts +0 -14
- package/src/__tests__/integration/abstract-types.test.ts +40 -52
- package/src/__tests__/integration/boolean.test.ts +3 -1
- package/src/__tests__/integration/complex-key.test.ts +40 -55
- package/src/__tests__/integration/configuration.test.ts +5 -5
- package/src/__tests__/integration/custom-directives.test.ts +8 -2
- package/src/__tests__/integration/multiple-key.test.ts +10 -11
- package/src/__tests__/integration/requires.test.ts +2 -2
- package/src/__tests__/integration/scope.test.ts +19 -30
- package/src/__tests__/integration/value-types.test.ts +31 -31
- package/src/__tests__/loadSupergraphSdlFromStorage.test.ts +217 -142
- package/src/__tests__/queryPlanCucumber.test.ts +4 -18
- package/src/core/__tests__/core.test.ts +1 -0
- package/src/executeQueryPlan.ts +1 -32
- package/src/index.ts +39 -80
- package/src/utilities/__tests__/cleanErrorOfInaccessibleElements.test.ts +4 -4
- package/LICENSE.md +0 -21
- package/dist/core/index.d.ts +0 -13
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js +0 -43
- package/dist/core/index.js.map +0 -1
- package/src/__tests__/build-query-plan-fragmentization.feature +0 -282
- package/src/core/index.ts +0 -51
|
@@ -36,313 +36,388 @@ describe('loadSupergraphSdlFromStorage', () => {
|
|
|
36
36
|
Object {
|
|
37
37
|
"id": "originalId-1234",
|
|
38
38
|
"supergraphSdl": "schema
|
|
39
|
-
@core(feature: \\"https://specs.apollo.dev/core/v0.2\\")
|
|
40
|
-
@core(feature: \\"https://specs.apollo.dev/join/v0.
|
|
39
|
+
@core(feature: \\"https://specs.apollo.dev/core/v0.2\\")
|
|
40
|
+
@core(feature: \\"https://specs.apollo.dev/join/v0.2\\", for: EXECUTION)
|
|
41
41
|
@core(feature: \\"https://specs.apollo.dev/tag/v0.1\\")
|
|
42
42
|
{
|
|
43
43
|
query: Query
|
|
44
44
|
mutation: Mutation
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
directive @core(
|
|
47
|
+
directive @core(feature: String!, as: String, for: core__Purpose) repeatable on SCHEMA
|
|
48
48
|
|
|
49
|
-
directive @join__field(graph: join__Graph, provides: join__FieldSet,
|
|
49
|
+
directive @join__field(graph: join__Graph!, requires: join__FieldSet, provides: join__FieldSet, type: String, external: Boolean) repeatable on FIELD_DEFINITION | INPUT_FIELD_DEFINITION
|
|
50
50
|
|
|
51
51
|
directive @join__graph(name: String!, url: String!) on ENUM_VALUE
|
|
52
52
|
|
|
53
|
-
directive @
|
|
53
|
+
directive @join__implements(graph: join__Graph!, interface: String!) repeatable on OBJECT | INTERFACE
|
|
54
54
|
|
|
55
|
-
directive @join__type(graph: join__Graph!, key: join__FieldSet) repeatable on INTERFACE |
|
|
55
|
+
directive @join__type(graph: join__Graph!, key: join__FieldSet, extension: Boolean! = false) repeatable on OBJECT | INTERFACE | UNION | ENUM | INPUT_OBJECT | SCALAR
|
|
56
56
|
|
|
57
57
|
directive @stream on FIELD
|
|
58
58
|
|
|
59
|
-
directive @tag(name: String!) repeatable on FIELD_DEFINITION |
|
|
59
|
+
directive @tag(name: String!) repeatable on FIELD_DEFINITION | OBJECT | INTERFACE | UNION
|
|
60
60
|
|
|
61
61
|
directive @transform(from: String!) on FIELD
|
|
62
62
|
|
|
63
63
|
union AccountType
|
|
64
|
+
@join__type(graph: ACCOUNTS)
|
|
64
65
|
@tag(name: \\"from-accounts\\")
|
|
65
|
-
|
|
66
|
+
= PasswordAccount | SMSAccount
|
|
66
67
|
|
|
67
|
-
type Amazon
|
|
68
|
+
type Amazon
|
|
69
|
+
@join__type(graph: PRODUCT)
|
|
70
|
+
{
|
|
68
71
|
referrer: String
|
|
69
72
|
}
|
|
70
73
|
|
|
71
|
-
union Body
|
|
74
|
+
union Body
|
|
75
|
+
@join__type(graph: DOCUMENTS)
|
|
76
|
+
= Image | Text
|
|
72
77
|
|
|
73
78
|
type Book implements Product
|
|
74
|
-
@
|
|
79
|
+
@join__implements(graph: INVENTORY, interface: \\"Product\\")
|
|
80
|
+
@join__implements(graph: PRODUCT, interface: \\"Product\\")
|
|
81
|
+
@join__implements(graph: REVIEWS, interface: \\"Product\\")
|
|
75
82
|
@join__type(graph: BOOKS, key: \\"isbn\\")
|
|
76
|
-
@join__type(graph: INVENTORY, key: \\"isbn\\")
|
|
77
|
-
@join__type(graph: PRODUCT, key: \\"isbn\\")
|
|
78
|
-
@join__type(graph: REVIEWS, key: \\"isbn\\")
|
|
83
|
+
@join__type(graph: INVENTORY, key: \\"isbn\\", extension: true)
|
|
84
|
+
@join__type(graph: PRODUCT, key: \\"isbn\\", extension: true)
|
|
85
|
+
@join__type(graph: REVIEWS, key: \\"isbn\\", extension: true)
|
|
79
86
|
{
|
|
80
|
-
|
|
87
|
+
isbn: String!
|
|
88
|
+
title: String @join__field(graph: BOOKS) @join__field(graph: PRODUCT, external: true)
|
|
89
|
+
year: Int @join__field(graph: BOOKS) @join__field(graph: PRODUCT, external: true)
|
|
90
|
+
similarBooks: [Book]! @join__field(graph: BOOKS) @join__field(graph: REVIEWS, external: true)
|
|
91
|
+
metadata: [MetadataOrError] @join__field(graph: BOOKS)
|
|
81
92
|
inStock: Boolean @join__field(graph: INVENTORY)
|
|
82
93
|
isCheckedOut: Boolean @join__field(graph: INVENTORY)
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
upc: String! @join__field(graph: PRODUCT)
|
|
95
|
+
sku: String! @join__field(graph: PRODUCT)
|
|
85
96
|
name(delimeter: String = \\" \\"): String @join__field(graph: PRODUCT, requires: \\"title year\\")
|
|
86
97
|
price: String @join__field(graph: PRODUCT)
|
|
87
|
-
|
|
98
|
+
details: ProductDetailsBook @join__field(graph: PRODUCT)
|
|
88
99
|
reviews: [Review] @join__field(graph: REVIEWS)
|
|
89
|
-
|
|
90
|
-
sku: String! @join__field(graph: PRODUCT)
|
|
91
|
-
title: String @join__field(graph: BOOKS)
|
|
92
|
-
upc: String! @join__field(graph: PRODUCT)
|
|
93
|
-
year: Int @join__field(graph: BOOKS)
|
|
100
|
+
relatedReviews: [Review!]! @join__field(graph: REVIEWS, requires: \\"similarBooks { isbn }\\")
|
|
94
101
|
}
|
|
95
102
|
|
|
96
|
-
union Brand
|
|
103
|
+
union Brand
|
|
104
|
+
@join__type(graph: PRODUCT)
|
|
105
|
+
= Ikea | Amazon
|
|
97
106
|
|
|
98
|
-
enum CacheControlScope
|
|
99
|
-
|
|
107
|
+
enum CacheControlScope
|
|
108
|
+
@join__type(graph: ACCOUNTS)
|
|
109
|
+
@join__type(graph: BOOKS)
|
|
110
|
+
@join__type(graph: PRODUCT)
|
|
111
|
+
{
|
|
100
112
|
PUBLIC
|
|
113
|
+
PRIVATE
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
type Car implements Vehicle
|
|
104
|
-
@
|
|
117
|
+
@join__implements(graph: PRODUCT, interface: \\"Vehicle\\")
|
|
118
|
+
@join__implements(graph: REVIEWS, interface: \\"Vehicle\\")
|
|
105
119
|
@join__type(graph: PRODUCT, key: \\"id\\")
|
|
106
|
-
@join__type(graph: REVIEWS, key: \\"id\\")
|
|
120
|
+
@join__type(graph: REVIEWS, key: \\"id\\", extension: true)
|
|
107
121
|
{
|
|
122
|
+
id: String!
|
|
108
123
|
description: String @join__field(graph: PRODUCT)
|
|
109
|
-
|
|
110
|
-
price: String @join__field(graph: PRODUCT)
|
|
124
|
+
price: String @join__field(graph: PRODUCT) @join__field(graph: REVIEWS, external: true)
|
|
111
125
|
retailPrice: String @join__field(graph: REVIEWS, requires: \\"price\\")
|
|
112
126
|
}
|
|
113
127
|
|
|
114
|
-
|
|
128
|
+
enum core__Purpose {
|
|
129
|
+
\\"\\"\\"
|
|
130
|
+
\`SECURITY\` features provide metadata necessary to securely resolve fields.
|
|
131
|
+
\\"\\"\\"
|
|
132
|
+
SECURITY
|
|
133
|
+
|
|
134
|
+
\\"\\"\\"
|
|
135
|
+
\`EXECUTION\` features provide metadata necessary for operation execution.
|
|
136
|
+
\\"\\"\\"
|
|
137
|
+
EXECUTION
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
type Error
|
|
141
|
+
@join__type(graph: BOOKS)
|
|
142
|
+
@join__type(graph: PRODUCT)
|
|
143
|
+
@join__type(graph: REVIEWS)
|
|
144
|
+
{
|
|
115
145
|
code: Int
|
|
116
146
|
message: String
|
|
117
147
|
}
|
|
118
148
|
|
|
119
149
|
type Furniture implements Product
|
|
120
|
-
@
|
|
150
|
+
@join__implements(graph: INVENTORY, interface: \\"Product\\")
|
|
151
|
+
@join__implements(graph: PRODUCT, interface: \\"Product\\")
|
|
152
|
+
@join__implements(graph: REVIEWS, interface: \\"Product\\")
|
|
153
|
+
@join__type(graph: INVENTORY, key: \\"sku\\", extension: true)
|
|
121
154
|
@join__type(graph: PRODUCT, key: \\"upc\\")
|
|
122
155
|
@join__type(graph: PRODUCT, key: \\"sku\\")
|
|
123
|
-
@join__type(graph:
|
|
124
|
-
@join__type(graph: REVIEWS, key: \\"upc\\")
|
|
156
|
+
@join__type(graph: REVIEWS, key: \\"upc\\", extension: true)
|
|
125
157
|
{
|
|
126
|
-
|
|
127
|
-
details: ProductDetailsFurniture @join__field(graph: PRODUCT)
|
|
158
|
+
sku: String! @join__field(graph: INVENTORY) @join__field(graph: PRODUCT)
|
|
128
159
|
inStock: Boolean @join__field(graph: INVENTORY)
|
|
129
160
|
isHeavy: Boolean @join__field(graph: INVENTORY)
|
|
130
|
-
|
|
161
|
+
upc: String! @join__field(graph: PRODUCT) @join__field(graph: REVIEWS)
|
|
131
162
|
name: String @join__field(graph: PRODUCT)
|
|
132
163
|
price: String @join__field(graph: PRODUCT)
|
|
164
|
+
brand: Brand @join__field(graph: PRODUCT)
|
|
165
|
+
metadata: [MetadataOrError] @join__field(graph: PRODUCT)
|
|
166
|
+
details: ProductDetailsFurniture @join__field(graph: PRODUCT)
|
|
133
167
|
reviews: [Review] @join__field(graph: REVIEWS)
|
|
134
|
-
sku: String! @join__field(graph: PRODUCT)
|
|
135
|
-
upc: String! @join__field(graph: PRODUCT)
|
|
136
168
|
}
|
|
137
169
|
|
|
138
|
-
type Ikea
|
|
170
|
+
type Ikea
|
|
171
|
+
@join__type(graph: PRODUCT)
|
|
172
|
+
{
|
|
139
173
|
asile: Int
|
|
140
174
|
}
|
|
141
175
|
|
|
142
|
-
type Image implements NamedObject
|
|
143
|
-
|
|
176
|
+
type Image implements NamedObject
|
|
177
|
+
@join__implements(graph: DOCUMENTS, interface: \\"NamedObject\\")
|
|
178
|
+
@join__type(graph: DOCUMENTS)
|
|
179
|
+
{
|
|
144
180
|
name: String!
|
|
181
|
+
attributes: ImageAttributes!
|
|
145
182
|
}
|
|
146
183
|
|
|
147
|
-
type ImageAttributes
|
|
184
|
+
type ImageAttributes
|
|
185
|
+
@join__type(graph: DOCUMENTS)
|
|
186
|
+
{
|
|
148
187
|
url: String!
|
|
149
188
|
}
|
|
150
189
|
|
|
151
|
-
scalar
|
|
190
|
+
scalar join__FieldSet
|
|
152
191
|
|
|
153
|
-
|
|
192
|
+
enum join__Graph {
|
|
193
|
+
ACCOUNTS @join__graph(name: \\"accounts\\", url: \\"https://accounts.api.com\\")
|
|
194
|
+
BOOKS @join__graph(name: \\"books\\", url: \\"https://books.api.com\\")
|
|
195
|
+
DOCUMENTS @join__graph(name: \\"documents\\", url: \\"https://documents.api.com\\")
|
|
196
|
+
INVENTORY @join__graph(name: \\"inventory\\", url: \\"https://inventory.api.com\\")
|
|
197
|
+
PRODUCT @join__graph(name: \\"product\\", url: \\"https://product.api.com\\")
|
|
198
|
+
REVIEWS @join__graph(name: \\"reviews\\", url: \\"https://reviews.api.com\\")
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
scalar JSON
|
|
202
|
+
@join__type(graph: ACCOUNTS)
|
|
203
|
+
@specifiedBy(url: \\"https://json-spec.dev\\")
|
|
204
|
+
|
|
205
|
+
type KeyValue
|
|
206
|
+
@join__type(graph: BOOKS)
|
|
207
|
+
@join__type(graph: PRODUCT)
|
|
208
|
+
@join__type(graph: REVIEWS)
|
|
209
|
+
{
|
|
154
210
|
key: String!
|
|
155
211
|
value: String!
|
|
156
212
|
}
|
|
157
213
|
|
|
158
214
|
type Library
|
|
159
|
-
@
|
|
215
|
+
@join__type(graph: ACCOUNTS, key: \\"id\\", extension: true)
|
|
160
216
|
@join__type(graph: BOOKS, key: \\"id\\")
|
|
161
|
-
@join__type(graph: ACCOUNTS, key: \\"id\\")
|
|
162
217
|
{
|
|
163
|
-
id: ID!
|
|
164
|
-
name: String @join__field(graph: BOOKS)
|
|
218
|
+
id: ID!
|
|
219
|
+
name: String @join__field(graph: ACCOUNTS, external: true) @join__field(graph: BOOKS)
|
|
165
220
|
userAccount(id: ID! = 1): User @join__field(graph: ACCOUNTS, requires: \\"name\\")
|
|
166
221
|
}
|
|
167
222
|
|
|
168
|
-
union MetadataOrError
|
|
223
|
+
union MetadataOrError
|
|
224
|
+
@join__type(graph: BOOKS)
|
|
225
|
+
@join__type(graph: PRODUCT)
|
|
226
|
+
@join__type(graph: REVIEWS)
|
|
227
|
+
= KeyValue | Error
|
|
169
228
|
|
|
170
|
-
type Mutation
|
|
171
|
-
|
|
172
|
-
|
|
229
|
+
type Mutation
|
|
230
|
+
@join__type(graph: ACCOUNTS)
|
|
231
|
+
@join__type(graph: REVIEWS)
|
|
232
|
+
{
|
|
233
|
+
login(username: String!, password: String!, userId: String @deprecated(reason: \\"Use username instead\\")): User @join__field(graph: ACCOUNTS)
|
|
173
234
|
reviewProduct(input: ReviewProduct!): Product @join__field(graph: REVIEWS)
|
|
174
235
|
updateReview(review: UpdateReviewInput!): Review @join__field(graph: REVIEWS)
|
|
236
|
+
deleteReview(id: ID!): Boolean @join__field(graph: REVIEWS)
|
|
175
237
|
}
|
|
176
238
|
|
|
177
|
-
type Name
|
|
239
|
+
type Name
|
|
240
|
+
@join__type(graph: ACCOUNTS)
|
|
241
|
+
{
|
|
178
242
|
first: String
|
|
179
243
|
last: String
|
|
180
244
|
}
|
|
181
245
|
|
|
182
|
-
interface NamedObject
|
|
246
|
+
interface NamedObject
|
|
247
|
+
@join__type(graph: DOCUMENTS)
|
|
248
|
+
{
|
|
183
249
|
name: String!
|
|
184
250
|
}
|
|
185
251
|
|
|
186
252
|
type PasswordAccount
|
|
187
|
-
@join__owner(graph: ACCOUNTS)
|
|
188
253
|
@join__type(graph: ACCOUNTS, key: \\"email\\")
|
|
189
254
|
{
|
|
190
|
-
email: String!
|
|
255
|
+
email: String!
|
|
191
256
|
}
|
|
192
257
|
|
|
193
258
|
interface Product
|
|
259
|
+
@join__type(graph: INVENTORY)
|
|
260
|
+
@join__type(graph: PRODUCT)
|
|
261
|
+
@join__type(graph: REVIEWS)
|
|
194
262
|
@tag(name: \\"from-reviews\\")
|
|
195
263
|
{
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
264
|
+
inStock: Boolean @join__field(graph: INVENTORY)
|
|
265
|
+
upc: String! @join__field(graph: PRODUCT)
|
|
266
|
+
sku: String! @join__field(graph: PRODUCT)
|
|
267
|
+
name: String @join__field(graph: PRODUCT)
|
|
268
|
+
price: String @join__field(graph: PRODUCT)
|
|
269
|
+
details: ProductDetails @join__field(graph: PRODUCT)
|
|
270
|
+
reviews: [Review] @join__field(graph: REVIEWS)
|
|
203
271
|
}
|
|
204
272
|
|
|
205
|
-
interface ProductDetails
|
|
273
|
+
interface ProductDetails
|
|
274
|
+
@join__type(graph: PRODUCT)
|
|
275
|
+
{
|
|
206
276
|
country: String
|
|
207
277
|
}
|
|
208
278
|
|
|
209
|
-
type ProductDetailsBook implements ProductDetails
|
|
279
|
+
type ProductDetailsBook implements ProductDetails
|
|
280
|
+
@join__implements(graph: PRODUCT, interface: \\"ProductDetails\\")
|
|
281
|
+
@join__type(graph: PRODUCT)
|
|
282
|
+
{
|
|
210
283
|
country: String
|
|
211
284
|
pages: Int
|
|
212
285
|
}
|
|
213
286
|
|
|
214
|
-
type ProductDetailsFurniture implements ProductDetails
|
|
215
|
-
|
|
287
|
+
type ProductDetailsFurniture implements ProductDetails
|
|
288
|
+
@join__implements(graph: PRODUCT, interface: \\"ProductDetails\\")
|
|
289
|
+
@join__type(graph: PRODUCT)
|
|
290
|
+
{
|
|
216
291
|
country: String
|
|
292
|
+
color: String
|
|
217
293
|
}
|
|
218
294
|
|
|
219
|
-
type Query
|
|
220
|
-
|
|
295
|
+
type Query
|
|
296
|
+
@join__type(graph: ACCOUNTS)
|
|
297
|
+
@join__type(graph: BOOKS)
|
|
298
|
+
@join__type(graph: DOCUMENTS)
|
|
299
|
+
@join__type(graph: INVENTORY)
|
|
300
|
+
@join__type(graph: PRODUCT)
|
|
301
|
+
@join__type(graph: REVIEWS)
|
|
302
|
+
{
|
|
303
|
+
user(id: ID!): User @join__field(graph: ACCOUNTS)
|
|
304
|
+
me: User @join__field(graph: ACCOUNTS)
|
|
221
305
|
book(isbn: String!): Book @join__field(graph: BOOKS)
|
|
222
306
|
books: [Book] @join__field(graph: BOOKS)
|
|
223
307
|
library(id: ID!): Library @join__field(graph: BOOKS)
|
|
224
|
-
|
|
308
|
+
body: Body! @join__field(graph: DOCUMENTS)
|
|
225
309
|
product(upc: String!): Product @join__field(graph: PRODUCT)
|
|
226
|
-
|
|
310
|
+
vehicle(id: String!): Vehicle @join__field(graph: PRODUCT)
|
|
227
311
|
topProducts(first: Int = 5): [Product] @join__field(graph: PRODUCT)
|
|
312
|
+
topCars(first: Int = 5): [Car] @join__field(graph: PRODUCT)
|
|
228
313
|
topReviews(first: Int = 5): [Review] @join__field(graph: REVIEWS)
|
|
229
|
-
user(id: ID!): User @join__field(graph: ACCOUNTS)
|
|
230
|
-
vehicle(id: String!): Vehicle @join__field(graph: PRODUCT)
|
|
231
314
|
}
|
|
232
315
|
|
|
233
316
|
type Review
|
|
234
|
-
@join__owner(graph: REVIEWS)
|
|
235
317
|
@join__type(graph: REVIEWS, key: \\"id\\")
|
|
236
318
|
{
|
|
319
|
+
id: ID!
|
|
320
|
+
body(format: Boolean = false): String
|
|
237
321
|
author: User @join__field(graph: REVIEWS, provides: \\"username\\")
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
metadata: [MetadataOrError] @join__field(graph: REVIEWS)
|
|
241
|
-
product: Product @join__field(graph: REVIEWS)
|
|
322
|
+
product: Product
|
|
323
|
+
metadata: [MetadataOrError]
|
|
242
324
|
}
|
|
243
325
|
|
|
244
|
-
input ReviewProduct
|
|
326
|
+
input ReviewProduct
|
|
327
|
+
@join__type(graph: REVIEWS)
|
|
328
|
+
{
|
|
329
|
+
upc: String!
|
|
245
330
|
body: String!
|
|
246
331
|
stars: Int @deprecated(reason: \\"Stars are no longer in use\\")
|
|
247
|
-
upc: String!
|
|
248
332
|
}
|
|
249
333
|
|
|
250
334
|
type SMSAccount
|
|
251
|
-
@join__owner(graph: ACCOUNTS)
|
|
252
335
|
@join__type(graph: ACCOUNTS, key: \\"number\\")
|
|
253
336
|
{
|
|
254
|
-
number: String
|
|
337
|
+
number: String
|
|
255
338
|
}
|
|
256
339
|
|
|
257
|
-
type Text implements NamedObject
|
|
258
|
-
|
|
340
|
+
type Text implements NamedObject
|
|
341
|
+
@join__implements(graph: DOCUMENTS, interface: \\"NamedObject\\")
|
|
342
|
+
@join__type(graph: DOCUMENTS)
|
|
343
|
+
{
|
|
259
344
|
name: String!
|
|
345
|
+
attributes: TextAttributes!
|
|
260
346
|
}
|
|
261
347
|
|
|
262
|
-
type TextAttributes
|
|
348
|
+
type TextAttributes
|
|
349
|
+
@join__type(graph: DOCUMENTS)
|
|
350
|
+
{
|
|
263
351
|
bold: Boolean
|
|
264
352
|
text: String
|
|
265
353
|
}
|
|
266
354
|
|
|
267
|
-
union Thing
|
|
355
|
+
union Thing
|
|
356
|
+
@join__type(graph: PRODUCT)
|
|
357
|
+
= Car | Ikea
|
|
268
358
|
|
|
269
|
-
input UpdateReviewInput
|
|
270
|
-
|
|
359
|
+
input UpdateReviewInput
|
|
360
|
+
@join__type(graph: REVIEWS)
|
|
361
|
+
{
|
|
271
362
|
id: ID!
|
|
363
|
+
body: String
|
|
272
364
|
}
|
|
273
365
|
|
|
274
366
|
type User
|
|
275
|
-
@join__owner(graph: ACCOUNTS)
|
|
276
367
|
@join__type(graph: ACCOUNTS, key: \\"id\\")
|
|
277
|
-
@join__type(graph: ACCOUNTS, key: \\"username name{first last}\\")
|
|
278
|
-
@join__type(graph: INVENTORY, key: \\"id\\")
|
|
279
|
-
@join__type(graph: PRODUCT, key: \\"id\\")
|
|
280
|
-
@join__type(graph: REVIEWS, key: \\"id\\")
|
|
368
|
+
@join__type(graph: ACCOUNTS, key: \\"username name { first last }\\")
|
|
369
|
+
@join__type(graph: INVENTORY, key: \\"id\\", extension: true)
|
|
370
|
+
@join__type(graph: PRODUCT, key: \\"id\\", extension: true)
|
|
371
|
+
@join__type(graph: REVIEWS, key: \\"id\\", extension: true)
|
|
281
372
|
@tag(name: \\"from-accounts\\")
|
|
282
373
|
@tag(name: \\"from-reviews\\")
|
|
283
374
|
{
|
|
284
|
-
|
|
285
|
-
birthDate(locale: String): String @join__field(graph: ACCOUNTS) @tag(name: \\"admin\\") @tag(name: \\"dev\\")
|
|
286
|
-
goodAddress: Boolean @join__field(graph: REVIEWS, requires: \\"metadata{address}\\")
|
|
287
|
-
goodDescription: Boolean @join__field(graph: INVENTORY, requires: \\"metadata{description}\\")
|
|
288
|
-
id: ID! @join__field(graph: ACCOUNTS) @tag(name: \\"accounts\\") @tag(name: \\"on-external\\")
|
|
289
|
-
metadata: [UserMetadata] @join__field(graph: ACCOUNTS)
|
|
375
|
+
id: ID! @tag(name: \\"accounts\\")
|
|
290
376
|
name: Name @join__field(graph: ACCOUNTS)
|
|
291
|
-
|
|
292
|
-
|
|
377
|
+
username: String @join__field(graph: ACCOUNTS) @join__field(graph: REVIEWS, external: true)
|
|
378
|
+
birthDate(locale: String): String @tag(name: \\"admin\\") @tag(name: \\"dev\\") @join__field(graph: ACCOUNTS)
|
|
379
|
+
account: AccountType @join__field(graph: ACCOUNTS)
|
|
380
|
+
metadata: [UserMetadata] @join__field(graph: ACCOUNTS) @join__field(graph: INVENTORY, external: true) @join__field(graph: REVIEWS, external: true)
|
|
293
381
|
ssn: String @join__field(graph: ACCOUNTS)
|
|
294
|
-
|
|
295
|
-
username: String @join__field(graph: ACCOUNTS)
|
|
382
|
+
goodDescription: Boolean @join__field(graph: INVENTORY, requires: \\"metadata { description }\\")
|
|
296
383
|
vehicle: Vehicle @join__field(graph: PRODUCT)
|
|
384
|
+
thing: Thing @join__field(graph: PRODUCT)
|
|
385
|
+
reviews: [Review] @join__field(graph: REVIEWS)
|
|
386
|
+
numberOfReviews: Int! @join__field(graph: REVIEWS)
|
|
387
|
+
goodAddress: Boolean @join__field(graph: REVIEWS, requires: \\"metadata { address }\\")
|
|
297
388
|
}
|
|
298
389
|
|
|
299
|
-
type UserMetadata
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
390
|
+
type UserMetadata
|
|
391
|
+
@join__type(graph: ACCOUNTS)
|
|
392
|
+
@join__type(graph: INVENTORY)
|
|
393
|
+
@join__type(graph: REVIEWS)
|
|
394
|
+
{
|
|
395
|
+
name: String @join__field(graph: ACCOUNTS)
|
|
396
|
+
address: String @join__field(graph: ACCOUNTS) @join__field(graph: REVIEWS, external: true)
|
|
397
|
+
description: String @join__field(graph: ACCOUNTS) @join__field(graph: INVENTORY, external: true)
|
|
303
398
|
}
|
|
304
399
|
|
|
305
400
|
type Van implements Vehicle
|
|
306
|
-
@
|
|
401
|
+
@join__implements(graph: PRODUCT, interface: \\"Vehicle\\")
|
|
402
|
+
@join__implements(graph: REVIEWS, interface: \\"Vehicle\\")
|
|
307
403
|
@join__type(graph: PRODUCT, key: \\"id\\")
|
|
308
|
-
@join__type(graph: REVIEWS, key: \\"id\\")
|
|
404
|
+
@join__type(graph: REVIEWS, key: \\"id\\", extension: true)
|
|
309
405
|
{
|
|
406
|
+
id: String!
|
|
310
407
|
description: String @join__field(graph: PRODUCT)
|
|
311
|
-
|
|
312
|
-
price: String @join__field(graph: PRODUCT)
|
|
408
|
+
price: String @join__field(graph: PRODUCT) @join__field(graph: REVIEWS, external: true)
|
|
313
409
|
retailPrice: String @join__field(graph: REVIEWS, requires: \\"price\\")
|
|
314
410
|
}
|
|
315
411
|
|
|
316
|
-
interface Vehicle
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
\`EXECUTION\` features provide metadata necessary to for operation execution.
|
|
326
|
-
\\"\\"\\"
|
|
327
|
-
EXECUTION
|
|
328
|
-
|
|
329
|
-
\\"\\"\\"
|
|
330
|
-
\`SECURITY\` features provide metadata necessary to securely resolve fields.
|
|
331
|
-
\\"\\"\\"
|
|
332
|
-
SECURITY
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
scalar join__FieldSet
|
|
336
|
-
|
|
337
|
-
enum join__Graph {
|
|
338
|
-
ACCOUNTS @join__graph(name: \\"accounts\\" url: \\"https://accounts.api.com\\")
|
|
339
|
-
BOOKS @join__graph(name: \\"books\\" url: \\"https://books.api.com\\")
|
|
340
|
-
DOCUMENTS @join__graph(name: \\"documents\\" url: \\"https://documents.api.com\\")
|
|
341
|
-
INVENTORY @join__graph(name: \\"inventory\\" url: \\"https://inventory.api.com\\")
|
|
342
|
-
PRODUCT @join__graph(name: \\"product\\" url: \\"https://product.api.com\\")
|
|
343
|
-
REVIEWS @join__graph(name: \\"reviews\\" url: \\"https://reviews.api.com\\")
|
|
344
|
-
}
|
|
345
|
-
",
|
|
412
|
+
interface Vehicle
|
|
413
|
+
@join__type(graph: PRODUCT)
|
|
414
|
+
@join__type(graph: REVIEWS)
|
|
415
|
+
{
|
|
416
|
+
id: String! @join__field(graph: PRODUCT)
|
|
417
|
+
description: String @join__field(graph: PRODUCT)
|
|
418
|
+
price: String @join__field(graph: PRODUCT)
|
|
419
|
+
retailPrice: String @join__field(graph: REVIEWS)
|
|
420
|
+
}",
|
|
346
421
|
}
|
|
347
422
|
`);
|
|
348
423
|
});
|
|
@@ -2,9 +2,9 @@ import gql from 'graphql-tag';
|
|
|
2
2
|
import { defineFeature, loadFeature } from 'jest-cucumber';
|
|
3
3
|
import { DocumentNode } from 'graphql';
|
|
4
4
|
|
|
5
|
-
import { QueryPlan
|
|
6
|
-
import { buildOperationContext } from '../operationContext';
|
|
5
|
+
import { QueryPlan } from '@apollo/query-planner';
|
|
7
6
|
import { getFederatedTestingSchema } from './execution-utils';
|
|
7
|
+
import { operationFromDocument } from '@apollo/federation-internals';
|
|
8
8
|
|
|
9
9
|
const buildQueryPlanFeature = loadFeature(
|
|
10
10
|
'./gateway-js/src/__tests__/build-query-plan.feature'
|
|
@@ -18,10 +18,9 @@ const features = [
|
|
|
18
18
|
features.forEach((feature) => {
|
|
19
19
|
defineFeature(feature, (test) => {
|
|
20
20
|
feature.scenarios.forEach((scenario) => {
|
|
21
|
-
test(scenario.title, async ({ given,
|
|
21
|
+
test(scenario.title, async ({ given, then }) => {
|
|
22
22
|
let operationDocument: DocumentNode;
|
|
23
23
|
let queryPlan: QueryPlan;
|
|
24
|
-
let options: BuildQueryPlanOptions = { autoFragmentization: false };
|
|
25
24
|
|
|
26
25
|
// throws on composition errors
|
|
27
26
|
const { schema, queryPlanner } = getFederatedTestingSchema();
|
|
@@ -32,21 +31,9 @@ features.forEach((feature) => {
|
|
|
32
31
|
})
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
const whenUsingAutoFragmentization = () => {
|
|
36
|
-
when(/using autofragmentization/i, () => {
|
|
37
|
-
options = { autoFragmentization: true };
|
|
38
|
-
})
|
|
39
|
-
}
|
|
40
|
-
|
|
41
34
|
const thenQueryPlanShouldBe = () => {
|
|
42
35
|
then(/^query plan$/i, (expectedQueryPlan: string) => {
|
|
43
|
-
queryPlan = queryPlanner.buildQueryPlan(
|
|
44
|
-
buildOperationContext({
|
|
45
|
-
schema,
|
|
46
|
-
operationDocument,
|
|
47
|
-
}),
|
|
48
|
-
options
|
|
49
|
-
);
|
|
36
|
+
queryPlan = queryPlanner.buildQueryPlan(operationFromDocument(schema, operationDocument));
|
|
50
37
|
|
|
51
38
|
const parsedExpectedPlan = JSON.parse(expectedQueryPlan);
|
|
52
39
|
|
|
@@ -59,7 +46,6 @@ features.forEach((feature) => {
|
|
|
59
46
|
scenario.steps.forEach(({ stepText }) => {
|
|
60
47
|
const title = stepText.toLocaleLowerCase();
|
|
61
48
|
if (title === "query") givenQuery();
|
|
62
|
-
else if (title === "using autofragmentization") whenUsingAutoFragmentization();
|
|
63
49
|
else if (title === "query plan") thenQueryPlanShouldBe();
|
|
64
50
|
else throw new Error(`Unrecognized steps used in "build-query-plan.feature"`);
|
|
65
51
|
});
|
|
@@ -192,6 +192,7 @@ describe('core v0.2', () => {
|
|
|
192
192
|
const supergraphSdl = `#graphql
|
|
193
193
|
schema
|
|
194
194
|
@core(feature: "https://specs.apollo.dev/core/v0.2")
|
|
195
|
+
@core(feature: "https://specs.apollo.dev/join/v0.1", for: EXECUTION)
|
|
195
196
|
@core(feature: "https://specs.apollo.dev/tag/v0.1")
|
|
196
197
|
@core(feature: "https://specs.apollo.dev/unsupported-feature/v0.1") {
|
|
197
198
|
query: Query
|
package/src/executeQueryPlan.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GraphQLExecutionResult,
|
|
3
3
|
GraphQLRequestContext,
|
|
4
|
-
VariableValues,
|
|
5
4
|
} from 'apollo-server-types';
|
|
6
5
|
import { Headers } from 'apollo-server-env';
|
|
7
6
|
import {
|
|
@@ -26,7 +25,6 @@ import {
|
|
|
26
25
|
QueryPlanSelectionNode,
|
|
27
26
|
QueryPlanFieldNode,
|
|
28
27
|
getResponseName,
|
|
29
|
-
toAPISchema
|
|
30
28
|
} from '@apollo/query-planner';
|
|
31
29
|
import { deepMerge } from './utilities/deepMerge';
|
|
32
30
|
import { isNotNullOrUndefined } from './utilities/array';
|
|
@@ -94,7 +92,7 @@ export async function executeQueryPlan<TContext>(
|
|
|
94
92
|
// the original query.
|
|
95
93
|
// It is also used to allow execution of introspection queries though.
|
|
96
94
|
try {
|
|
97
|
-
const schema =
|
|
95
|
+
const schema = operationContext.schema;
|
|
98
96
|
({ data } = await execute({
|
|
99
97
|
schema,
|
|
100
98
|
document: {
|
|
@@ -233,10 +231,6 @@ async function executeNode<TContext>(
|
|
|
233
231
|
});
|
|
234
232
|
}
|
|
235
233
|
case 'Fetch': {
|
|
236
|
-
if (shouldSkipFetchNode(node, context.requestContext.request.variables)) {
|
|
237
|
-
return new Trace.QueryPlanNode();
|
|
238
|
-
}
|
|
239
|
-
|
|
240
234
|
const traceNode = new Trace.QueryPlanNode.FetchNode({
|
|
241
235
|
serviceName: node.serviceName,
|
|
242
236
|
// executeFetch will fill in the other fields if desired.
|
|
@@ -257,31 +251,6 @@ async function executeNode<TContext>(
|
|
|
257
251
|
}
|
|
258
252
|
}
|
|
259
253
|
|
|
260
|
-
export function shouldSkipFetchNode(
|
|
261
|
-
node: FetchNode,
|
|
262
|
-
variables: VariableValues = {},
|
|
263
|
-
) {
|
|
264
|
-
if (!node.inclusionConditions) return false;
|
|
265
|
-
|
|
266
|
-
return node.inclusionConditions.every((conditionals) => {
|
|
267
|
-
function resolveConditionalValue(conditional: 'skip' | 'include') {
|
|
268
|
-
const conditionalType = typeof conditionals[conditional];
|
|
269
|
-
if (conditionalType === 'boolean') {
|
|
270
|
-
return conditionals[conditional] as boolean;
|
|
271
|
-
} else if (conditionalType === 'string') {
|
|
272
|
-
return variables[conditionals[conditional] as string] as boolean;
|
|
273
|
-
} else {
|
|
274
|
-
return null;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const includeValue = resolveConditionalValue('include');
|
|
279
|
-
const skipValue = resolveConditionalValue('skip');
|
|
280
|
-
|
|
281
|
-
return includeValue === false || skipValue === true;
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
|
|
285
254
|
async function executeFetch<TContext>(
|
|
286
255
|
context: ExecutionContext<TContext>,
|
|
287
256
|
fetch: FetchNode,
|