@graphql-tools/executor 1.1.0 → 1.2.0-alpha-20230809163713-4e6faf66
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/cjs/execution/execute.js +72 -19
- package/cjs/execution/normalizedExecutor.js +2 -2
- package/cjs/execution/promiseForObject.js +9 -4
- package/esm/execution/execute.js +74 -21
- package/esm/execution/normalizedExecutor.js +2 -2
- package/esm/execution/promiseForObject.js +9 -4
- package/esm/execution/values.js +1 -1
- package/package.json +2 -2
- package/typings/execution/execute.d.cts +5 -3
- package/typings/execution/execute.d.ts +5 -3
- package/typings/execution/normalizedExecutor.d.cts +1 -1
- package/typings/execution/normalizedExecutor.d.ts +1 -1
- package/typings/execution/promiseForObject.d.cts +1 -1
- package/typings/execution/promiseForObject.d.ts +1 -1
- package/typings/execution/values.d.cts +1 -1
- package/typings/execution/values.d.ts +1 -1
package/cjs/execution/execute.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.isIncrementalResult = exports.getFieldDef = exports.flattenIncrementalResults = exports.subscribe = exports.defaultFieldResolver = exports.defaultTypeResolver = exports.buildResolveInfo = exports.buildExecutionContext = exports.getFragmentsFromDocument = exports.assertValidExecutionArguments = exports.executeSync = exports.execute = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
|
+
const value_or_promise_1 = require("value-or-promise");
|
|
5
6
|
const utils_1 = require("@graphql-tools/utils");
|
|
6
|
-
const values_js_1 = require("./values.js");
|
|
7
|
-
const promiseForObject_js_1 = require("./promiseForObject.js");
|
|
8
7
|
const flattenAsyncIterable_js_1 = require("./flattenAsyncIterable.js");
|
|
9
8
|
const invariant_js_1 = require("./invariant.js");
|
|
10
|
-
const
|
|
9
|
+
const promiseForObject_js_1 = require("./promiseForObject.js");
|
|
10
|
+
const values_js_1 = require("./values.js");
|
|
11
11
|
/**
|
|
12
12
|
* A memoized collection of relevant subfields with regard to the return
|
|
13
13
|
* type. Memoizing ensures the subfields are not repeatedly calculated, which
|
|
@@ -135,7 +135,7 @@ exports.getFragmentsFromDocument = (0, utils_1.memoize1)(function getFragmentsFr
|
|
|
135
135
|
* @internal
|
|
136
136
|
*/
|
|
137
137
|
function buildExecutionContext(args) {
|
|
138
|
-
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, } = args;
|
|
138
|
+
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args;
|
|
139
139
|
// If the schema used for execution is invalid, throw an error.
|
|
140
140
|
(0, graphql_1.assertValidSchema)(schema);
|
|
141
141
|
const fragments = (0, exports.getFragmentsFromDocument)(document);
|
|
@@ -145,7 +145,9 @@ function buildExecutionContext(args) {
|
|
|
145
145
|
case graphql_1.Kind.OPERATION_DEFINITION:
|
|
146
146
|
if (operationName == null) {
|
|
147
147
|
if (operation !== undefined) {
|
|
148
|
-
return [
|
|
148
|
+
return [
|
|
149
|
+
(0, utils_1.createGraphQLError)('Must provide operation name if query contains multiple operations.'),
|
|
150
|
+
];
|
|
149
151
|
}
|
|
150
152
|
operation = definition;
|
|
151
153
|
}
|
|
@@ -184,6 +186,7 @@ function buildExecutionContext(args) {
|
|
|
184
186
|
subscribeFieldResolver: subscribeFieldResolver ?? exports.defaultFieldResolver,
|
|
185
187
|
subsequentPayloads: new Set(),
|
|
186
188
|
errors: [],
|
|
189
|
+
signal,
|
|
187
190
|
};
|
|
188
191
|
}
|
|
189
192
|
exports.buildExecutionContext = buildExecutionContext;
|
|
@@ -226,13 +229,26 @@ function executeOperation(exeContext) {
|
|
|
226
229
|
* for fields that must be executed serially.
|
|
227
230
|
*/
|
|
228
231
|
function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) {
|
|
232
|
+
let abortErrorThrown = false;
|
|
229
233
|
return (0, utils_1.promiseReduce)(fields, (results, [responseName, fieldNodes]) => {
|
|
230
234
|
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name);
|
|
235
|
+
if (exeContext.signal?.aborted) {
|
|
236
|
+
results[responseName] = null;
|
|
237
|
+
return results;
|
|
238
|
+
}
|
|
231
239
|
return new value_or_promise_1.ValueOrPromise(() => executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath)).then(result => {
|
|
232
240
|
if (result === undefined) {
|
|
233
241
|
return results;
|
|
234
242
|
}
|
|
235
243
|
results[responseName] = result;
|
|
244
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
245
|
+
exeContext.errors.push((0, utils_1.createGraphQLError)('Execution aborted', {
|
|
246
|
+
nodes: fieldNodes,
|
|
247
|
+
path: (0, utils_1.pathToArray)(fieldPath),
|
|
248
|
+
originalError: exeContext.signal?.reason,
|
|
249
|
+
}));
|
|
250
|
+
abortErrorThrown = true;
|
|
251
|
+
}
|
|
236
252
|
return results;
|
|
237
253
|
});
|
|
238
254
|
}, Object.create(null)).resolve();
|
|
@@ -244,8 +260,13 @@ function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields
|
|
|
244
260
|
function executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord) {
|
|
245
261
|
const results = Object.create(null);
|
|
246
262
|
let containsPromise = false;
|
|
263
|
+
let abortErrorThrown = false;
|
|
247
264
|
try {
|
|
248
265
|
for (const [responseName, fieldNodes] of fields) {
|
|
266
|
+
if (exeContext.signal?.aborted) {
|
|
267
|
+
results[responseName] = null;
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
249
270
|
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name);
|
|
250
271
|
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath, asyncPayloadRecord);
|
|
251
272
|
if (result !== undefined) {
|
|
@@ -254,12 +275,20 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
254
275
|
containsPromise = true;
|
|
255
276
|
}
|
|
256
277
|
}
|
|
278
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
279
|
+
exeContext.errors.push((0, utils_1.createGraphQLError)('Execution aborted', {
|
|
280
|
+
nodes: fieldNodes,
|
|
281
|
+
path: (0, utils_1.pathToArray)(fieldPath),
|
|
282
|
+
originalError: exeContext.signal?.reason,
|
|
283
|
+
}));
|
|
284
|
+
abortErrorThrown = true;
|
|
285
|
+
}
|
|
257
286
|
}
|
|
258
287
|
}
|
|
259
288
|
catch (error) {
|
|
260
289
|
if (containsPromise) {
|
|
261
290
|
// Ensure that any promises returned by other fields are handled, as they may also reject.
|
|
262
|
-
return (0, promiseForObject_js_1.promiseForObject)(results).finally(() => {
|
|
291
|
+
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal).finally(() => {
|
|
263
292
|
throw error;
|
|
264
293
|
});
|
|
265
294
|
}
|
|
@@ -272,7 +301,7 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
272
301
|
// Otherwise, results is a map from field name to the result of resolving that
|
|
273
302
|
// field, which is possibly a promise. Return a promise that will return this
|
|
274
303
|
// same map, but with any promises replaced with the values they resolved to.
|
|
275
|
-
return (0, promiseForObject_js_1.promiseForObject)(results);
|
|
304
|
+
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal);
|
|
276
305
|
}
|
|
277
306
|
/**
|
|
278
307
|
* Implements the "Executing fields" section of the spec
|
|
@@ -450,6 +479,14 @@ function getStreamValues(exeContext, fieldNodes, path) {
|
|
|
450
479
|
* recursively until all the results are completed.
|
|
451
480
|
*/
|
|
452
481
|
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) {
|
|
482
|
+
exeContext.signal?.addEventListener('abort', () => {
|
|
483
|
+
iterator.return?.();
|
|
484
|
+
exeContext.errors.push((0, utils_1.createGraphQLError)('Execution aborted', {
|
|
485
|
+
nodes: fieldNodes,
|
|
486
|
+
path: (0, utils_1.pathToArray)(path),
|
|
487
|
+
originalError: exeContext.signal?.reason,
|
|
488
|
+
}));
|
|
489
|
+
});
|
|
453
490
|
const errors = asyncPayloadRecord?.errors ?? exeContext.errors;
|
|
454
491
|
const stream = getStreamValues(exeContext, fieldNodes, path);
|
|
455
492
|
let containsPromise = false;
|
|
@@ -772,20 +809,24 @@ function subscribe(args) {
|
|
|
772
809
|
return mapSourceToResponse(exeContext, resultOrStream);
|
|
773
810
|
}
|
|
774
811
|
exports.subscribe = subscribe;
|
|
775
|
-
function flattenIncrementalResults(incrementalResults) {
|
|
812
|
+
function flattenIncrementalResults(incrementalResults, signal) {
|
|
776
813
|
const subsequentIterator = incrementalResults.subsequentResults;
|
|
777
814
|
let initialResultSent = false;
|
|
778
815
|
let done = false;
|
|
816
|
+
signal?.addEventListener('abort', () => {
|
|
817
|
+
done = true;
|
|
818
|
+
subsequentIterator.throw?.(signal?.reason);
|
|
819
|
+
});
|
|
779
820
|
return {
|
|
780
821
|
[Symbol.asyncIterator]() {
|
|
781
822
|
return this;
|
|
782
823
|
},
|
|
783
|
-
|
|
824
|
+
next() {
|
|
784
825
|
if (done) {
|
|
785
|
-
return {
|
|
826
|
+
return Promise.resolve({
|
|
786
827
|
value: undefined,
|
|
787
828
|
done,
|
|
788
|
-
};
|
|
829
|
+
});
|
|
789
830
|
}
|
|
790
831
|
if (initialResultSent) {
|
|
791
832
|
return subsequentIterator.next();
|
|
@@ -807,9 +848,9 @@ function flattenIncrementalResults(incrementalResults) {
|
|
|
807
848
|
};
|
|
808
849
|
}
|
|
809
850
|
exports.flattenIncrementalResults = flattenIncrementalResults;
|
|
810
|
-
async function* ensureAsyncIterable(someExecutionResult) {
|
|
851
|
+
async function* ensureAsyncIterable(someExecutionResult, signal) {
|
|
811
852
|
if ('initialResult' in someExecutionResult) {
|
|
812
|
-
yield* flattenIncrementalResults(someExecutionResult);
|
|
853
|
+
yield* flattenIncrementalResults(someExecutionResult, signal);
|
|
813
854
|
}
|
|
814
855
|
else {
|
|
815
856
|
yield someExecutionResult;
|
|
@@ -825,7 +866,7 @@ function mapSourceToResponse(exeContext, resultOrStream) {
|
|
|
825
866
|
// the GraphQL specification. The `execute` function provides the
|
|
826
867
|
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
|
|
827
868
|
// "ExecuteQuery" algorithm, for which `execute` is also used.
|
|
828
|
-
return (0, flattenAsyncIterable_js_1.flattenAsyncIterable)((0, utils_1.mapAsyncIterator)(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload))), async function* (error) {
|
|
869
|
+
return (0, flattenAsyncIterable_js_1.flattenAsyncIterable)((0, utils_1.mapAsyncIterator)(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload)), exeContext.signal), async function* (error) {
|
|
829
870
|
const wrappedError = (0, utils_1.createGraphQLError)(error.message, {
|
|
830
871
|
originalError: error,
|
|
831
872
|
nodes: [exeContext.operation],
|
|
@@ -851,14 +892,18 @@ function executeSubscription(exeContext) {
|
|
|
851
892
|
const { schema, fragments, operation, variableValues, rootValue } = exeContext;
|
|
852
893
|
const rootType = schema.getSubscriptionType();
|
|
853
894
|
if (rootType == null) {
|
|
854
|
-
throw (0, utils_1.createGraphQLError)('Schema is not configured to execute subscription operation.', {
|
|
895
|
+
throw (0, utils_1.createGraphQLError)('Schema is not configured to execute subscription operation.', {
|
|
896
|
+
nodes: operation,
|
|
897
|
+
});
|
|
855
898
|
}
|
|
856
899
|
const { fields: rootFields } = (0, utils_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet);
|
|
857
900
|
const [responseName, fieldNodes] = [...rootFields.entries()][0];
|
|
858
901
|
const fieldName = fieldNodes[0].name.value;
|
|
859
902
|
const fieldDef = getFieldDef(schema, rootType, fieldNodes[0]);
|
|
860
903
|
if (!fieldDef) {
|
|
861
|
-
throw (0, utils_1.createGraphQLError)(`The subscription field "${fieldName}" is not defined.`, {
|
|
904
|
+
throw (0, utils_1.createGraphQLError)(`The subscription field "${fieldName}" is not defined.`, {
|
|
905
|
+
nodes: fieldNodes,
|
|
906
|
+
});
|
|
862
907
|
}
|
|
863
908
|
const path = (0, utils_1.addPath)(undefined, responseName, rootType.name);
|
|
864
909
|
const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, rootType, path);
|
|
@@ -881,13 +926,13 @@ function executeSubscription(exeContext) {
|
|
|
881
926
|
throw (0, graphql_1.locatedError)(error, fieldNodes, (0, utils_1.pathToArray)(path));
|
|
882
927
|
});
|
|
883
928
|
}
|
|
884
|
-
return assertEventStream(result);
|
|
929
|
+
return assertEventStream(result, exeContext.signal);
|
|
885
930
|
}
|
|
886
931
|
catch (error) {
|
|
887
932
|
throw (0, graphql_1.locatedError)(error, fieldNodes, (0, utils_1.pathToArray)(path));
|
|
888
933
|
}
|
|
889
934
|
}
|
|
890
|
-
function assertEventStream(result) {
|
|
935
|
+
function assertEventStream(result, signal) {
|
|
891
936
|
if (result instanceof Error) {
|
|
892
937
|
throw result;
|
|
893
938
|
}
|
|
@@ -895,7 +940,15 @@ function assertEventStream(result) {
|
|
|
895
940
|
if (!(0, utils_1.isAsyncIterable)(result)) {
|
|
896
941
|
throw (0, utils_1.createGraphQLError)('Subscription field must return Async Iterable. ' + `Received: ${(0, utils_1.inspect)(result)}.`);
|
|
897
942
|
}
|
|
898
|
-
return
|
|
943
|
+
return {
|
|
944
|
+
[Symbol.asyncIterator]() {
|
|
945
|
+
const asyncIterator = result[Symbol.asyncIterator]();
|
|
946
|
+
signal?.addEventListener('abort', () => {
|
|
947
|
+
asyncIterator.return?.();
|
|
948
|
+
});
|
|
949
|
+
return asyncIterator;
|
|
950
|
+
},
|
|
951
|
+
};
|
|
899
952
|
}
|
|
900
953
|
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext) {
|
|
901
954
|
const asyncPayloadRecord = new DeferredFragmentRecord({
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.normalizedExecutor = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
|
-
const execute_js_1 = require("./execute.js");
|
|
6
5
|
const value_or_promise_1 = require("value-or-promise");
|
|
6
|
+
const execute_js_1 = require("./execute.js");
|
|
7
7
|
function normalizedExecutor(args) {
|
|
8
8
|
const operationAST = (0, graphql_1.getOperationAST)(args.document, args.operationName);
|
|
9
9
|
if (operationAST == null) {
|
|
@@ -15,7 +15,7 @@ function normalizedExecutor(args) {
|
|
|
15
15
|
return new value_or_promise_1.ValueOrPromise(() => (0, execute_js_1.execute)(args))
|
|
16
16
|
.then((result) => {
|
|
17
17
|
if ('initialResult' in result) {
|
|
18
|
-
return (0, execute_js_1.flattenIncrementalResults)(result);
|
|
18
|
+
return (0, execute_js_1.flattenIncrementalResults)(result, args.signal);
|
|
19
19
|
}
|
|
20
20
|
return result;
|
|
21
21
|
})
|
|
@@ -8,11 +8,16 @@ exports.promiseForObject = void 0;
|
|
|
8
8
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
9
9
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
10
10
|
*/
|
|
11
|
-
async function promiseForObject(object) {
|
|
11
|
+
async function promiseForObject(object, signal) {
|
|
12
12
|
const resolvedObject = Object.create(null);
|
|
13
|
-
await Promise
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
await new Promise((resolve, reject) => {
|
|
14
|
+
signal?.addEventListener('abort', () => {
|
|
15
|
+
resolve();
|
|
16
|
+
});
|
|
17
|
+
Promise.all(Object.entries(object).map(async ([key, value]) => {
|
|
18
|
+
resolvedObject[key] = await value;
|
|
19
|
+
})).then(() => resolve(), reject);
|
|
20
|
+
});
|
|
16
21
|
return resolvedObject;
|
|
17
22
|
}
|
|
18
23
|
exports.promiseForObject = promiseForObject;
|
package/esm/execution/execute.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { promiseForObject } from './promiseForObject.js';
|
|
1
|
+
import { assertValidSchema, getDirectiveValues, GraphQLError, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, Kind, locatedError, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, } from 'graphql';
|
|
2
|
+
import { ValueOrPromise } from 'value-or-promise';
|
|
3
|
+
import { collectSubFields as _collectSubfields, addPath, collectFields, createGraphQLError, getArgumentValues, getDefinedRootType, GraphQLStreamDirective, inspect, isAsyncIterable, isIterableObject, isObjectLike, isPromise, mapAsyncIterator, memoize1, memoize3, pathToArray, promiseReduce, } from '@graphql-tools/utils';
|
|
5
4
|
import { flattenAsyncIterable } from './flattenAsyncIterable.js';
|
|
6
5
|
import { invariant } from './invariant.js';
|
|
7
|
-
import {
|
|
6
|
+
import { promiseForObject } from './promiseForObject.js';
|
|
7
|
+
import { getVariableValues } from './values.js';
|
|
8
8
|
/**
|
|
9
9
|
* A memoized collection of relevant subfields with regard to the return
|
|
10
10
|
* type. Memoizing ensures the subfields are not repeatedly calculated, which
|
|
@@ -129,7 +129,7 @@ export const getFragmentsFromDocument = memoize1(function getFragmentsFromDocume
|
|
|
129
129
|
* @internal
|
|
130
130
|
*/
|
|
131
131
|
export function buildExecutionContext(args) {
|
|
132
|
-
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, } = args;
|
|
132
|
+
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args;
|
|
133
133
|
// If the schema used for execution is invalid, throw an error.
|
|
134
134
|
assertValidSchema(schema);
|
|
135
135
|
const fragments = getFragmentsFromDocument(document);
|
|
@@ -139,7 +139,9 @@ export function buildExecutionContext(args) {
|
|
|
139
139
|
case Kind.OPERATION_DEFINITION:
|
|
140
140
|
if (operationName == null) {
|
|
141
141
|
if (operation !== undefined) {
|
|
142
|
-
return [
|
|
142
|
+
return [
|
|
143
|
+
createGraphQLError('Must provide operation name if query contains multiple operations.'),
|
|
144
|
+
];
|
|
143
145
|
}
|
|
144
146
|
operation = definition;
|
|
145
147
|
}
|
|
@@ -178,6 +180,7 @@ export function buildExecutionContext(args) {
|
|
|
178
180
|
subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver,
|
|
179
181
|
subsequentPayloads: new Set(),
|
|
180
182
|
errors: [],
|
|
183
|
+
signal,
|
|
181
184
|
};
|
|
182
185
|
}
|
|
183
186
|
function buildPerEventExecutionContext(exeContext, payload) {
|
|
@@ -219,13 +222,26 @@ function executeOperation(exeContext) {
|
|
|
219
222
|
* for fields that must be executed serially.
|
|
220
223
|
*/
|
|
221
224
|
function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) {
|
|
225
|
+
let abortErrorThrown = false;
|
|
222
226
|
return promiseReduce(fields, (results, [responseName, fieldNodes]) => {
|
|
223
227
|
const fieldPath = addPath(path, responseName, parentType.name);
|
|
228
|
+
if (exeContext.signal?.aborted) {
|
|
229
|
+
results[responseName] = null;
|
|
230
|
+
return results;
|
|
231
|
+
}
|
|
224
232
|
return new ValueOrPromise(() => executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath)).then(result => {
|
|
225
233
|
if (result === undefined) {
|
|
226
234
|
return results;
|
|
227
235
|
}
|
|
228
236
|
results[responseName] = result;
|
|
237
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
238
|
+
exeContext.errors.push(createGraphQLError('Execution aborted', {
|
|
239
|
+
nodes: fieldNodes,
|
|
240
|
+
path: pathToArray(fieldPath),
|
|
241
|
+
originalError: exeContext.signal?.reason,
|
|
242
|
+
}));
|
|
243
|
+
abortErrorThrown = true;
|
|
244
|
+
}
|
|
229
245
|
return results;
|
|
230
246
|
});
|
|
231
247
|
}, Object.create(null)).resolve();
|
|
@@ -237,8 +253,13 @@ function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields
|
|
|
237
253
|
function executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord) {
|
|
238
254
|
const results = Object.create(null);
|
|
239
255
|
let containsPromise = false;
|
|
256
|
+
let abortErrorThrown = false;
|
|
240
257
|
try {
|
|
241
258
|
for (const [responseName, fieldNodes] of fields) {
|
|
259
|
+
if (exeContext.signal?.aborted) {
|
|
260
|
+
results[responseName] = null;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
242
263
|
const fieldPath = addPath(path, responseName, parentType.name);
|
|
243
264
|
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath, asyncPayloadRecord);
|
|
244
265
|
if (result !== undefined) {
|
|
@@ -247,12 +268,20 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
247
268
|
containsPromise = true;
|
|
248
269
|
}
|
|
249
270
|
}
|
|
271
|
+
if (exeContext.signal?.aborted && !abortErrorThrown) {
|
|
272
|
+
exeContext.errors.push(createGraphQLError('Execution aborted', {
|
|
273
|
+
nodes: fieldNodes,
|
|
274
|
+
path: pathToArray(fieldPath),
|
|
275
|
+
originalError: exeContext.signal?.reason,
|
|
276
|
+
}));
|
|
277
|
+
abortErrorThrown = true;
|
|
278
|
+
}
|
|
250
279
|
}
|
|
251
280
|
}
|
|
252
281
|
catch (error) {
|
|
253
282
|
if (containsPromise) {
|
|
254
283
|
// Ensure that any promises returned by other fields are handled, as they may also reject.
|
|
255
|
-
return promiseForObject(results).finally(() => {
|
|
284
|
+
return promiseForObject(results, exeContext.signal).finally(() => {
|
|
256
285
|
throw error;
|
|
257
286
|
});
|
|
258
287
|
}
|
|
@@ -265,7 +294,7 @@ function executeFields(exeContext, parentType, sourceValue, path, fields, asyncP
|
|
|
265
294
|
// Otherwise, results is a map from field name to the result of resolving that
|
|
266
295
|
// field, which is possibly a promise. Return a promise that will return this
|
|
267
296
|
// same map, but with any promises replaced with the values they resolved to.
|
|
268
|
-
return promiseForObject(results);
|
|
297
|
+
return promiseForObject(results, exeContext.signal);
|
|
269
298
|
}
|
|
270
299
|
/**
|
|
271
300
|
* Implements the "Executing fields" section of the spec
|
|
@@ -442,6 +471,14 @@ function getStreamValues(exeContext, fieldNodes, path) {
|
|
|
442
471
|
* recursively until all the results are completed.
|
|
443
472
|
*/
|
|
444
473
|
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) {
|
|
474
|
+
exeContext.signal?.addEventListener('abort', () => {
|
|
475
|
+
iterator.return?.();
|
|
476
|
+
exeContext.errors.push(createGraphQLError('Execution aborted', {
|
|
477
|
+
nodes: fieldNodes,
|
|
478
|
+
path: pathToArray(path),
|
|
479
|
+
originalError: exeContext.signal?.reason,
|
|
480
|
+
}));
|
|
481
|
+
});
|
|
445
482
|
const errors = asyncPayloadRecord?.errors ?? exeContext.errors;
|
|
446
483
|
const stream = getStreamValues(exeContext, fieldNodes, path);
|
|
447
484
|
let containsPromise = false;
|
|
@@ -761,20 +798,24 @@ export function subscribe(args) {
|
|
|
761
798
|
}
|
|
762
799
|
return mapSourceToResponse(exeContext, resultOrStream);
|
|
763
800
|
}
|
|
764
|
-
export function flattenIncrementalResults(incrementalResults) {
|
|
801
|
+
export function flattenIncrementalResults(incrementalResults, signal) {
|
|
765
802
|
const subsequentIterator = incrementalResults.subsequentResults;
|
|
766
803
|
let initialResultSent = false;
|
|
767
804
|
let done = false;
|
|
805
|
+
signal?.addEventListener('abort', () => {
|
|
806
|
+
done = true;
|
|
807
|
+
subsequentIterator.throw?.(signal?.reason);
|
|
808
|
+
});
|
|
768
809
|
return {
|
|
769
810
|
[Symbol.asyncIterator]() {
|
|
770
811
|
return this;
|
|
771
812
|
},
|
|
772
|
-
|
|
813
|
+
next() {
|
|
773
814
|
if (done) {
|
|
774
|
-
return {
|
|
815
|
+
return Promise.resolve({
|
|
775
816
|
value: undefined,
|
|
776
817
|
done,
|
|
777
|
-
};
|
|
818
|
+
});
|
|
778
819
|
}
|
|
779
820
|
if (initialResultSent) {
|
|
780
821
|
return subsequentIterator.next();
|
|
@@ -795,9 +836,9 @@ export function flattenIncrementalResults(incrementalResults) {
|
|
|
795
836
|
},
|
|
796
837
|
};
|
|
797
838
|
}
|
|
798
|
-
async function* ensureAsyncIterable(someExecutionResult) {
|
|
839
|
+
async function* ensureAsyncIterable(someExecutionResult, signal) {
|
|
799
840
|
if ('initialResult' in someExecutionResult) {
|
|
800
|
-
yield* flattenIncrementalResults(someExecutionResult);
|
|
841
|
+
yield* flattenIncrementalResults(someExecutionResult, signal);
|
|
801
842
|
}
|
|
802
843
|
else {
|
|
803
844
|
yield someExecutionResult;
|
|
@@ -813,7 +854,7 @@ function mapSourceToResponse(exeContext, resultOrStream) {
|
|
|
813
854
|
// the GraphQL specification. The `execute` function provides the
|
|
814
855
|
// "ExecuteSubscriptionEvent" algorithm, as it is nearly identical to the
|
|
815
856
|
// "ExecuteQuery" algorithm, for which `execute` is also used.
|
|
816
|
-
return flattenAsyncIterable(mapAsyncIterator(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload))), async function* (error) {
|
|
857
|
+
return flattenAsyncIterable(mapAsyncIterator(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload)), exeContext.signal), async function* (error) {
|
|
817
858
|
const wrappedError = createGraphQLError(error.message, {
|
|
818
859
|
originalError: error,
|
|
819
860
|
nodes: [exeContext.operation],
|
|
@@ -839,14 +880,18 @@ function executeSubscription(exeContext) {
|
|
|
839
880
|
const { schema, fragments, operation, variableValues, rootValue } = exeContext;
|
|
840
881
|
const rootType = schema.getSubscriptionType();
|
|
841
882
|
if (rootType == null) {
|
|
842
|
-
throw createGraphQLError('Schema is not configured to execute subscription operation.', {
|
|
883
|
+
throw createGraphQLError('Schema is not configured to execute subscription operation.', {
|
|
884
|
+
nodes: operation,
|
|
885
|
+
});
|
|
843
886
|
}
|
|
844
887
|
const { fields: rootFields } = collectFields(schema, fragments, variableValues, rootType, operation.selectionSet);
|
|
845
888
|
const [responseName, fieldNodes] = [...rootFields.entries()][0];
|
|
846
889
|
const fieldName = fieldNodes[0].name.value;
|
|
847
890
|
const fieldDef = getFieldDef(schema, rootType, fieldNodes[0]);
|
|
848
891
|
if (!fieldDef) {
|
|
849
|
-
throw createGraphQLError(`The subscription field "${fieldName}" is not defined.`, {
|
|
892
|
+
throw createGraphQLError(`The subscription field "${fieldName}" is not defined.`, {
|
|
893
|
+
nodes: fieldNodes,
|
|
894
|
+
});
|
|
850
895
|
}
|
|
851
896
|
const path = addPath(undefined, responseName, rootType.name);
|
|
852
897
|
const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, rootType, path);
|
|
@@ -869,13 +914,13 @@ function executeSubscription(exeContext) {
|
|
|
869
914
|
throw locatedError(error, fieldNodes, pathToArray(path));
|
|
870
915
|
});
|
|
871
916
|
}
|
|
872
|
-
return assertEventStream(result);
|
|
917
|
+
return assertEventStream(result, exeContext.signal);
|
|
873
918
|
}
|
|
874
919
|
catch (error) {
|
|
875
920
|
throw locatedError(error, fieldNodes, pathToArray(path));
|
|
876
921
|
}
|
|
877
922
|
}
|
|
878
|
-
function assertEventStream(result) {
|
|
923
|
+
function assertEventStream(result, signal) {
|
|
879
924
|
if (result instanceof Error) {
|
|
880
925
|
throw result;
|
|
881
926
|
}
|
|
@@ -883,7 +928,15 @@ function assertEventStream(result) {
|
|
|
883
928
|
if (!isAsyncIterable(result)) {
|
|
884
929
|
throw createGraphQLError('Subscription field must return Async Iterable. ' + `Received: ${inspect(result)}.`);
|
|
885
930
|
}
|
|
886
|
-
return
|
|
931
|
+
return {
|
|
932
|
+
[Symbol.asyncIterator]() {
|
|
933
|
+
const asyncIterator = result[Symbol.asyncIterator]();
|
|
934
|
+
signal?.addEventListener('abort', () => {
|
|
935
|
+
asyncIterator.return?.();
|
|
936
|
+
});
|
|
937
|
+
return asyncIterator;
|
|
938
|
+
},
|
|
939
|
+
};
|
|
887
940
|
}
|
|
888
941
|
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext) {
|
|
889
942
|
const asyncPayloadRecord = new DeferredFragmentRecord({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getOperationAST } from 'graphql';
|
|
2
|
-
import { execute, flattenIncrementalResults, subscribe } from './execute.js';
|
|
3
2
|
import { ValueOrPromise } from 'value-or-promise';
|
|
3
|
+
import { execute, flattenIncrementalResults, subscribe } from './execute.js';
|
|
4
4
|
export function normalizedExecutor(args) {
|
|
5
5
|
const operationAST = getOperationAST(args.document, args.operationName);
|
|
6
6
|
if (operationAST == null) {
|
|
@@ -12,7 +12,7 @@ export function normalizedExecutor(args) {
|
|
|
12
12
|
return new ValueOrPromise(() => execute(args))
|
|
13
13
|
.then((result) => {
|
|
14
14
|
if ('initialResult' in result) {
|
|
15
|
-
return flattenIncrementalResults(result);
|
|
15
|
+
return flattenIncrementalResults(result, args.signal);
|
|
16
16
|
}
|
|
17
17
|
return result;
|
|
18
18
|
})
|
|
@@ -5,10 +5,15 @@
|
|
|
5
5
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
6
6
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
7
7
|
*/
|
|
8
|
-
export async function promiseForObject(object) {
|
|
8
|
+
export async function promiseForObject(object, signal) {
|
|
9
9
|
const resolvedObject = Object.create(null);
|
|
10
|
-
await Promise
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
await new Promise((resolve, reject) => {
|
|
11
|
+
signal?.addEventListener('abort', () => {
|
|
12
|
+
resolve();
|
|
13
|
+
});
|
|
14
|
+
Promise.all(Object.entries(object).map(async ([key, value]) => {
|
|
15
|
+
resolvedObject[key] = await value;
|
|
16
|
+
})).then(() => resolve(), reject);
|
|
17
|
+
});
|
|
13
18
|
return resolvedObject;
|
|
14
19
|
}
|
package/esm/execution/values.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { coerceInputValue, isInputType, isNonNullType, print, typeFromAST, valueFromAST, } from 'graphql';
|
|
2
2
|
import { createGraphQLError, hasOwnProperty, inspect, printPathArray } from '@graphql-tools/utils';
|
|
3
3
|
/**
|
|
4
4
|
* Prepares an object map of variableValues of the correct type based on the
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphql-tools/executor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0-alpha-20230809163713-4e6faf66",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"peerDependencies": {
|
|
6
6
|
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@repeaterjs/repeater": "^3.0.4",
|
|
10
9
|
"@graphql-tools/utils": "^10.0.0",
|
|
11
10
|
"@graphql-typed-document-node/core": "3.2.0",
|
|
11
|
+
"@repeaterjs/repeater": "^3.0.4",
|
|
12
12
|
"tslib": "^2.4.0",
|
|
13
13
|
"value-or-promise": "^1.0.12"
|
|
14
14
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { DocumentNode, FieldNode, FragmentDefinitionNode, GraphQLError, GraphQLField, GraphQLFieldResolver, GraphQLFormattedError, GraphQLObjectType, GraphQLResolveInfo, GraphQLSchema, GraphQLTypeResolver, OperationDefinitionNode } from 'graphql';
|
|
2
|
+
import { Maybe, MaybePromise, Path } from '@graphql-tools/utils';
|
|
3
3
|
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
4
4
|
export interface SingularExecutionResult<TData = any, TExtensions = any> {
|
|
5
5
|
errors?: ReadonlyArray<GraphQLError>;
|
|
@@ -43,6 +43,7 @@ export interface ExecutionContext<TVariables = any, TContext = any> {
|
|
|
43
43
|
subscribeFieldResolver: GraphQLFieldResolver<any, TContext>;
|
|
44
44
|
errors: Array<GraphQLError>;
|
|
45
45
|
subsequentPayloads: Set<AsyncPayloadRecord>;
|
|
46
|
+
signal?: AbortSignal;
|
|
46
47
|
}
|
|
47
48
|
export interface FormattedExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> {
|
|
48
49
|
errors?: ReadonlyArray<GraphQLFormattedError>;
|
|
@@ -107,6 +108,7 @@ export interface ExecutionArgs<TData = any, TVariables = any, TContext = any> {
|
|
|
107
108
|
fieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
108
109
|
typeResolver?: Maybe<GraphQLTypeResolver<any, TContext>>;
|
|
109
110
|
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
111
|
+
signal?: AbortSignal;
|
|
110
112
|
}
|
|
111
113
|
/**
|
|
112
114
|
* Implements the "Executing requests" section of the GraphQL specification,
|
|
@@ -202,7 +204,7 @@ export declare const defaultFieldResolver: GraphQLFieldResolver<unknown, unknown
|
|
|
202
204
|
* Accepts an object with named arguments.
|
|
203
205
|
*/
|
|
204
206
|
export declare function subscribe<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<AsyncGenerator<SingularExecutionResult<TData> | InitialIncrementalExecutionResult<TData> | SubsequentIncrementalExecutionResult<TData>, void, void> | SingularExecutionResult<TData>>;
|
|
205
|
-
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData
|
|
207
|
+
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData>, signal?: AbortSignal): AsyncGenerator<SubsequentIncrementalExecutionResult<TData, Record<string, unknown>>, void, void>;
|
|
206
208
|
declare class DeferredFragmentRecord {
|
|
207
209
|
type: 'defer';
|
|
208
210
|
errors: Array<GraphQLError>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { DocumentNode, FieldNode, FragmentDefinitionNode, GraphQLError, GraphQLField, GraphQLFieldResolver, GraphQLFormattedError, GraphQLObjectType, GraphQLResolveInfo, GraphQLSchema, GraphQLTypeResolver, OperationDefinitionNode } from 'graphql';
|
|
2
|
+
import { Maybe, MaybePromise, Path } from '@graphql-tools/utils';
|
|
3
3
|
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
4
4
|
export interface SingularExecutionResult<TData = any, TExtensions = any> {
|
|
5
5
|
errors?: ReadonlyArray<GraphQLError>;
|
|
@@ -43,6 +43,7 @@ export interface ExecutionContext<TVariables = any, TContext = any> {
|
|
|
43
43
|
subscribeFieldResolver: GraphQLFieldResolver<any, TContext>;
|
|
44
44
|
errors: Array<GraphQLError>;
|
|
45
45
|
subsequentPayloads: Set<AsyncPayloadRecord>;
|
|
46
|
+
signal?: AbortSignal;
|
|
46
47
|
}
|
|
47
48
|
export interface FormattedExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> {
|
|
48
49
|
errors?: ReadonlyArray<GraphQLFormattedError>;
|
|
@@ -107,6 +108,7 @@ export interface ExecutionArgs<TData = any, TVariables = any, TContext = any> {
|
|
|
107
108
|
fieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
108
109
|
typeResolver?: Maybe<GraphQLTypeResolver<any, TContext>>;
|
|
109
110
|
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, TContext>>;
|
|
111
|
+
signal?: AbortSignal;
|
|
110
112
|
}
|
|
111
113
|
/**
|
|
112
114
|
* Implements the "Executing requests" section of the GraphQL specification,
|
|
@@ -202,7 +204,7 @@ export declare const defaultFieldResolver: GraphQLFieldResolver<unknown, unknown
|
|
|
202
204
|
* Accepts an object with named arguments.
|
|
203
205
|
*/
|
|
204
206
|
export declare function subscribe<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<AsyncGenerator<SingularExecutionResult<TData> | InitialIncrementalExecutionResult<TData> | SubsequentIncrementalExecutionResult<TData>, void, void> | SingularExecutionResult<TData>>;
|
|
205
|
-
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData
|
|
207
|
+
export declare function flattenIncrementalResults<TData>(incrementalResults: IncrementalExecutionResults<TData>, signal?: AbortSignal): AsyncGenerator<SubsequentIncrementalExecutionResult<TData, Record<string, unknown>>, void, void>;
|
|
206
208
|
declare class DeferredFragmentRecord {
|
|
207
209
|
type: 'defer';
|
|
208
210
|
errors: Array<GraphQLError>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExecutionResult, MaybeAsyncIterable, MaybePromise } from '@graphql-tools/utils';
|
|
2
2
|
import { ExecutionArgs } from './execute.cjs';
|
|
3
3
|
export declare function normalizedExecutor<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<MaybeAsyncIterable<ExecutionResult<TData>>>;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ExecutionResult, MaybeAsyncIterable, MaybePromise } from '@graphql-tools/utils';
|
|
2
2
|
import { ExecutionArgs } from './execute.js';
|
|
3
3
|
export declare function normalizedExecutor<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<MaybeAsyncIterable<ExecutionResult<TData>>>;
|
|
@@ -8,5 +8,5 @@ type ResolvedObject<TData> = {
|
|
|
8
8
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
9
9
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
10
10
|
*/
|
|
11
|
-
export declare function promiseForObject<TData>(object: TData): Promise<ResolvedObject<TData>>;
|
|
11
|
+
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal): Promise<ResolvedObject<TData>>;
|
|
12
12
|
export {};
|
|
@@ -8,5 +8,5 @@ type ResolvedObject<TData> = {
|
|
|
8
8
|
* This is akin to bluebird's `Promise.props`, but implemented only using
|
|
9
9
|
* `Promise.all` so it will work with any implementation of ES6 promises.
|
|
10
10
|
*/
|
|
11
|
-
export declare function promiseForObject<TData>(object: TData): Promise<ResolvedObject<TData>>;
|
|
11
|
+
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal): Promise<ResolvedObject<TData>>;
|
|
12
12
|
export {};
|