@apollo/gateway 2.4.5 → 2.4.6
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/dist/__generated__/graphqlTypes.d.ts +19 -1
- package/dist/__generated__/graphqlTypes.d.ts.map +1 -1
- package/dist/__generated__/graphqlTypes.js +1 -0
- package/dist/__generated__/graphqlTypes.js.map +1 -1
- package/package.json +4 -4
- package/src/__generated__/graphqlTypes.ts +33 -2
- package/src/__mocks__/tsconfig.json +0 -7
- package/src/__tests__/.gitkeep +0 -0
- package/src/__tests__/CucumberREADME.md +0 -96
- package/src/__tests__/build-query-plan.feature +0 -1471
- package/src/__tests__/buildQueryPlan.test.ts +0 -1225
- package/src/__tests__/executeQueryPlan.conditions.test.ts +0 -1488
- package/src/__tests__/executeQueryPlan.introspection.test.ts +0 -140
- package/src/__tests__/executeQueryPlan.test.ts +0 -6140
- package/src/__tests__/execution-utils.ts +0 -124
- package/src/__tests__/gateway/__snapshots__/opentelemetry.test.ts.snap +0 -195
- package/src/__tests__/gateway/buildService.test.ts +0 -249
- package/src/__tests__/gateway/endToEnd.test.ts +0 -486
- package/src/__tests__/gateway/executor.test.ts +0 -96
- package/src/__tests__/gateway/extensions.test.ts +0 -37
- package/src/__tests__/gateway/lifecycle-hooks.test.ts +0 -239
- package/src/__tests__/gateway/opentelemetry.test.ts +0 -123
- package/src/__tests__/gateway/queryPlanCache.test.ts +0 -231
- package/src/__tests__/gateway/queryPlannerConfig.test.ts +0 -101
- package/src/__tests__/gateway/reporting.test.ts +0 -616
- package/src/__tests__/gateway/supergraphSdl.test.ts +0 -396
- package/src/__tests__/gateway/testUtils.ts +0 -89
- package/src/__tests__/integration/abstract-types.test.ts +0 -1861
- package/src/__tests__/integration/aliases.test.ts +0 -180
- package/src/__tests__/integration/boolean.test.ts +0 -279
- package/src/__tests__/integration/complex-key.test.ts +0 -197
- package/src/__tests__/integration/configuration.test.ts +0 -404
- package/src/__tests__/integration/custom-directives.test.ts +0 -174
- package/src/__tests__/integration/execution-style.test.ts +0 -35
- package/src/__tests__/integration/fragments.test.ts +0 -237
- package/src/__tests__/integration/list-key.test.ts +0 -128
- package/src/__tests__/integration/logger.test.ts +0 -122
- package/src/__tests__/integration/managed.test.ts +0 -319
- package/src/__tests__/integration/merge-arrays.test.ts +0 -34
- package/src/__tests__/integration/multiple-key.test.ts +0 -327
- package/src/__tests__/integration/mutations.test.ts +0 -287
- package/src/__tests__/integration/networkRequests.test.ts +0 -542
- package/src/__tests__/integration/nockMocks.ts +0 -157
- package/src/__tests__/integration/provides.test.ts +0 -77
- package/src/__tests__/integration/requires.test.ts +0 -359
- package/src/__tests__/integration/scope.test.ts +0 -557
- package/src/__tests__/integration/single-service.test.ts +0 -119
- package/src/__tests__/integration/unions.test.ts +0 -79
- package/src/__tests__/integration/value-types.test.ts +0 -382
- package/src/__tests__/integration/variables.test.ts +0 -120
- package/src/__tests__/nockAssertions.ts +0 -20
- package/src/__tests__/queryPlanCucumber.test.ts +0 -55
- package/src/__tests__/resultShaping.test.ts +0 -605
- package/src/__tests__/testSetup.ts +0 -1
- package/src/__tests__/tsconfig.json +0 -8
- package/src/core/__tests__/core.test.ts +0 -412
- package/src/datasources/__tests__/LocalGraphQLDataSource.test.ts +0 -51
- package/src/datasources/__tests__/RemoteGraphQLDataSource.test.ts +0 -574
- package/src/schema-helper/__tests__/addExtensions.test.ts +0 -70
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/IntrospectAndCompose.test.ts +0 -364
- package/src/supergraphManagers/IntrospectAndCompose/__tests__/loadServicesFromRemoteEndpoint.test.ts +0 -40
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/UplinkSupergraphManager.test.ts +0 -65
- package/src/supergraphManagers/UplinkSupergraphManager/__tests__/loadSupergraphSdlFromStorage.test.ts +0 -511
- package/src/utilities/__tests__/deepMerge.test.ts +0 -77
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
import { execute } from '../execution-utils';
|
|
2
|
-
import { ApolloServer } from '@apollo/server';
|
|
3
|
-
import { buildSubgraphSchema } from '@apollo/subgraph';
|
|
4
|
-
import { LocalGraphQLDataSource } from '../../datasources/LocalGraphQLDataSource';
|
|
5
|
-
import { ApolloGateway } from '../../';
|
|
6
|
-
import { fixtures } from 'apollo-federation-integration-testsuite';
|
|
7
|
-
import { unwrapSingleResultKind } from '../gateway/testUtils';
|
|
8
|
-
|
|
9
|
-
it('supports simple aliases', async () => {
|
|
10
|
-
const query = `#graphql
|
|
11
|
-
query GetProduct($upc: String!) {
|
|
12
|
-
product(upc: $upc) {
|
|
13
|
-
name
|
|
14
|
-
title: name
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
`;
|
|
18
|
-
|
|
19
|
-
const upc = '1';
|
|
20
|
-
const { data, queryPlan } = await execute({
|
|
21
|
-
query,
|
|
22
|
-
variables: { upc },
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
expect(data).toEqual({
|
|
26
|
-
product: {
|
|
27
|
-
name: 'Table',
|
|
28
|
-
title: 'Table',
|
|
29
|
-
},
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
expect(queryPlan).toCallService('product');
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
it('supports aliases of root fields on subservices', async () => {
|
|
36
|
-
const query = `#graphql
|
|
37
|
-
query GetProduct($upc: String!) {
|
|
38
|
-
product(upc: $upc) {
|
|
39
|
-
name
|
|
40
|
-
title: name
|
|
41
|
-
reviews {
|
|
42
|
-
body
|
|
43
|
-
}
|
|
44
|
-
productReviews: reviews {
|
|
45
|
-
body
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
`;
|
|
50
|
-
|
|
51
|
-
const upc = '1';
|
|
52
|
-
const { data, queryPlan } = await execute({
|
|
53
|
-
query,
|
|
54
|
-
variables: { upc },
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
expect(data).toEqual({
|
|
58
|
-
product: {
|
|
59
|
-
name: 'Table',
|
|
60
|
-
title: 'Table',
|
|
61
|
-
reviews: [
|
|
62
|
-
{
|
|
63
|
-
body: 'Love it!',
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
body: 'Prefer something else.',
|
|
67
|
-
},
|
|
68
|
-
],
|
|
69
|
-
productReviews: [
|
|
70
|
-
{
|
|
71
|
-
body: 'Love it!',
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
body: 'Prefer something else.',
|
|
75
|
-
},
|
|
76
|
-
],
|
|
77
|
-
},
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
expect(queryPlan).toCallService('product');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('supports aliases of nested fields on subservices', async () => {
|
|
84
|
-
const query = `#graphql
|
|
85
|
-
query GetProduct($upc: String!) {
|
|
86
|
-
product(upc: $upc) {
|
|
87
|
-
name
|
|
88
|
-
title: name
|
|
89
|
-
reviews {
|
|
90
|
-
content: body
|
|
91
|
-
body
|
|
92
|
-
}
|
|
93
|
-
productReviews: reviews {
|
|
94
|
-
body
|
|
95
|
-
reviewer: author {
|
|
96
|
-
name: username
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
`;
|
|
102
|
-
|
|
103
|
-
const upc = '1';
|
|
104
|
-
const { data, queryPlan } = await execute({
|
|
105
|
-
query,
|
|
106
|
-
variables: { upc },
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
expect(data).toEqual({
|
|
110
|
-
product: {
|
|
111
|
-
name: 'Table',
|
|
112
|
-
title: 'Table',
|
|
113
|
-
reviews: [
|
|
114
|
-
{
|
|
115
|
-
content: 'Love it!',
|
|
116
|
-
body: 'Love it!',
|
|
117
|
-
},
|
|
118
|
-
{
|
|
119
|
-
content: 'Prefer something else.',
|
|
120
|
-
body: 'Prefer something else.',
|
|
121
|
-
},
|
|
122
|
-
],
|
|
123
|
-
productReviews: [
|
|
124
|
-
{
|
|
125
|
-
body: 'Love it!',
|
|
126
|
-
reviewer: {
|
|
127
|
-
name: '@ada',
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
body: 'Prefer something else.',
|
|
132
|
-
reviewer: {
|
|
133
|
-
name: '@complete',
|
|
134
|
-
},
|
|
135
|
-
},
|
|
136
|
-
],
|
|
137
|
-
},
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
expect(queryPlan).toCallService('product');
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
// TODO after we remove GraphQLExtensions from ApolloServer, this can go away
|
|
144
|
-
it('supports aliases when using ApolloServer', async () => {
|
|
145
|
-
const localDataSources = Object.fromEntries(
|
|
146
|
-
fixtures.map((f) => [
|
|
147
|
-
f.name,
|
|
148
|
-
new LocalGraphQLDataSource(buildSubgraphSchema(f)),
|
|
149
|
-
]),
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
const gateway = new ApolloGateway({
|
|
153
|
-
localServiceList: fixtures,
|
|
154
|
-
buildService(service) {
|
|
155
|
-
return localDataSources[service.name];
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
const server = new ApolloServer({ gateway });
|
|
160
|
-
await server.start();
|
|
161
|
-
|
|
162
|
-
const upc = '1';
|
|
163
|
-
|
|
164
|
-
const result = await server.executeOperation({
|
|
165
|
-
query: `#graphql
|
|
166
|
-
query GetProduct($upc: String!) {
|
|
167
|
-
product(upc: $upc) {
|
|
168
|
-
title: name
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
`,
|
|
172
|
-
variables: { upc },
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
expect(unwrapSingleResultKind(result).data).toEqual({
|
|
176
|
-
product: {
|
|
177
|
-
title: 'Table',
|
|
178
|
-
},
|
|
179
|
-
});
|
|
180
|
-
});
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
import { execute } from '../execution-utils';
|
|
2
|
-
import { astSerializer, queryPlanSerializer } from 'apollo-federation-integration-testsuite';
|
|
3
|
-
|
|
4
|
-
expect.addSnapshotSerializer(astSerializer);
|
|
5
|
-
expect.addSnapshotSerializer(queryPlanSerializer);
|
|
6
|
-
|
|
7
|
-
describe('@skip', () => {
|
|
8
|
-
it('supports @skip when a boolean condition is met', async () => {
|
|
9
|
-
const query = `#graphql
|
|
10
|
-
query GetReviewers {
|
|
11
|
-
topReviews {
|
|
12
|
-
body
|
|
13
|
-
author @skip(if: true) {
|
|
14
|
-
name {
|
|
15
|
-
first
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
`;
|
|
21
|
-
|
|
22
|
-
const { data, queryPlan } = await execute({
|
|
23
|
-
query,
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
expect(data).toEqual({
|
|
27
|
-
topReviews: [
|
|
28
|
-
{ body: 'Love it!' },
|
|
29
|
-
{ body: 'Too expensive.' },
|
|
30
|
-
{ body: 'Could be better.' },
|
|
31
|
-
{ body: 'Prefer something else.' },
|
|
32
|
-
{ body: 'Wish I had read this before.' },
|
|
33
|
-
],
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
expect(queryPlan).toCallService('reviews');
|
|
37
|
-
expect(queryPlan).not.toCallService('accounts');
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
it('supports @skip when a boolean condition is met (variable driven)', async () => {
|
|
41
|
-
const query = `#graphql
|
|
42
|
-
query GetReviewers($skip: Boolean!) {
|
|
43
|
-
topReviews {
|
|
44
|
-
body
|
|
45
|
-
author @skip(if: $skip) {
|
|
46
|
-
username
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
`;
|
|
51
|
-
|
|
52
|
-
const skip = true;
|
|
53
|
-
const { data, queryPlan } = await execute({
|
|
54
|
-
query,
|
|
55
|
-
variables: { skip },
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
expect(data).toEqual({
|
|
59
|
-
topReviews: [
|
|
60
|
-
{ body: 'Love it!' },
|
|
61
|
-
{ body: 'Too expensive.' },
|
|
62
|
-
{ body: 'Could be better.' },
|
|
63
|
-
{ body: 'Prefer something else.' },
|
|
64
|
-
{ body: 'Wish I had read this before.' },
|
|
65
|
-
],
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
expect(queryPlan).not.toCallService('accounts');
|
|
69
|
-
expect(queryPlan).toCallService('reviews');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
// Data looks good here, suspect the matcher is incorrect
|
|
73
|
-
it('supports @skip when a boolean condition is not met', async () => {
|
|
74
|
-
const query = `#graphql
|
|
75
|
-
query GetReviewers {
|
|
76
|
-
topReviews {
|
|
77
|
-
body
|
|
78
|
-
author @skip(if: false) {
|
|
79
|
-
name {
|
|
80
|
-
first
|
|
81
|
-
last
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
`;
|
|
87
|
-
|
|
88
|
-
const { data, queryPlan } = await execute({
|
|
89
|
-
query,
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
expect(data).toEqual({
|
|
93
|
-
topReviews: [
|
|
94
|
-
{ body: 'Love it!', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
95
|
-
{ body: 'Too expensive.', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
96
|
-
{ body: 'Could be better.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
97
|
-
{ body: 'Prefer something else.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
98
|
-
{ body: 'Wish I had read this before.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
99
|
-
],
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
expect(queryPlan).toCallService('accounts');
|
|
103
|
-
expect(queryPlan).toCallService('reviews');
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
// Data looks good here, suspect the matcher is incorrect
|
|
107
|
-
it('supports @skip when a boolean condition is not met (variable driven)', async () => {
|
|
108
|
-
const query = `#graphql
|
|
109
|
-
query GetReviewers($skip: Boolean!) {
|
|
110
|
-
topReviews {
|
|
111
|
-
body
|
|
112
|
-
author @skip(if: $skip) {
|
|
113
|
-
name {
|
|
114
|
-
first
|
|
115
|
-
last
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
`;
|
|
121
|
-
|
|
122
|
-
const skip = false;
|
|
123
|
-
const { data, queryPlan, operation } = await execute({
|
|
124
|
-
query,
|
|
125
|
-
variables: { skip },
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
expect(data).toEqual({
|
|
129
|
-
topReviews: [
|
|
130
|
-
{ body: 'Love it!', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
131
|
-
{ body: 'Too expensive.', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
132
|
-
{ body: 'Could be better.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
133
|
-
{ body: 'Prefer something else.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
134
|
-
{ body: 'Wish I had read this before.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
135
|
-
],
|
|
136
|
-
});
|
|
137
|
-
|
|
138
|
-
const variables = { definitions: operation.variableDefinitions, values: {skip} };
|
|
139
|
-
expect(queryPlan).toCallService('reviews', variables);
|
|
140
|
-
expect(queryPlan).toCallService('accounts', variables);
|
|
141
|
-
});
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
describe('@include', () => {
|
|
145
|
-
it('supports @include when a boolean condition is not met', async () => {
|
|
146
|
-
const query = `#graphql
|
|
147
|
-
query GetReviewers {
|
|
148
|
-
topReviews {
|
|
149
|
-
body
|
|
150
|
-
author @include(if: false) {
|
|
151
|
-
username
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
`;
|
|
156
|
-
|
|
157
|
-
const { data, queryPlan } = await execute({
|
|
158
|
-
query,
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
expect(data).toEqual({
|
|
162
|
-
topReviews: [
|
|
163
|
-
{ body: 'Love it!' },
|
|
164
|
-
{ body: 'Too expensive.' },
|
|
165
|
-
{ body: 'Could be better.' },
|
|
166
|
-
{ body: 'Prefer something else.' },
|
|
167
|
-
{ body: 'Wish I had read this before.' },
|
|
168
|
-
],
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
expect(queryPlan).not.toCallService('accounts');
|
|
172
|
-
expect(queryPlan).toCallService('reviews');
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('supports @include when a boolean condition is not met (variable driven)', async () => {
|
|
176
|
-
const query = `#graphql
|
|
177
|
-
query GetReviewers($include: Boolean!) {
|
|
178
|
-
topReviews {
|
|
179
|
-
body
|
|
180
|
-
author @include(if: $include) {
|
|
181
|
-
username
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
`;
|
|
186
|
-
|
|
187
|
-
const include = false;
|
|
188
|
-
const { data, queryPlan } = await execute({
|
|
189
|
-
query,
|
|
190
|
-
variables: { include },
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
expect(data).toEqual({
|
|
194
|
-
topReviews: [
|
|
195
|
-
{ body: 'Love it!' },
|
|
196
|
-
{ body: 'Too expensive.' },
|
|
197
|
-
{ body: 'Could be better.' },
|
|
198
|
-
{ body: 'Prefer something else.' },
|
|
199
|
-
{ body: 'Wish I had read this before.' },
|
|
200
|
-
],
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
expect(queryPlan).not.toCallService('accounts');
|
|
204
|
-
expect(queryPlan).toCallService('reviews');
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// Data looks good here, suspect the matcher is incorrect
|
|
208
|
-
// Added the query plan snapshot for a view.
|
|
209
|
-
it('supports @include when a boolean condition is met', async () => {
|
|
210
|
-
const query = `#graphql
|
|
211
|
-
query GetReviewers {
|
|
212
|
-
topReviews {
|
|
213
|
-
body
|
|
214
|
-
author @include(if: true) {
|
|
215
|
-
name {
|
|
216
|
-
first
|
|
217
|
-
last
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
`;
|
|
223
|
-
|
|
224
|
-
const { data, queryPlan } = await execute({
|
|
225
|
-
query,
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
expect(data).toEqual({
|
|
229
|
-
topReviews: [
|
|
230
|
-
{ body: 'Love it!', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
231
|
-
{ body: 'Too expensive.', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
232
|
-
{ body: 'Could be better.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
233
|
-
{ body: 'Prefer something else.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
234
|
-
{ body: 'Wish I had read this before.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
235
|
-
],
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
expect(queryPlan).toCallService('accounts');
|
|
239
|
-
expect(queryPlan).toCallService('reviews');
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
// Data looks good here, suspect the matcher is incorrect
|
|
243
|
-
// Added the query plan snapshot for a view.
|
|
244
|
-
it('supports @include when a boolean condition is met (variable driven)', async () => {
|
|
245
|
-
const query = `#graphql
|
|
246
|
-
query GetReviewers($include: Boolean!) {
|
|
247
|
-
topReviews {
|
|
248
|
-
body
|
|
249
|
-
author @include(if: $include) {
|
|
250
|
-
name {
|
|
251
|
-
first
|
|
252
|
-
last
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
`;
|
|
258
|
-
|
|
259
|
-
const include = true;
|
|
260
|
-
const { data, queryPlan, operation } = await execute({
|
|
261
|
-
query,
|
|
262
|
-
variables: { include },
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
expect(data).toEqual({
|
|
266
|
-
topReviews: [
|
|
267
|
-
{ body: 'Love it!', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
268
|
-
{ body: 'Too expensive.', author: { name: { first: 'Ada', last: 'Lovelace' } } },
|
|
269
|
-
{ body: 'Could be better.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
270
|
-
{ body: 'Prefer something else.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
271
|
-
{ body: 'Wish I had read this before.', author: { name: { first: 'Alan', last: 'Turing' } } },
|
|
272
|
-
],
|
|
273
|
-
});
|
|
274
|
-
|
|
275
|
-
const variables = { definitions: operation.variableDefinitions, values: {include} };
|
|
276
|
-
expect(queryPlan).toCallService('accounts', variables);
|
|
277
|
-
expect(queryPlan).toCallService('reviews', variables);
|
|
278
|
-
});
|
|
279
|
-
});
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import gql from 'graphql-tag';
|
|
2
|
-
import { execute, ServiceDefinitionModule } from '../execution-utils';
|
|
3
|
-
import { astSerializer, queryPlanSerializer } from 'apollo-federation-integration-testsuite';
|
|
4
|
-
|
|
5
|
-
expect.addSnapshotSerializer(astSerializer);
|
|
6
|
-
expect.addSnapshotSerializer(queryPlanSerializer);
|
|
7
|
-
|
|
8
|
-
const users = [
|
|
9
|
-
{ id: '1', name: 'Trevor', organizationId: '1', __typename: 'User' },
|
|
10
|
-
{ id: '1', name: 'Trevor', organizationId: '2', __typename: 'User' },
|
|
11
|
-
{ id: '2', name: 'James Baxley', organizationId: '1', __typename: 'User' },
|
|
12
|
-
{ id: '2', name: 'James Baxley', organizationId: '3', __typename: 'User' },
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const organizations = [
|
|
16
|
-
{ id: '1', name: 'Apollo', __typename: 'Organization' },
|
|
17
|
-
{ id: '2', name: 'Wayfair', __typename: 'Organization' },
|
|
18
|
-
{ id: '3', name: 'Major League Soccer', __typename: 'Organization' },
|
|
19
|
-
];
|
|
20
|
-
|
|
21
|
-
const reviews = [
|
|
22
|
-
{ id: '1', authorId: '1', organizationId: '1', __typename: 'Review' },
|
|
23
|
-
{ id: '2', authorId: '1', organizationId: '2', __typename: 'Review' },
|
|
24
|
-
{ id: '3', authorId: '2', organizationId: '1', __typename: 'Review' },
|
|
25
|
-
{ id: '4', authorId: '2', organizationId: '3', __typename: 'Review' },
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const reviewService: ServiceDefinitionModule = {
|
|
29
|
-
name: 'review',
|
|
30
|
-
typeDefs: gql`
|
|
31
|
-
type Query {
|
|
32
|
-
reviews: [Review!]!
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
type Review {
|
|
36
|
-
id: ID!
|
|
37
|
-
author: User!
|
|
38
|
-
body: String!
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
# TODO: consider ergonomics of external types.
|
|
42
|
-
extend type User @key(fields: "id organization { id }") {
|
|
43
|
-
id: ID! @external
|
|
44
|
-
organization: Organization! @external
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
extend type Organization {
|
|
48
|
-
id: ID! @external
|
|
49
|
-
}
|
|
50
|
-
`,
|
|
51
|
-
resolvers: {
|
|
52
|
-
Query: {
|
|
53
|
-
reviews() {
|
|
54
|
-
return reviews;
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
Review: {
|
|
58
|
-
author(review) {
|
|
59
|
-
return {
|
|
60
|
-
id: review.authorId,
|
|
61
|
-
organization: {
|
|
62
|
-
id: review.organizationId,
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
},
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const userService: ServiceDefinitionModule = {
|
|
71
|
-
name: 'user',
|
|
72
|
-
typeDefs: gql`
|
|
73
|
-
type User @key(fields: "id organization { id }") {
|
|
74
|
-
id: ID!
|
|
75
|
-
name: String!
|
|
76
|
-
organization: Organization!
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
type Organization @key(fields: "id") {
|
|
80
|
-
id: ID!
|
|
81
|
-
name: String!
|
|
82
|
-
}
|
|
83
|
-
`,
|
|
84
|
-
resolvers: {
|
|
85
|
-
User: {
|
|
86
|
-
__resolveReference(reference) {
|
|
87
|
-
return users.find(
|
|
88
|
-
user =>
|
|
89
|
-
user.id === reference.id &&
|
|
90
|
-
user.organizationId === reference.organization.id,
|
|
91
|
-
);
|
|
92
|
-
},
|
|
93
|
-
organization(user) {
|
|
94
|
-
return organizations.find(org => org.id === user.organizationId);
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
},
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
it('works fetches data correctly with complex / nested @key fields', async () => {
|
|
101
|
-
const query = `#graphql
|
|
102
|
-
query Reviews {
|
|
103
|
-
reviews {
|
|
104
|
-
author {
|
|
105
|
-
name
|
|
106
|
-
organization {
|
|
107
|
-
name
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
`;
|
|
113
|
-
|
|
114
|
-
const { data, queryPlan } = await execute(
|
|
115
|
-
{
|
|
116
|
-
query,
|
|
117
|
-
},
|
|
118
|
-
[userService, reviewService],
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
expect(queryPlan).toMatchInlineSnapshot(`
|
|
122
|
-
QueryPlan {
|
|
123
|
-
Sequence {
|
|
124
|
-
Fetch(service: "review") {
|
|
125
|
-
{
|
|
126
|
-
reviews {
|
|
127
|
-
author {
|
|
128
|
-
__typename
|
|
129
|
-
id
|
|
130
|
-
organization {
|
|
131
|
-
id
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
},
|
|
137
|
-
Flatten(path: "reviews.@.author") {
|
|
138
|
-
Fetch(service: "user") {
|
|
139
|
-
{
|
|
140
|
-
... on User {
|
|
141
|
-
__typename
|
|
142
|
-
id
|
|
143
|
-
organization {
|
|
144
|
-
id
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
} =>
|
|
148
|
-
{
|
|
149
|
-
... on User {
|
|
150
|
-
name
|
|
151
|
-
organization {
|
|
152
|
-
name
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
},
|
|
157
|
-
},
|
|
158
|
-
},
|
|
159
|
-
}
|
|
160
|
-
`);
|
|
161
|
-
expect(data).toEqual({
|
|
162
|
-
reviews: [
|
|
163
|
-
{
|
|
164
|
-
author: {
|
|
165
|
-
name: 'Trevor',
|
|
166
|
-
organization: {
|
|
167
|
-
name: 'Apollo',
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
author: {
|
|
173
|
-
name: 'Trevor',
|
|
174
|
-
organization: {
|
|
175
|
-
name: 'Wayfair',
|
|
176
|
-
},
|
|
177
|
-
},
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
author: {
|
|
181
|
-
name: 'James Baxley',
|
|
182
|
-
organization: {
|
|
183
|
-
name: 'Apollo',
|
|
184
|
-
},
|
|
185
|
-
},
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
author: {
|
|
189
|
-
name: 'James Baxley',
|
|
190
|
-
organization: {
|
|
191
|
-
name: 'Major League Soccer',
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
},
|
|
195
|
-
],
|
|
196
|
-
});
|
|
197
|
-
});
|