@graphql-tools/executor
Advanced tools
Comparing version
@@ -153,3 +153,2 @@ "use strict"; | ||
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args; | ||
signal?.throwIfAborted(); | ||
// If the schema used for execution is invalid, throw an error. | ||
@@ -209,24 +208,2 @@ (0, graphql_1.assertValidSchema)(schema); | ||
} | ||
signal?.throwIfAborted(); | ||
let onSignalAbort; | ||
let signalPromise; | ||
if (signal) { | ||
const listeners = new Set(); | ||
const signalDeferred = (0, promise_helpers_1.createDeferredPromise)(); | ||
signalPromise = signalDeferred.promise; | ||
const sharedListener = () => { | ||
signalDeferred.reject(signal.reason); | ||
signal.removeEventListener('abort', sharedListener); | ||
}; | ||
signal.addEventListener('abort', sharedListener, { once: true }); | ||
signalPromise.catch(() => { | ||
for (const listener of listeners) { | ||
listener(); | ||
} | ||
listeners.clear(); | ||
}); | ||
onSignalAbort = handler => { | ||
listeners.add(handler); | ||
}; | ||
} | ||
return { | ||
@@ -245,4 +222,2 @@ schema, | ||
signal, | ||
onSignalAbort, | ||
signalPromise, | ||
}; | ||
@@ -322,5 +297,5 @@ } | ||
catch (error) { | ||
if (error !== exeContext.signal?.reason && containsPromise) { | ||
if (containsPromise) { | ||
// Ensure that any promises returned by other fields are handled, as they may also reject. | ||
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal, exeContext.signalPromise).finally(() => { | ||
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal).finally(() => { | ||
throw error; | ||
@@ -338,3 +313,3 @@ }); | ||
// same map, but with any promises replaced with the values they resolved to. | ||
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal, exeContext.signalPromise); | ||
return (0, promiseForObject_js_1.promiseForObject)(results, exeContext.signal); | ||
} | ||
@@ -358,3 +333,2 @@ /** | ||
try { | ||
exeContext.signal?.throwIfAborted(); | ||
// Build a JS object of arguments from the field.arguments AST, using the | ||
@@ -541,5 +515,4 @@ // variables scope to fulfill any variable references. | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) { | ||
exeContext.signal?.throwIfAborted(); | ||
if (iterator.return) { | ||
exeContext.onSignalAbort?.(() => { | ||
if (exeContext.signal && iterator.return) { | ||
(0, utils_1.registerAbortSignalListener)(exeContext.signal, () => { | ||
iterator.return?.(); | ||
@@ -986,9 +959,7 @@ }); | ||
if ((0, utils_1.isPromise)(result)) { | ||
return result | ||
.then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort)) | ||
.then(undefined, error => { | ||
return result.then(assertEventStream).then(undefined, error => { | ||
throw (0, graphql_1.locatedError)(error, fieldNodes, (0, utils_1.pathToArray)(path)); | ||
}); | ||
} | ||
return assertEventStream(result, exeContext.signal, exeContext.onSignalAbort); | ||
return assertEventStream(result, exeContext.signal); | ||
} | ||
@@ -999,4 +970,3 @@ catch (error) { | ||
} | ||
function assertEventStream(result, signal, onSignalAbort) { | ||
signal?.throwIfAborted(); | ||
function assertEventStream(result, signal) { | ||
if (result instanceof Error) { | ||
@@ -1009,3 +979,3 @@ throw result; | ||
} | ||
if (onSignalAbort) { | ||
if (signal) { | ||
return { | ||
@@ -1015,3 +985,3 @@ [Symbol.asyncIterator]() { | ||
if (asyncIterator.return) { | ||
onSignalAbort?.(() => { | ||
(0, utils_1.registerAbortSignalListener)(signal, () => { | ||
asyncIterator.return?.(); | ||
@@ -1244,2 +1214,3 @@ }); | ||
let isDone = false; | ||
const abortPromise = exeContext.signal ? (0, utils_1.getAbortPromise)(exeContext.signal) : undefined; | ||
async function next() { | ||
@@ -1250,4 +1221,4 @@ if (isDone) { | ||
const subSequentPayloadPromises = Array.from(exeContext.subsequentPayloads).map(record => record.promise); | ||
if (exeContext.signalPromise) { | ||
await Promise.race([exeContext.signalPromise, ...subSequentPayloadPromises]); | ||
if (abortPromise) { | ||
await Promise.race([abortPromise, ...subSequentPayloadPromises]); | ||
} | ||
@@ -1254,0 +1225,0 @@ else { |
@@ -12,23 +12,12 @@ "use strict"; | ||
*/ | ||
function promiseForObject(object, signal, signalPromise) { | ||
signal?.throwIfAborted(); | ||
async function promiseForObject(object, signal) { | ||
const resolvedObject = Object.create(null); | ||
const promises = []; | ||
for (const key in object) { | ||
const value = object[key]; | ||
if ((0, utils_1.isPromise)(value)) { | ||
promises.push(value.then(value => { | ||
signal?.throwIfAborted(); | ||
resolvedObject[key] = value; | ||
})); | ||
} | ||
else { | ||
resolvedObject[key] = value; | ||
} | ||
const promises = Promise.all(Object.entries(object).map(async ([key, value]) => { | ||
resolvedObject[key] = await value; | ||
})); | ||
if (signal) { | ||
const abortPromise = (0, utils_1.getAbortPromise)(signal); | ||
return Promise.race([abortPromise, promises]).then(() => resolvedObject); | ||
} | ||
const promiseAll = Promise.all(promises); | ||
if (signalPromise) { | ||
return Promise.race([signalPromise, promiseAll]).then(() => resolvedObject); | ||
} | ||
return promiseAll.then(() => resolvedObject); | ||
return promises.then(() => resolvedObject); | ||
} |
import { assertValidSchema, getDirectiveValues, GraphQLError, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, Kind, locatedError, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, versionInfo, } from 'graphql'; | ||
import { collectSubFields as _collectSubfields, addPath, collectFields, createGraphQLError, fakePromise, getArgumentValues, getDefinedRootType, GraphQLStreamDirective, inspect, isAsyncIterable, isIterableObject, isObjectLike, isPromise, mapAsyncIterator, memoize1, memoize3, pathToArray, promiseReduce, } from '@graphql-tools/utils'; | ||
import { collectSubFields as _collectSubfields, addPath, collectFields, createGraphQLError, fakePromise, getAbortPromise, getArgumentValues, getDefinedRootType, GraphQLStreamDirective, inspect, isAsyncIterable, isIterableObject, isObjectLike, isPromise, mapAsyncIterator, memoize1, memoize3, pathToArray, promiseReduce, registerAbortSignalListener, } from '@graphql-tools/utils'; | ||
import { DisposableSymbols } from '@whatwg-node/disposablestack'; | ||
import { createDeferredPromise, handleMaybePromise } from '@whatwg-node/promise-helpers'; | ||
import { handleMaybePromise } from '@whatwg-node/promise-helpers'; | ||
import { coerceError } from './coerceError.js'; | ||
@@ -140,3 +140,2 @@ import { flattenAsyncIterable } from './flattenAsyncIterable.js'; | ||
const { schema, document, rootValue, contextValue, variableValues: rawVariableValues, operationName, fieldResolver, typeResolver, subscribeFieldResolver, signal, } = args; | ||
signal?.throwIfAborted(); | ||
// If the schema used for execution is invalid, throw an error. | ||
@@ -196,24 +195,2 @@ assertValidSchema(schema); | ||
} | ||
signal?.throwIfAborted(); | ||
let onSignalAbort; | ||
let signalPromise; | ||
if (signal) { | ||
const listeners = new Set(); | ||
const signalDeferred = createDeferredPromise(); | ||
signalPromise = signalDeferred.promise; | ||
const sharedListener = () => { | ||
signalDeferred.reject(signal.reason); | ||
signal.removeEventListener('abort', sharedListener); | ||
}; | ||
signal.addEventListener('abort', sharedListener, { once: true }); | ||
signalPromise.catch(() => { | ||
for (const listener of listeners) { | ||
listener(); | ||
} | ||
listeners.clear(); | ||
}); | ||
onSignalAbort = handler => { | ||
listeners.add(handler); | ||
}; | ||
} | ||
return { | ||
@@ -232,4 +209,2 @@ schema, | ||
signal, | ||
onSignalAbort, | ||
signalPromise, | ||
}; | ||
@@ -309,5 +284,5 @@ } | ||
catch (error) { | ||
if (error !== exeContext.signal?.reason && containsPromise) { | ||
if (containsPromise) { | ||
// Ensure that any promises returned by other fields are handled, as they may also reject. | ||
return promiseForObject(results, exeContext.signal, exeContext.signalPromise).finally(() => { | ||
return promiseForObject(results, exeContext.signal).finally(() => { | ||
throw error; | ||
@@ -325,3 +300,3 @@ }); | ||
// same map, but with any promises replaced with the values they resolved to. | ||
return promiseForObject(results, exeContext.signal, exeContext.signalPromise); | ||
return promiseForObject(results, exeContext.signal); | ||
} | ||
@@ -345,3 +320,2 @@ /** | ||
try { | ||
exeContext.signal?.throwIfAborted(); | ||
// Build a JS object of arguments from the field.arguments AST, using the | ||
@@ -528,5 +502,4 @@ // variables scope to fulfill any variable references. | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) { | ||
exeContext.signal?.throwIfAborted(); | ||
if (iterator.return) { | ||
exeContext.onSignalAbort?.(() => { | ||
if (exeContext.signal && iterator.return) { | ||
registerAbortSignalListener(exeContext.signal, () => { | ||
iterator.return?.(); | ||
@@ -971,9 +944,7 @@ }); | ||
if (isPromise(result)) { | ||
return result | ||
.then(result => assertEventStream(result, exeContext.signal, exeContext.onSignalAbort)) | ||
.then(undefined, error => { | ||
return result.then(assertEventStream).then(undefined, error => { | ||
throw locatedError(error, fieldNodes, pathToArray(path)); | ||
}); | ||
} | ||
return assertEventStream(result, exeContext.signal, exeContext.onSignalAbort); | ||
return assertEventStream(result, exeContext.signal); | ||
} | ||
@@ -984,4 +955,3 @@ catch (error) { | ||
} | ||
function assertEventStream(result, signal, onSignalAbort) { | ||
signal?.throwIfAborted(); | ||
function assertEventStream(result, signal) { | ||
if (result instanceof Error) { | ||
@@ -994,3 +964,3 @@ throw result; | ||
} | ||
if (onSignalAbort) { | ||
if (signal) { | ||
return { | ||
@@ -1000,3 +970,3 @@ [Symbol.asyncIterator]() { | ||
if (asyncIterator.return) { | ||
onSignalAbort?.(() => { | ||
registerAbortSignalListener(signal, () => { | ||
asyncIterator.return?.(); | ||
@@ -1229,2 +1199,3 @@ }); | ||
let isDone = false; | ||
const abortPromise = exeContext.signal ? getAbortPromise(exeContext.signal) : undefined; | ||
async function next() { | ||
@@ -1235,4 +1206,4 @@ if (isDone) { | ||
const subSequentPayloadPromises = Array.from(exeContext.subsequentPayloads).map(record => record.promise); | ||
if (exeContext.signalPromise) { | ||
await Promise.race([exeContext.signalPromise, ...subSequentPayloadPromises]); | ||
if (abortPromise) { | ||
await Promise.race([abortPromise, ...subSequentPayloadPromises]); | ||
} | ||
@@ -1239,0 +1210,0 @@ else { |
@@ -1,2 +0,2 @@ | ||
import { isPromise } from '@graphql-tools/utils'; | ||
import { getAbortPromise } from '@graphql-tools/utils'; | ||
/** | ||
@@ -9,23 +9,12 @@ * This function transforms a JS object `Record<string, Promise<T>>` into | ||
*/ | ||
export function promiseForObject(object, signal, signalPromise) { | ||
signal?.throwIfAborted(); | ||
export async function promiseForObject(object, signal) { | ||
const resolvedObject = Object.create(null); | ||
const promises = []; | ||
for (const key in object) { | ||
const value = object[key]; | ||
if (isPromise(value)) { | ||
promises.push(value.then(value => { | ||
signal?.throwIfAborted(); | ||
resolvedObject[key] = value; | ||
})); | ||
} | ||
else { | ||
resolvedObject[key] = value; | ||
} | ||
const promises = Promise.all(Object.entries(object).map(async ([key, value]) => { | ||
resolvedObject[key] = await value; | ||
})); | ||
if (signal) { | ||
const abortPromise = getAbortPromise(signal); | ||
return Promise.race([abortPromise, promises]).then(() => resolvedObject); | ||
} | ||
const promiseAll = Promise.all(promises); | ||
if (signalPromise) { | ||
return Promise.race([signalPromise, promiseAll]).then(() => resolvedObject); | ||
} | ||
return promiseAll.then(() => resolvedObject); | ||
return promises.then(() => resolvedObject); | ||
} |
{ | ||
"name": "@graphql-tools/executor", | ||
"version": "1.4.3-alpha-20250226150456-c866968c9e16e4eb2d1460dcbf97397c4a27ca60", | ||
"version": "1.4.3-alpha-20250303233029-5b75d14ad566ee286424ed075aa252b89e3c6e04", | ||
"sideEffects": false, | ||
@@ -9,3 +9,3 @@ "peerDependencies": { | ||
"dependencies": { | ||
"@graphql-tools/utils": "10.8.4-alpha-20250226150456-c866968c9e16e4eb2d1460dcbf97397c4a27ca60", | ||
"@graphql-tools/utils": "10.8.4-alpha-20250303233029-5b75d14ad566ee286424ed075aa252b89e3c6e04", | ||
"@graphql-typed-document-node/core": "^3.2.0", | ||
@@ -12,0 +12,0 @@ "@repeaterjs/repeater": "^3.0.4", |
@@ -47,4 +47,2 @@ import { DocumentNode, FieldNode, FragmentDefinitionNode, GraphQLError, GraphQLField, GraphQLFieldResolver, GraphQLFormattedError, GraphQLObjectType, GraphQLSchema, GraphQLTypeResolver, OperationDefinitionNode } from 'graphql'; | ||
signal?: AbortSignal; | ||
onSignalAbort?(handler: () => void): void; | ||
signalPromise?: Promise<never>; | ||
} | ||
@@ -51,0 +49,0 @@ export interface FormattedExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> { |
@@ -11,3 +11,3 @@ type ResolvedObject<TData> = { | ||
*/ | ||
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal, signalPromise?: Promise<never>): Promise<ResolvedObject<TData>>; | ||
export declare function promiseForObject<TData>(object: TData, signal?: AbortSignal): Promise<ResolvedObject<TData>>; | ||
export {}; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
173144
-1.58%3587
-2.23%+ Added
- Removed
Updated