@graphql-tools/executor
Advanced tools
Comparing version 0.0.3-alpha-20221101131317-20a4af5d to 0.0.3-alpha-20221101140152-8ae0755c
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isIncrementalResult = exports.getFieldDef = exports.createSourceEventStream = exports.subscribe = exports.defaultFieldResolver = exports.defaultTypeResolver = exports.buildResolveInfo = exports.buildExecutionContext = exports.assertValidExecutionArguments = exports.executeSync = exports.execute = void 0; | ||
exports.getFieldDef = exports.createSourceEventStream = exports.subscribe = exports.defaultFieldResolver = exports.defaultTypeResolver = exports.buildResolveInfo = exports.buildExecutionContext = exports.assertValidExecutionArguments = exports.executeSync = exports.execute = void 0; | ||
const graphql_1 = require("graphql"); | ||
const utils_1 = require("@graphql-tools/utils"); | ||
const values_js_1 = require("./values.js"); | ||
const promiseForObject_js_1 = require("./promiseForObject.js"); | ||
const flattenAsyncIterable_js_1 = require("./flattenAsyncIterable.js"); | ||
const invariant_js_1 = require("./invariant.js"); | ||
const value_or_promise_1 = require("value-or-promise"); | ||
/** | ||
* A memoized collection of relevant subfields with regard to the return | ||
* type. Memoizing ensures the subfields are not repeatedly calculated, which | ||
* saves overhead when resolving lists of values. | ||
*/ | ||
const collectSubfields = (0, utils_1.memoize3)((exeContext, returnType, fieldNodes) => (0, utils_1.collectSubFields)(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes)); | ||
/** | ||
* Implements the "Executing requests" section of the GraphQL specification, | ||
* including `@defer` and `@stream` as proposed in | ||
* https://github.com/graphql/graphql-spec/pull/742 | ||
* Implements the "Executing requests" section of the GraphQL specification. | ||
* | ||
* This function returns a Promise of an IncrementalExecutionResults | ||
* object. This object either consists of a single ExecutionResult, or an | ||
* object containing an `initialResult` and a stream of `subsequentResults`. | ||
* Returns either a synchronous ExecutionResult (if all encountered resolvers | ||
* are synchronous), or a Promise of an ExecutionResult that will eventually be | ||
* resolved and never rejected. | ||
* | ||
@@ -52,20 +40,16 @@ * If the arguments to this function do not result in a legal execution context, | ||
// in this case is the entire response. | ||
return new value_or_promise_1.ValueOrPromise(() => executeOperation(exeContext)) | ||
.then(data => { | ||
const initialResult = buildResponse(data, exeContext.errors); | ||
if (exeContext.subsequentPayloads.size > 0) { | ||
return { | ||
initialResult: { | ||
...initialResult, | ||
hasNext: true, | ||
}, | ||
subsequentResults: yieldSubsequentPayloads(exeContext), | ||
}; | ||
try { | ||
const result = executeOperation(exeContext); | ||
if ((0, utils_1.isPromise)(result)) { | ||
return result.then(data => buildResponse(data, exeContext.errors), error => { | ||
exeContext.errors.push(error); | ||
return buildResponse(null, exeContext.errors); | ||
}); | ||
} | ||
return initialResult; | ||
}, (error) => { | ||
return buildResponse(result, exeContext.errors); | ||
} | ||
catch (error) { | ||
exeContext.errors.push(error); | ||
return buildResponse(null, exeContext.errors); | ||
}) | ||
.resolve(); | ||
} | ||
} | ||
@@ -80,3 +64,3 @@ /** | ||
// Assert that the execution was synchronous. | ||
if ((0, utils_1.isPromise)(result) || 'initialResult' in result) { | ||
if ((0, utils_1.isPromise)(result)) { | ||
throw new Error('GraphQL execution failed to complete synchronously.'); | ||
@@ -169,3 +153,2 @@ } | ||
subscribeFieldResolver: subscribeFieldResolver !== null && subscribeFieldResolver !== void 0 ? subscribeFieldResolver : exports.defaultFieldResolver, | ||
subsequentPayloads: new Set(), | ||
errors: [], | ||
@@ -179,3 +162,2 @@ }; | ||
rootValue: payload, | ||
subsequentPayloads: new Set(), | ||
errors: [], | ||
@@ -190,21 +172,15 @@ }; | ||
const rootType = (0, utils_1.getDefinedRootType)(schema, operation.operation, [operation]); | ||
if (rootType == null) { | ||
(0, utils_1.createGraphQLError)(`Schema is not configured to execute ${operation.operation} operation.`, { | ||
nodes: operation, | ||
}); | ||
} | ||
const { fields: rootFields, patches } = (0, utils_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const rootFields = (0, utils_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const path = undefined; | ||
let result; | ||
if (operation.operation === 'mutation') { | ||
result = executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields); | ||
switch (operation.operation) { | ||
case 'query': | ||
return executeFields(exeContext, rootType, rootValue, path, rootFields); | ||
case 'mutation': | ||
return executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields); | ||
case 'subscription': | ||
// TODO: deprecate `subscribe` and move all logic here | ||
// Temporary solution until we finish merging execute and subscribe together | ||
return executeFields(exeContext, rootType, rootValue, path, rootFields); | ||
} | ||
else { | ||
result = executeFields(exeContext, rootType, rootValue, path, rootFields); | ||
} | ||
for (const patch of patches) { | ||
const { label, fields: patchFields } = patch; | ||
executeDeferredFragment(exeContext, rootType, rootValue, patchFields, label, path); | ||
} | ||
return result; | ||
throw new Error(`Can only execute queries, mutations and subscriptions, got "${operation.operation}".`); | ||
} | ||
@@ -216,13 +192,16 @@ /** | ||
function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) { | ||
return (0, utils_1.promiseReduce)(fields, (results, [responseName, fieldNodes]) => { | ||
return (0, utils_1.promiseReduce)(fields.entries(), (results, [responseName, fieldNodes]) => { | ||
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name); | ||
return new value_or_promise_1.ValueOrPromise(() => executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath)) | ||
.then(result => { | ||
if (result === undefined) { | ||
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath); | ||
if (result === undefined) { | ||
return results; | ||
} | ||
if ((0, utils_1.isPromise)(result)) { | ||
return result.then(resolvedResult => { | ||
results[responseName] = resolvedResult; | ||
return results; | ||
} | ||
results[responseName] = result; | ||
return results; | ||
}) | ||
.resolve(); | ||
}); | ||
} | ||
results[responseName] = result; | ||
return results; | ||
}, Object.create(null)); | ||
@@ -234,26 +213,15 @@ } | ||
*/ | ||
function executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord) { | ||
function executeFields(exeContext, parentType, sourceValue, path, fields) { | ||
const results = Object.create(null); | ||
let containsPromise = false; | ||
try { | ||
for (const [responseName, fieldNodes] of fields) { | ||
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name); | ||
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath, asyncPayloadRecord); | ||
if (result !== undefined) { | ||
results[responseName] = result; | ||
if ((0, utils_1.isPromise)(result)) { | ||
containsPromise = true; | ||
} | ||
for (const [responseName, fieldNodes] of fields.entries()) { | ||
const fieldPath = (0, utils_1.addPath)(path, responseName, parentType.name); | ||
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath); | ||
if (result !== undefined) { | ||
results[responseName] = result; | ||
if ((0, utils_1.isPromise)(result)) { | ||
containsPromise = true; | ||
} | ||
} | ||
} | ||
catch (error) { | ||
if (containsPromise) { | ||
// Ensure that any promises returned by other fields are handled, as they may also reject. | ||
return (0, promiseForObject_js_1.promiseForObject)(results).finally(() => { | ||
throw error; | ||
}); | ||
} | ||
throw error; | ||
} | ||
// If there are no promises, we can just return the object | ||
@@ -266,3 +234,9 @@ if (!containsPromise) { | ||
// same map, but with any promises replaced with the values they resolved to. | ||
return (0, promiseForObject_js_1.promiseForObject)(results); | ||
return Promise.all(Object.values(results)).then(resolvedValues => { | ||
const resolvedObject = Object.create(null); | ||
for (const [i, key] of Object.keys(results).entries()) { | ||
resolvedObject[key] = resolvedValues[i]; | ||
} | ||
return resolvedObject; | ||
}); | ||
} | ||
@@ -275,5 +249,4 @@ /** | ||
*/ | ||
function executeField(exeContext, parentType, source, fieldNodes, path, asyncPayloadRecord) { | ||
var _a, _b; | ||
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors; | ||
function executeField(exeContext, parentType, source, fieldNodes, path) { | ||
var _a; | ||
const fieldDef = getFieldDef(exeContext.schema, parentType, fieldNodes[0]); | ||
@@ -284,3 +257,3 @@ if (!fieldDef) { | ||
const returnType = fieldDef.type; | ||
const resolveFn = (_b = fieldDef.resolve) !== null && _b !== void 0 ? _b : exeContext.fieldResolver; | ||
const resolveFn = (_a = fieldDef.resolve) !== null && _a !== void 0 ? _a : exeContext.fieldResolver; | ||
const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path); | ||
@@ -300,6 +273,6 @@ // Get the resolve function, regardless of if its result is normal or abrupt (error). | ||
if ((0, utils_1.isPromise)(result)) { | ||
completed = result.then(resolved => completeValue(exeContext, returnType, fieldNodes, info, path, resolved, asyncPayloadRecord)); | ||
completed = result.then(resolved => completeValue(exeContext, returnType, fieldNodes, info, path, resolved)); | ||
} | ||
else { | ||
completed = completeValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
completed = completeValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
@@ -311,5 +284,3 @@ if ((0, utils_1.isPromise)(completed)) { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(path)); | ||
const handledError = handleFieldError(error, returnType, errors); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return handledError; | ||
return handleFieldError(error, returnType, exeContext); | ||
}); | ||
@@ -321,5 +292,3 @@ } | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(path)); | ||
const handledError = handleFieldError(error, returnType, errors); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return handledError; | ||
return handleFieldError(error, returnType, exeContext); | ||
} | ||
@@ -348,3 +317,3 @@ } | ||
exports.buildResolveInfo = buildResolveInfo; | ||
function handleFieldError(error, returnType, errors) { | ||
function handleFieldError(error, returnType, exeContext) { | ||
// If the field type is non-nullable, then it is resolved without any | ||
@@ -357,3 +326,3 @@ // protection from errors, however it still properly locates the error. | ||
// a null value for this field if one is encountered. | ||
errors.push(error); | ||
exeContext.errors.push(error); | ||
return null; | ||
@@ -382,3 +351,3 @@ } | ||
*/ | ||
function completeValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
function completeValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
// If result is an Error, throw a located error. | ||
@@ -391,3 +360,3 @@ if (result instanceof Error) { | ||
if ((0, graphql_1.isNonNullType)(returnType)) { | ||
const completed = completeValue(exeContext, returnType.ofType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
const completed = completeValue(exeContext, returnType.ofType, fieldNodes, info, path, result); | ||
if (completed === null) { | ||
@@ -404,3 +373,3 @@ throw new Error(`Cannot return null for non-nullable field ${info.parentType.name}.${info.fieldName}.`); | ||
if ((0, graphql_1.isListType)(returnType)) { | ||
return completeListValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeListValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
@@ -415,7 +384,7 @@ // If field type is a leaf type, Scalar or Enum, serialize to a valid value, | ||
if ((0, graphql_1.isAbstractType)(returnType)) { | ||
return completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
// If field type is Object, execute and complete all sub-selections. | ||
if ((0, graphql_1.isObjectType)(returnType)) { | ||
return completeObjectValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeObjectValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
@@ -427,35 +396,6 @@ /* c8 ignore next 6 */ | ||
/** | ||
* Returns an object containing the `@stream` arguments if a field should be | ||
* streamed based on the experimental flag, stream directive present and | ||
* not disabled by the "if" argument. | ||
*/ | ||
function getStreamValues(exeContext, fieldNodes, path) { | ||
// do not stream inner lists of multi-dimensional lists | ||
if (typeof path.key === 'number') { | ||
return; | ||
} | ||
// validation only allows equivalent streams on multiple fields, so it is | ||
// safe to only check the first fieldNode for the stream directive | ||
const stream = (0, graphql_1.getDirectiveValues)(utils_1.GraphQLStreamDirective, fieldNodes[0], exeContext.variableValues); | ||
if (!stream) { | ||
return; | ||
} | ||
if (stream['if'] === false) { | ||
return; | ||
} | ||
(0, invariant_js_1.invariant)(typeof stream['initialCount'] === 'number', 'initialCount must be a number'); | ||
(0, invariant_js_1.invariant)(stream['initialCount'] >= 0, 'initialCount must be a positive integer'); | ||
return { | ||
initialCount: stream['initialCount'], | ||
label: typeof stream['label'] === 'string' ? stream['label'] : undefined, | ||
}; | ||
} | ||
/** | ||
* Complete a async iterator value by completing the result and calling | ||
* recursively until all the results are completed. | ||
*/ | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) { | ||
var _a; | ||
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors; | ||
const stream = getStreamValues(exeContext, fieldNodes, path); | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator) { | ||
let containsPromise = false; | ||
@@ -465,22 +405,28 @@ const completedResults = []; | ||
while (true) { | ||
if (stream && typeof stream.initialCount === 'number' && index >= stream.initialCount) { | ||
executeStreamIterator(index, iterator, exeContext, fieldNodes, info, itemType, path, stream.label, asyncPayloadRecord); | ||
break; | ||
} | ||
const itemPath = (0, utils_1.addPath)(path, index, undefined); | ||
let iteration; | ||
const fieldPath = (0, utils_1.addPath)(path, index, undefined); | ||
try { | ||
iteration = await iterator.next(); | ||
if (iteration.done) { | ||
const { value, done } = await iterator.next(); | ||
if (done) { | ||
break; | ||
} | ||
try { | ||
// TODO can the error checking logic be consolidated with completeListValue? | ||
const completedItem = completeValue(exeContext, itemType, fieldNodes, info, fieldPath, value); | ||
if ((0, utils_1.isPromise)(completedItem)) { | ||
containsPromise = true; | ||
} | ||
completedResults.push(completedItem); | ||
} | ||
catch (rawError) { | ||
completedResults.push(null); | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(fieldPath)); | ||
handleFieldError(error, itemType, exeContext); | ||
} | ||
} | ||
catch (rawError) { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
completedResults.push(handleFieldError(error, itemType, errors)); | ||
completedResults.push(null); | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(fieldPath)); | ||
handleFieldError(error, itemType, exeContext); | ||
break; | ||
} | ||
if (completeListItemValue(iteration.value, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord)) { | ||
containsPromise = true; | ||
} | ||
index += 1; | ||
@@ -494,9 +440,7 @@ } | ||
*/ | ||
function completeListValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
var _a; | ||
function completeListValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
const itemType = returnType.ofType; | ||
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors; | ||
if ((0, utils_1.isAsyncIterable)(result)) { | ||
const iterator = result[Symbol.asyncIterator](); | ||
return completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord); | ||
return completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator); | ||
} | ||
@@ -506,61 +450,36 @@ if (!(0, utils_1.isIterableObject)(result)) { | ||
} | ||
const stream = getStreamValues(exeContext, fieldNodes, path); | ||
// This is specified as a simple map, however we're optimizing the path | ||
// where the list contains no Promises by avoiding creating another Promise. | ||
let containsPromise = false; | ||
let previousAsyncPayloadRecord = asyncPayloadRecord; | ||
const completedResults = []; | ||
let index = 0; | ||
for (const item of result) { | ||
const completedResults = Array.from(result, (item, index) => { | ||
// No need to modify the info object containing the path, | ||
// since from here on it is not ever accessed by resolver functions. | ||
const itemPath = (0, utils_1.addPath)(path, index, undefined); | ||
if (stream && typeof stream.initialCount === 'number' && index >= stream.initialCount) { | ||
previousAsyncPayloadRecord = executeStreamField(path, itemPath, item, exeContext, fieldNodes, info, itemType, stream.label, previousAsyncPayloadRecord); | ||
index++; | ||
continue; | ||
try { | ||
let completedItem; | ||
if ((0, utils_1.isPromise)(item)) { | ||
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved)); | ||
} | ||
else { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item); | ||
} | ||
if ((0, utils_1.isPromise)(completedItem)) { | ||
containsPromise = true; | ||
// Note: we don't rely on a `catch` method, but we do expect "thenable" | ||
// to take a second callback for the error case. | ||
return completedItem.then(undefined, rawError => { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
return handleFieldError(error, itemType, exeContext); | ||
}); | ||
} | ||
return completedItem; | ||
} | ||
if (completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord)) { | ||
containsPromise = true; | ||
catch (rawError) { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
return handleFieldError(error, itemType, exeContext); | ||
} | ||
index++; | ||
} | ||
}); | ||
return containsPromise ? Promise.all(completedResults) : completedResults; | ||
} | ||
/** | ||
* Complete a list item value by adding it to the completed results. | ||
* | ||
* Returns true if the value is a Promise. | ||
*/ | ||
function completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord) { | ||
try { | ||
let completedItem; | ||
if ((0, utils_1.isPromise)(item)) { | ||
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord)); | ||
} | ||
else { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord); | ||
} | ||
if ((0, utils_1.isPromise)(completedItem)) { | ||
// Note: we don't rely on a `catch` method, but we do expect "thenable" | ||
// to take a second callback for the error case. | ||
completedResults.push(completedItem.then(undefined, rawError => { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
const handledError = handleFieldError(error, itemType, errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return handledError; | ||
})); | ||
return true; | ||
} | ||
completedResults.push(completedItem); | ||
} | ||
catch (rawError) { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
const handledError = handleFieldError(error, itemType, errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
completedResults.push(handledError); | ||
} | ||
return false; | ||
} | ||
/** | ||
* Complete a Scalar or Enum by serializing to a valid value, returning | ||
@@ -581,3 +500,3 @@ * null if serialization is not possible. | ||
*/ | ||
function completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
function completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
var _a; | ||
@@ -588,5 +507,5 @@ const resolveTypeFn = (_a = returnType.resolveType) !== null && _a !== void 0 ? _a : exeContext.typeResolver; | ||
if ((0, utils_1.isPromise)(runtimeType)) { | ||
return runtimeType.then(resolvedRuntimeType => completeObjectValue(exeContext, ensureValidRuntimeType(resolvedRuntimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result, asyncPayloadRecord)); | ||
return runtimeType.then(resolvedRuntimeType => completeObjectValue(exeContext, ensureValidRuntimeType(resolvedRuntimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result)); | ||
} | ||
return completeObjectValue(exeContext, ensureValidRuntimeType(runtimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeObjectValue(exeContext, ensureValidRuntimeType(runtimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result); | ||
} | ||
@@ -621,3 +540,5 @@ function ensureValidRuntimeType(runtimeTypeName, exeContext, returnType, fieldNodes, info, result) { | ||
*/ | ||
function completeObjectValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
function completeObjectValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
// Collect sub-fields to execute to complete this value. | ||
const subFieldNodes = (0, utils_1.collectSubFields)(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes); | ||
// If there is an isTypeOf predicate function, call it with the | ||
@@ -633,3 +554,3 @@ // current result. If isTypeOf returns false, then raise an error rather | ||
} | ||
return collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord); | ||
return executeFields(exeContext, returnType, result, path, subFieldNodes); | ||
}); | ||
@@ -641,3 +562,3 @@ } | ||
} | ||
return collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord); | ||
return executeFields(exeContext, returnType, result, path, subFieldNodes); | ||
} | ||
@@ -649,12 +570,2 @@ function invalidReturnTypeError(returnType, result, fieldNodes) { | ||
} | ||
function collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord) { | ||
// Collect sub-fields to execute to complete this value. | ||
const { fields: subFieldNodes, patches: subPatches } = collectSubfields(exeContext, returnType, fieldNodes); | ||
const subFields = executeFields(exeContext, returnType, result, path, subFieldNodes, asyncPayloadRecord); | ||
for (const subPatch of subPatches) { | ||
const { label, fields: subPatchFieldNodes } = subPatch; | ||
executeDeferredFragment(exeContext, returnType, result, subPatchFieldNodes, label, path, asyncPayloadRecord); | ||
} | ||
return subFields; | ||
} | ||
/** | ||
@@ -719,5 +630,3 @@ * If a resolveType function is not given, then a default resolve behavior is | ||
/** | ||
* Implements the "Subscribe" algorithm described in the GraphQL specification, | ||
* including `@defer` and `@stream` as proposed in | ||
* https://github.com/graphql/graphql-spec/pull/742 | ||
* Implements the "Subscribe" algorithm described in the GraphQL specification. | ||
* | ||
@@ -730,23 +639,13 @@ * Returns a Promise which resolves to either an AsyncIterator (if successful) | ||
* If the client-provided arguments to this function do not result in a | ||
* compliant subscription, a GraphQL Response (ExecutionResult) with descriptive | ||
* errors and no data will be returned. | ||
* compliant subscription, a GraphQL Response (ExecutionResult) with | ||
* descriptive errors and no data will be returned. | ||
* | ||
* If the source stream could not be created due to faulty subscription resolver | ||
* logic or underlying systems, the promise will resolve to a single | ||
* If the source stream could not be created due to faulty subscription | ||
* resolver logic or underlying systems, the promise will resolve to a single | ||
* ExecutionResult containing `errors` and no `data`. | ||
* | ||
* If the operation succeeded, the promise resolves to an AsyncIterator, which | ||
* yields a stream of result representing the response stream. | ||
* yields a stream of ExecutionResults representing the response stream. | ||
* | ||
* Each result may be an ExecutionResult with no `hasNext` (if executing the | ||
* event did not use `@defer` or `@stream`), or an | ||
* `InitialIncrementalExecutionResult` or `SubsequentIncrementalExecutionResult` | ||
* (if executing the event used `@defer` or `@stream`). In the case of | ||
* incremental execution results, each event produces a single | ||
* `InitialIncrementalExecutionResult` followed by one or more | ||
* `SubsequentIncrementalExecutionResult`s; all but the last have `hasNext: true`, | ||
* and the last has `hasNext: false`. There is no interleaving between results | ||
* generated from the same original event. | ||
* | ||
* Accepts an object with named arguments. | ||
* Accepts either an object with named arguments, or individual arguments. | ||
*/ | ||
@@ -768,11 +667,2 @@ function subscribe(args) { | ||
exports.subscribe = subscribe; | ||
async function* ensureAsyncIterable(someExecutionResult) { | ||
if ('initialResult' in someExecutionResult) { | ||
yield someExecutionResult.initialResult; | ||
yield* someExecutionResult.subsequentResults; | ||
} | ||
else { | ||
yield someExecutionResult; | ||
} | ||
} | ||
function mapSourceToResponse(exeContext, resultOrStream) { | ||
@@ -788,3 +678,3 @@ if (!(0, utils_1.isAsyncIterable)(resultOrStream)) { | ||
// "ExecuteQuery" algorithm, for which `execute` is also used. | ||
return (0, flattenAsyncIterable_js_1.flattenAsyncIterable)((0, utils_1.mapAsyncIterator)(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload))))); | ||
return (0, utils_1.mapAsyncIterator)(resultOrStream[Symbol.asyncIterator](), (payload) => executeImpl(buildPerEventExecutionContext(exeContext, payload))); | ||
} | ||
@@ -849,3 +739,3 @@ /** | ||
} | ||
const { fields: rootFields } = (0, utils_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const rootFields = (0, utils_1.collectFields)(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const [responseName, fieldNodes] = [...rootFields.entries()][0]; | ||
@@ -894,335 +784,2 @@ const fieldName = fieldNodes[0].name.value; | ||
} | ||
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext) { | ||
const asyncPayloadRecord = new DeferredFragmentRecord({ | ||
label, | ||
path, | ||
parentContext, | ||
exeContext, | ||
}); | ||
let promiseOrData; | ||
try { | ||
promiseOrData = executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord); | ||
if ((0, utils_1.isPromise)(promiseOrData)) { | ||
promiseOrData = promiseOrData.then(null, e => { | ||
asyncPayloadRecord.errors.push(e); | ||
return null; | ||
}); | ||
} | ||
} | ||
catch (e) { | ||
asyncPayloadRecord.errors.push(e); | ||
promiseOrData = null; | ||
} | ||
asyncPayloadRecord.addData(promiseOrData); | ||
} | ||
function executeStreamField(path, itemPath, item, exeContext, fieldNodes, info, itemType, label, parentContext) { | ||
const asyncPayloadRecord = new StreamRecord({ | ||
label, | ||
path: itemPath, | ||
parentContext, | ||
exeContext, | ||
}); | ||
let completedItem; | ||
try { | ||
try { | ||
if ((0, utils_1.isPromise)(item)) { | ||
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord)); | ||
} | ||
else { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord); | ||
} | ||
if ((0, utils_1.isPromise)(completedItem)) { | ||
// Note: we don't rely on a `catch` method, but we do expect "thenable" | ||
// to take a second callback for the error case. | ||
completedItem = completedItem.then(undefined, rawError => { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return handledError; | ||
}); | ||
} | ||
} | ||
catch (rawError) { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
completedItem = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
} | ||
} | ||
catch (error) { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
asyncPayloadRecord.addItems(null); | ||
return asyncPayloadRecord; | ||
} | ||
let completedItems; | ||
if ((0, utils_1.isPromise)(completedItem)) { | ||
completedItems = completedItem.then(value => [value], error => { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return null; | ||
}); | ||
} | ||
else { | ||
completedItems = [completedItem]; | ||
} | ||
asyncPayloadRecord.addItems(completedItems); | ||
return asyncPayloadRecord; | ||
} | ||
async function executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath) { | ||
let item; | ||
try { | ||
const { value, done } = await iterator.next(); | ||
if (done) { | ||
asyncPayloadRecord.setIsCompletedIterator(); | ||
return { done, value: undefined }; | ||
} | ||
item = value; | ||
} | ||
catch (rawError) { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
// don't continue if iterator throws | ||
return { done: true, value }; | ||
} | ||
let completedItem; | ||
try { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord); | ||
if ((0, utils_1.isPromise)(completedItem)) { | ||
completedItem = completedItem.then(undefined, rawError => { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return handledError; | ||
}); | ||
} | ||
return { done: false, value: completedItem }; | ||
} | ||
catch (rawError) { | ||
const error = (0, graphql_1.locatedError)(rawError, fieldNodes, (0, utils_1.pathToArray)(itemPath)); | ||
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return { done: false, value }; | ||
} | ||
} | ||
async function executeStreamIterator(initialIndex, iterator, exeContext, fieldNodes, info, itemType, path, label, parentContext) { | ||
let index = initialIndex; | ||
let previousAsyncPayloadRecord = parentContext !== null && parentContext !== void 0 ? parentContext : undefined; | ||
while (true) { | ||
const itemPath = (0, utils_1.addPath)(path, index, undefined); | ||
const asyncPayloadRecord = new StreamRecord({ | ||
label, | ||
path: itemPath, | ||
parentContext: previousAsyncPayloadRecord, | ||
iterator, | ||
exeContext, | ||
}); | ||
let iteration; | ||
try { | ||
iteration = await executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath); | ||
} | ||
catch (error) { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
asyncPayloadRecord.addItems(null); | ||
// entire stream has errored and bubbled upwards | ||
if (iterator === null || iterator === void 0 ? void 0 : iterator.return) { | ||
iterator.return().catch(() => { | ||
// ignore errors | ||
}); | ||
} | ||
return; | ||
} | ||
const { done, value: completedItem } = iteration; | ||
let completedItems; | ||
if ((0, utils_1.isPromise)(completedItem)) { | ||
completedItems = completedItem.then(value => [value], error => { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return null; | ||
}); | ||
} | ||
else { | ||
completedItems = [completedItem]; | ||
} | ||
asyncPayloadRecord.addItems(completedItems); | ||
if (done) { | ||
break; | ||
} | ||
previousAsyncPayloadRecord = asyncPayloadRecord; | ||
index++; | ||
} | ||
} | ||
function filterSubsequentPayloads(exeContext, nullPath, currentAsyncRecord) { | ||
const nullPathArray = (0, utils_1.pathToArray)(nullPath); | ||
exeContext.subsequentPayloads.forEach(asyncRecord => { | ||
var _a; | ||
if (asyncRecord === currentAsyncRecord) { | ||
// don't remove payload from where error originates | ||
return; | ||
} | ||
for (let i = 0; i < nullPathArray.length; i++) { | ||
if (asyncRecord.path[i] !== nullPathArray[i]) { | ||
// asyncRecord points to a path unaffected by this payload | ||
return; | ||
} | ||
} | ||
// asyncRecord path points to nulled error field | ||
if (isStreamPayload(asyncRecord) && ((_a = asyncRecord.iterator) === null || _a === void 0 ? void 0 : _a.return)) { | ||
asyncRecord.iterator.return().catch(() => { | ||
// ignore error | ||
}); | ||
} | ||
exeContext.subsequentPayloads.delete(asyncRecord); | ||
}); | ||
} | ||
function getCompletedIncrementalResults(exeContext) { | ||
const incrementalResults = []; | ||
for (const asyncPayloadRecord of exeContext.subsequentPayloads) { | ||
const incrementalResult = {}; | ||
if (!asyncPayloadRecord.isCompleted) { | ||
continue; | ||
} | ||
exeContext.subsequentPayloads.delete(asyncPayloadRecord); | ||
if (isStreamPayload(asyncPayloadRecord)) { | ||
const items = asyncPayloadRecord.items; | ||
if (asyncPayloadRecord.isCompletedIterator) { | ||
// async iterable resolver just finished but there may be pending payloads | ||
continue; | ||
} | ||
incrementalResult.items = items; | ||
} | ||
else { | ||
const data = asyncPayloadRecord.data; | ||
incrementalResult.data = data !== null && data !== void 0 ? data : null; | ||
} | ||
incrementalResult.path = asyncPayloadRecord.path; | ||
if (asyncPayloadRecord.label) { | ||
incrementalResult.label = asyncPayloadRecord.label; | ||
} | ||
if (asyncPayloadRecord.errors.length > 0) { | ||
incrementalResult.errors = asyncPayloadRecord.errors; | ||
} | ||
incrementalResults.push(incrementalResult); | ||
} | ||
return incrementalResults; | ||
} | ||
function yieldSubsequentPayloads(exeContext) { | ||
let isDone = false; | ||
async function next() { | ||
if (isDone) { | ||
return { value: undefined, done: true }; | ||
} | ||
await Promise.race(Array.from(exeContext.subsequentPayloads).map(p => p.promise)); | ||
if (isDone) { | ||
// a different call to next has exhausted all payloads | ||
return { value: undefined, done: true }; | ||
} | ||
const incremental = getCompletedIncrementalResults(exeContext); | ||
const hasNext = exeContext.subsequentPayloads.size > 0; | ||
if (!incremental.length && hasNext) { | ||
return next(); | ||
} | ||
if (!hasNext) { | ||
isDone = true; | ||
} | ||
return { | ||
value: incremental.length ? { incremental, hasNext } : { hasNext }, | ||
done: false, | ||
}; | ||
} | ||
function returnStreamIterators() { | ||
const promises = []; | ||
exeContext.subsequentPayloads.forEach(asyncPayloadRecord => { | ||
var _a; | ||
if (isStreamPayload(asyncPayloadRecord) && ((_a = asyncPayloadRecord.iterator) === null || _a === void 0 ? void 0 : _a.return)) { | ||
promises.push(asyncPayloadRecord.iterator.return()); | ||
} | ||
}); | ||
return Promise.all(promises); | ||
} | ||
return { | ||
[Symbol.asyncIterator]() { | ||
return this; | ||
}, | ||
next, | ||
async return() { | ||
await returnStreamIterators(); | ||
isDone = true; | ||
return { value: undefined, done: true }; | ||
}, | ||
async throw(error) { | ||
await returnStreamIterators(); | ||
isDone = true; | ||
return Promise.reject(error); | ||
}, | ||
}; | ||
} | ||
class DeferredFragmentRecord { | ||
constructor(opts) { | ||
this.type = 'defer'; | ||
this.label = opts.label; | ||
this.path = (0, utils_1.pathToArray)(opts.path); | ||
this.parentContext = opts.parentContext; | ||
this.errors = []; | ||
this._exeContext = opts.exeContext; | ||
this._exeContext.subsequentPayloads.add(this); | ||
this.isCompleted = false; | ||
this.data = null; | ||
this.promise = new Promise(resolve => { | ||
this._resolve = MaybePromise => { | ||
resolve(MaybePromise); | ||
}; | ||
}).then(data => { | ||
this.data = data; | ||
this.isCompleted = true; | ||
}); | ||
} | ||
addData(data) { | ||
var _a, _b, _c; | ||
const parentData = (_a = this.parentContext) === null || _a === void 0 ? void 0 : _a.promise; | ||
if (parentData) { | ||
(_b = this._resolve) === null || _b === void 0 ? void 0 : _b.call(this, parentData.then(() => data)); | ||
return; | ||
} | ||
(_c = this._resolve) === null || _c === void 0 ? void 0 : _c.call(this, data); | ||
} | ||
} | ||
class StreamRecord { | ||
constructor(opts) { | ||
this.type = 'stream'; | ||
this.items = null; | ||
this.label = opts.label; | ||
this.path = (0, utils_1.pathToArray)(opts.path); | ||
this.parentContext = opts.parentContext; | ||
this.iterator = opts.iterator; | ||
this.errors = []; | ||
this._exeContext = opts.exeContext; | ||
this._exeContext.subsequentPayloads.add(this); | ||
this.isCompleted = false; | ||
this.items = null; | ||
this.promise = new Promise(resolve => { | ||
this._resolve = MaybePromise => { | ||
resolve(MaybePromise); | ||
}; | ||
}).then(items => { | ||
this.items = items; | ||
this.isCompleted = true; | ||
}); | ||
} | ||
addItems(items) { | ||
var _a, _b, _c; | ||
const parentData = (_a = this.parentContext) === null || _a === void 0 ? void 0 : _a.promise; | ||
if (parentData) { | ||
(_b = this._resolve) === null || _b === void 0 ? void 0 : _b.call(this, parentData.then(() => items)); | ||
return; | ||
} | ||
(_c = this._resolve) === null || _c === void 0 ? void 0 : _c.call(this, items); | ||
} | ||
setIsCompletedIterator() { | ||
this.isCompletedIterator = true; | ||
} | ||
} | ||
function isStreamPayload(asyncPayload) { | ||
return asyncPayload.type === 'stream'; | ||
} | ||
/** | ||
@@ -1253,5 +810,1 @@ * This method looks up the field on the given type definition. | ||
exports.getFieldDef = getFieldDef; | ||
function isIncrementalResult(result) { | ||
return 'incremental' in result; | ||
} | ||
exports.isIncrementalResult = isIncrementalResult; |
@@ -6,2 +6,1 @@ "use strict"; | ||
tslib_1.__exportStar(require("./values.js"), exports); | ||
tslib_1.__exportStar(require("./normalizedExecutor.js"), exports); |
@@ -1,22 +0,10 @@ | ||
import { locatedError, Kind, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, assertValidSchema, getDirectiveValues, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, } from 'graphql'; | ||
import { createGraphQLError, inspect, isAsyncIterable, isIterableObject, isObjectLike, isPromise, pathToArray, addPath, getArgumentValues, promiseReduce, memoize3, getDefinedRootType, mapAsyncIterator, GraphQLStreamDirective, collectFields, collectSubFields as _collectSubfields, } from '@graphql-tools/utils'; | ||
import { locatedError, Kind, isAbstractType, isLeafType, isListType, isNonNullType, isObjectType, assertValidSchema, SchemaMetaFieldDef, TypeMetaFieldDef, TypeNameMetaFieldDef, } from 'graphql'; | ||
import { collectFields, collectSubFields, createGraphQLError, inspect, isAsyncIterable, isIterableObject, isObjectLike, isPromise, mapAsyncIterator, pathToArray, addPath, getArgumentValues, promiseReduce, getDefinedRootType, } from '@graphql-tools/utils'; | ||
import { getVariableValues } from './values.js'; | ||
import { promiseForObject } from './promiseForObject.js'; | ||
import { flattenAsyncIterable } from './flattenAsyncIterable.js'; | ||
import { invariant } from './invariant.js'; | ||
import { ValueOrPromise } from 'value-or-promise'; | ||
/** | ||
* A memoized collection of relevant subfields with regard to the return | ||
* type. Memoizing ensures the subfields are not repeatedly calculated, which | ||
* saves overhead when resolving lists of values. | ||
*/ | ||
const collectSubfields = memoize3((exeContext, returnType, fieldNodes) => _collectSubfields(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes)); | ||
/** | ||
* Implements the "Executing requests" section of the GraphQL specification, | ||
* including `@defer` and `@stream` as proposed in | ||
* https://github.com/graphql/graphql-spec/pull/742 | ||
* Implements the "Executing requests" section of the GraphQL specification. | ||
* | ||
* This function returns a Promise of an IncrementalExecutionResults | ||
* object. This object either consists of a single ExecutionResult, or an | ||
* object containing an `initialResult` and a stream of `subsequentResults`. | ||
* Returns either a synchronous ExecutionResult (if all encountered resolvers | ||
* are synchronous), or a Promise of an ExecutionResult that will eventually be | ||
* resolved and never rejected. | ||
* | ||
@@ -48,20 +36,16 @@ * If the arguments to this function do not result in a legal execution context, | ||
// in this case is the entire response. | ||
return new ValueOrPromise(() => executeOperation(exeContext)) | ||
.then(data => { | ||
const initialResult = buildResponse(data, exeContext.errors); | ||
if (exeContext.subsequentPayloads.size > 0) { | ||
return { | ||
initialResult: { | ||
...initialResult, | ||
hasNext: true, | ||
}, | ||
subsequentResults: yieldSubsequentPayloads(exeContext), | ||
}; | ||
try { | ||
const result = executeOperation(exeContext); | ||
if (isPromise(result)) { | ||
return result.then(data => buildResponse(data, exeContext.errors), error => { | ||
exeContext.errors.push(error); | ||
return buildResponse(null, exeContext.errors); | ||
}); | ||
} | ||
return initialResult; | ||
}, (error) => { | ||
return buildResponse(result, exeContext.errors); | ||
} | ||
catch (error) { | ||
exeContext.errors.push(error); | ||
return buildResponse(null, exeContext.errors); | ||
}) | ||
.resolve(); | ||
} | ||
} | ||
@@ -76,3 +60,3 @@ /** | ||
// Assert that the execution was synchronous. | ||
if (isPromise(result) || 'initialResult' in result) { | ||
if (isPromise(result)) { | ||
throw new Error('GraphQL execution failed to complete synchronously.'); | ||
@@ -163,3 +147,2 @@ } | ||
subscribeFieldResolver: subscribeFieldResolver !== null && subscribeFieldResolver !== void 0 ? subscribeFieldResolver : defaultFieldResolver, | ||
subsequentPayloads: new Set(), | ||
errors: [], | ||
@@ -172,3 +155,2 @@ }; | ||
rootValue: payload, | ||
subsequentPayloads: new Set(), | ||
errors: [], | ||
@@ -183,21 +165,15 @@ }; | ||
const rootType = getDefinedRootType(schema, operation.operation, [operation]); | ||
if (rootType == null) { | ||
createGraphQLError(`Schema is not configured to execute ${operation.operation} operation.`, { | ||
nodes: operation, | ||
}); | ||
} | ||
const { fields: rootFields, patches } = collectFields(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const rootFields = collectFields(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const path = undefined; | ||
let result; | ||
if (operation.operation === 'mutation') { | ||
result = executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields); | ||
switch (operation.operation) { | ||
case 'query': | ||
return executeFields(exeContext, rootType, rootValue, path, rootFields); | ||
case 'mutation': | ||
return executeFieldsSerially(exeContext, rootType, rootValue, path, rootFields); | ||
case 'subscription': | ||
// TODO: deprecate `subscribe` and move all logic here | ||
// Temporary solution until we finish merging execute and subscribe together | ||
return executeFields(exeContext, rootType, rootValue, path, rootFields); | ||
} | ||
else { | ||
result = executeFields(exeContext, rootType, rootValue, path, rootFields); | ||
} | ||
for (const patch of patches) { | ||
const { label, fields: patchFields } = patch; | ||
executeDeferredFragment(exeContext, rootType, rootValue, patchFields, label, path); | ||
} | ||
return result; | ||
throw new Error(`Can only execute queries, mutations and subscriptions, got "${operation.operation}".`); | ||
} | ||
@@ -209,13 +185,16 @@ /** | ||
function executeFieldsSerially(exeContext, parentType, sourceValue, path, fields) { | ||
return promiseReduce(fields, (results, [responseName, fieldNodes]) => { | ||
return promiseReduce(fields.entries(), (results, [responseName, fieldNodes]) => { | ||
const fieldPath = addPath(path, responseName, parentType.name); | ||
return new ValueOrPromise(() => executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath)) | ||
.then(result => { | ||
if (result === undefined) { | ||
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath); | ||
if (result === undefined) { | ||
return results; | ||
} | ||
if (isPromise(result)) { | ||
return result.then(resolvedResult => { | ||
results[responseName] = resolvedResult; | ||
return results; | ||
} | ||
results[responseName] = result; | ||
return results; | ||
}) | ||
.resolve(); | ||
}); | ||
} | ||
results[responseName] = result; | ||
return results; | ||
}, Object.create(null)); | ||
@@ -227,26 +206,15 @@ } | ||
*/ | ||
function executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord) { | ||
function executeFields(exeContext, parentType, sourceValue, path, fields) { | ||
const results = Object.create(null); | ||
let containsPromise = false; | ||
try { | ||
for (const [responseName, fieldNodes] of fields) { | ||
const fieldPath = addPath(path, responseName, parentType.name); | ||
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath, asyncPayloadRecord); | ||
if (result !== undefined) { | ||
results[responseName] = result; | ||
if (isPromise(result)) { | ||
containsPromise = true; | ||
} | ||
for (const [responseName, fieldNodes] of fields.entries()) { | ||
const fieldPath = addPath(path, responseName, parentType.name); | ||
const result = executeField(exeContext, parentType, sourceValue, fieldNodes, fieldPath); | ||
if (result !== undefined) { | ||
results[responseName] = result; | ||
if (isPromise(result)) { | ||
containsPromise = true; | ||
} | ||
} | ||
} | ||
catch (error) { | ||
if (containsPromise) { | ||
// Ensure that any promises returned by other fields are handled, as they may also reject. | ||
return promiseForObject(results).finally(() => { | ||
throw error; | ||
}); | ||
} | ||
throw error; | ||
} | ||
// If there are no promises, we can just return the object | ||
@@ -259,3 +227,9 @@ if (!containsPromise) { | ||
// same map, but with any promises replaced with the values they resolved to. | ||
return promiseForObject(results); | ||
return Promise.all(Object.values(results)).then(resolvedValues => { | ||
const resolvedObject = Object.create(null); | ||
for (const [i, key] of Object.keys(results).entries()) { | ||
resolvedObject[key] = resolvedValues[i]; | ||
} | ||
return resolvedObject; | ||
}); | ||
} | ||
@@ -268,5 +242,4 @@ /** | ||
*/ | ||
function executeField(exeContext, parentType, source, fieldNodes, path, asyncPayloadRecord) { | ||
var _a, _b; | ||
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors; | ||
function executeField(exeContext, parentType, source, fieldNodes, path) { | ||
var _a; | ||
const fieldDef = getFieldDef(exeContext.schema, parentType, fieldNodes[0]); | ||
@@ -277,3 +250,3 @@ if (!fieldDef) { | ||
const returnType = fieldDef.type; | ||
const resolveFn = (_b = fieldDef.resolve) !== null && _b !== void 0 ? _b : exeContext.fieldResolver; | ||
const resolveFn = (_a = fieldDef.resolve) !== null && _a !== void 0 ? _a : exeContext.fieldResolver; | ||
const info = buildResolveInfo(exeContext, fieldDef, fieldNodes, parentType, path); | ||
@@ -293,6 +266,6 @@ // Get the resolve function, regardless of if its result is normal or abrupt (error). | ||
if (isPromise(result)) { | ||
completed = result.then(resolved => completeValue(exeContext, returnType, fieldNodes, info, path, resolved, asyncPayloadRecord)); | ||
completed = result.then(resolved => completeValue(exeContext, returnType, fieldNodes, info, path, resolved)); | ||
} | ||
else { | ||
completed = completeValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
completed = completeValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
@@ -304,5 +277,3 @@ if (isPromise(completed)) { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(path)); | ||
const handledError = handleFieldError(error, returnType, errors); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return handledError; | ||
return handleFieldError(error, returnType, exeContext); | ||
}); | ||
@@ -314,5 +285,3 @@ } | ||
const error = locatedError(rawError, fieldNodes, pathToArray(path)); | ||
const handledError = handleFieldError(error, returnType, errors); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return handledError; | ||
return handleFieldError(error, returnType, exeContext); | ||
} | ||
@@ -340,3 +309,3 @@ } | ||
} | ||
function handleFieldError(error, returnType, errors) { | ||
function handleFieldError(error, returnType, exeContext) { | ||
// If the field type is non-nullable, then it is resolved without any | ||
@@ -349,3 +318,3 @@ // protection from errors, however it still properly locates the error. | ||
// a null value for this field if one is encountered. | ||
errors.push(error); | ||
exeContext.errors.push(error); | ||
return null; | ||
@@ -374,3 +343,3 @@ } | ||
*/ | ||
function completeValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
function completeValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
// If result is an Error, throw a located error. | ||
@@ -383,3 +352,3 @@ if (result instanceof Error) { | ||
if (isNonNullType(returnType)) { | ||
const completed = completeValue(exeContext, returnType.ofType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
const completed = completeValue(exeContext, returnType.ofType, fieldNodes, info, path, result); | ||
if (completed === null) { | ||
@@ -396,3 +365,3 @@ throw new Error(`Cannot return null for non-nullable field ${info.parentType.name}.${info.fieldName}.`); | ||
if (isListType(returnType)) { | ||
return completeListValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeListValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
@@ -407,7 +376,7 @@ // If field type is a leaf type, Scalar or Enum, serialize to a valid value, | ||
if (isAbstractType(returnType)) { | ||
return completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
// If field type is Object, execute and complete all sub-selections. | ||
if (isObjectType(returnType)) { | ||
return completeObjectValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeObjectValue(exeContext, returnType, fieldNodes, info, path, result); | ||
} | ||
@@ -419,35 +388,6 @@ /* c8 ignore next 6 */ | ||
/** | ||
* Returns an object containing the `@stream` arguments if a field should be | ||
* streamed based on the experimental flag, stream directive present and | ||
* not disabled by the "if" argument. | ||
*/ | ||
function getStreamValues(exeContext, fieldNodes, path) { | ||
// do not stream inner lists of multi-dimensional lists | ||
if (typeof path.key === 'number') { | ||
return; | ||
} | ||
// validation only allows equivalent streams on multiple fields, so it is | ||
// safe to only check the first fieldNode for the stream directive | ||
const stream = getDirectiveValues(GraphQLStreamDirective, fieldNodes[0], exeContext.variableValues); | ||
if (!stream) { | ||
return; | ||
} | ||
if (stream['if'] === false) { | ||
return; | ||
} | ||
invariant(typeof stream['initialCount'] === 'number', 'initialCount must be a number'); | ||
invariant(stream['initialCount'] >= 0, 'initialCount must be a positive integer'); | ||
return { | ||
initialCount: stream['initialCount'], | ||
label: typeof stream['label'] === 'string' ? stream['label'] : undefined, | ||
}; | ||
} | ||
/** | ||
* Complete a async iterator value by completing the result and calling | ||
* recursively until all the results are completed. | ||
*/ | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord) { | ||
var _a; | ||
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors; | ||
const stream = getStreamValues(exeContext, fieldNodes, path); | ||
async function completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator) { | ||
let containsPromise = false; | ||
@@ -457,22 +397,28 @@ const completedResults = []; | ||
while (true) { | ||
if (stream && typeof stream.initialCount === 'number' && index >= stream.initialCount) { | ||
executeStreamIterator(index, iterator, exeContext, fieldNodes, info, itemType, path, stream.label, asyncPayloadRecord); | ||
break; | ||
} | ||
const itemPath = addPath(path, index, undefined); | ||
let iteration; | ||
const fieldPath = addPath(path, index, undefined); | ||
try { | ||
iteration = await iterator.next(); | ||
if (iteration.done) { | ||
const { value, done } = await iterator.next(); | ||
if (done) { | ||
break; | ||
} | ||
try { | ||
// TODO can the error checking logic be consolidated with completeListValue? | ||
const completedItem = completeValue(exeContext, itemType, fieldNodes, info, fieldPath, value); | ||
if (isPromise(completedItem)) { | ||
containsPromise = true; | ||
} | ||
completedResults.push(completedItem); | ||
} | ||
catch (rawError) { | ||
completedResults.push(null); | ||
const error = locatedError(rawError, fieldNodes, pathToArray(fieldPath)); | ||
handleFieldError(error, itemType, exeContext); | ||
} | ||
} | ||
catch (rawError) { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
completedResults.push(handleFieldError(error, itemType, errors)); | ||
completedResults.push(null); | ||
const error = locatedError(rawError, fieldNodes, pathToArray(fieldPath)); | ||
handleFieldError(error, itemType, exeContext); | ||
break; | ||
} | ||
if (completeListItemValue(iteration.value, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord)) { | ||
containsPromise = true; | ||
} | ||
index += 1; | ||
@@ -486,9 +432,7 @@ } | ||
*/ | ||
function completeListValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
var _a; | ||
function completeListValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
const itemType = returnType.ofType; | ||
const errors = (_a = asyncPayloadRecord === null || asyncPayloadRecord === void 0 ? void 0 : asyncPayloadRecord.errors) !== null && _a !== void 0 ? _a : exeContext.errors; | ||
if (isAsyncIterable(result)) { | ||
const iterator = result[Symbol.asyncIterator](); | ||
return completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator, asyncPayloadRecord); | ||
return completeAsyncIteratorValue(exeContext, itemType, fieldNodes, info, path, iterator); | ||
} | ||
@@ -498,61 +442,36 @@ if (!isIterableObject(result)) { | ||
} | ||
const stream = getStreamValues(exeContext, fieldNodes, path); | ||
// This is specified as a simple map, however we're optimizing the path | ||
// where the list contains no Promises by avoiding creating another Promise. | ||
let containsPromise = false; | ||
let previousAsyncPayloadRecord = asyncPayloadRecord; | ||
const completedResults = []; | ||
let index = 0; | ||
for (const item of result) { | ||
const completedResults = Array.from(result, (item, index) => { | ||
// No need to modify the info object containing the path, | ||
// since from here on it is not ever accessed by resolver functions. | ||
const itemPath = addPath(path, index, undefined); | ||
if (stream && typeof stream.initialCount === 'number' && index >= stream.initialCount) { | ||
previousAsyncPayloadRecord = executeStreamField(path, itemPath, item, exeContext, fieldNodes, info, itemType, stream.label, previousAsyncPayloadRecord); | ||
index++; | ||
continue; | ||
try { | ||
let completedItem; | ||
if (isPromise(item)) { | ||
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved)); | ||
} | ||
else { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item); | ||
} | ||
if (isPromise(completedItem)) { | ||
containsPromise = true; | ||
// Note: we don't rely on a `catch` method, but we do expect "thenable" | ||
// to take a second callback for the error case. | ||
return completedItem.then(undefined, rawError => { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
return handleFieldError(error, itemType, exeContext); | ||
}); | ||
} | ||
return completedItem; | ||
} | ||
if (completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord)) { | ||
containsPromise = true; | ||
catch (rawError) { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
return handleFieldError(error, itemType, exeContext); | ||
} | ||
index++; | ||
} | ||
}); | ||
return containsPromise ? Promise.all(completedResults) : completedResults; | ||
} | ||
/** | ||
* Complete a list item value by adding it to the completed results. | ||
* | ||
* Returns true if the value is a Promise. | ||
*/ | ||
function completeListItemValue(item, completedResults, errors, exeContext, itemType, fieldNodes, info, itemPath, asyncPayloadRecord) { | ||
try { | ||
let completedItem; | ||
if (isPromise(item)) { | ||
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord)); | ||
} | ||
else { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord); | ||
} | ||
if (isPromise(completedItem)) { | ||
// Note: we don't rely on a `catch` method, but we do expect "thenable" | ||
// to take a second callback for the error case. | ||
completedResults.push(completedItem.then(undefined, rawError => { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
const handledError = handleFieldError(error, itemType, errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return handledError; | ||
})); | ||
return true; | ||
} | ||
completedResults.push(completedItem); | ||
} | ||
catch (rawError) { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
const handledError = handleFieldError(error, itemType, errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
completedResults.push(handledError); | ||
} | ||
return false; | ||
} | ||
/** | ||
* Complete a Scalar or Enum by serializing to a valid value, returning | ||
@@ -573,3 +492,3 @@ * null if serialization is not possible. | ||
*/ | ||
function completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
function completeAbstractValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
var _a; | ||
@@ -580,5 +499,5 @@ const resolveTypeFn = (_a = returnType.resolveType) !== null && _a !== void 0 ? _a : exeContext.typeResolver; | ||
if (isPromise(runtimeType)) { | ||
return runtimeType.then(resolvedRuntimeType => completeObjectValue(exeContext, ensureValidRuntimeType(resolvedRuntimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result, asyncPayloadRecord)); | ||
return runtimeType.then(resolvedRuntimeType => completeObjectValue(exeContext, ensureValidRuntimeType(resolvedRuntimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result)); | ||
} | ||
return completeObjectValue(exeContext, ensureValidRuntimeType(runtimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result, asyncPayloadRecord); | ||
return completeObjectValue(exeContext, ensureValidRuntimeType(runtimeType, exeContext, returnType, fieldNodes, info, result), fieldNodes, info, path, result); | ||
} | ||
@@ -613,3 +532,5 @@ function ensureValidRuntimeType(runtimeTypeName, exeContext, returnType, fieldNodes, info, result) { | ||
*/ | ||
function completeObjectValue(exeContext, returnType, fieldNodes, info, path, result, asyncPayloadRecord) { | ||
function completeObjectValue(exeContext, returnType, fieldNodes, info, path, result) { | ||
// Collect sub-fields to execute to complete this value. | ||
const subFieldNodes = collectSubFields(exeContext.schema, exeContext.fragments, exeContext.variableValues, returnType, fieldNodes); | ||
// If there is an isTypeOf predicate function, call it with the | ||
@@ -625,3 +546,3 @@ // current result. If isTypeOf returns false, then raise an error rather | ||
} | ||
return collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord); | ||
return executeFields(exeContext, returnType, result, path, subFieldNodes); | ||
}); | ||
@@ -633,3 +554,3 @@ } | ||
} | ||
return collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord); | ||
return executeFields(exeContext, returnType, result, path, subFieldNodes); | ||
} | ||
@@ -641,12 +562,2 @@ function invalidReturnTypeError(returnType, result, fieldNodes) { | ||
} | ||
function collectAndExecuteSubfields(exeContext, returnType, fieldNodes, path, result, asyncPayloadRecord) { | ||
// Collect sub-fields to execute to complete this value. | ||
const { fields: subFieldNodes, patches: subPatches } = collectSubfields(exeContext, returnType, fieldNodes); | ||
const subFields = executeFields(exeContext, returnType, result, path, subFieldNodes, asyncPayloadRecord); | ||
for (const subPatch of subPatches) { | ||
const { label, fields: subPatchFieldNodes } = subPatch; | ||
executeDeferredFragment(exeContext, returnType, result, subPatchFieldNodes, label, path, asyncPayloadRecord); | ||
} | ||
return subFields; | ||
} | ||
/** | ||
@@ -709,5 +620,3 @@ * If a resolveType function is not given, then a default resolve behavior is | ||
/** | ||
* Implements the "Subscribe" algorithm described in the GraphQL specification, | ||
* including `@defer` and `@stream` as proposed in | ||
* https://github.com/graphql/graphql-spec/pull/742 | ||
* Implements the "Subscribe" algorithm described in the GraphQL specification. | ||
* | ||
@@ -720,23 +629,13 @@ * Returns a Promise which resolves to either an AsyncIterator (if successful) | ||
* If the client-provided arguments to this function do not result in a | ||
* compliant subscription, a GraphQL Response (ExecutionResult) with descriptive | ||
* errors and no data will be returned. | ||
* compliant subscription, a GraphQL Response (ExecutionResult) with | ||
* descriptive errors and no data will be returned. | ||
* | ||
* If the source stream could not be created due to faulty subscription resolver | ||
* logic or underlying systems, the promise will resolve to a single | ||
* If the source stream could not be created due to faulty subscription | ||
* resolver logic or underlying systems, the promise will resolve to a single | ||
* ExecutionResult containing `errors` and no `data`. | ||
* | ||
* If the operation succeeded, the promise resolves to an AsyncIterator, which | ||
* yields a stream of result representing the response stream. | ||
* yields a stream of ExecutionResults representing the response stream. | ||
* | ||
* Each result may be an ExecutionResult with no `hasNext` (if executing the | ||
* event did not use `@defer` or `@stream`), or an | ||
* `InitialIncrementalExecutionResult` or `SubsequentIncrementalExecutionResult` | ||
* (if executing the event used `@defer` or `@stream`). In the case of | ||
* incremental execution results, each event produces a single | ||
* `InitialIncrementalExecutionResult` followed by one or more | ||
* `SubsequentIncrementalExecutionResult`s; all but the last have `hasNext: true`, | ||
* and the last has `hasNext: false`. There is no interleaving between results | ||
* generated from the same original event. | ||
* | ||
* Accepts an object with named arguments. | ||
* Accepts either an object with named arguments, or individual arguments. | ||
*/ | ||
@@ -757,11 +656,2 @@ export function subscribe(args) { | ||
} | ||
async function* ensureAsyncIterable(someExecutionResult) { | ||
if ('initialResult' in someExecutionResult) { | ||
yield someExecutionResult.initialResult; | ||
yield* someExecutionResult.subsequentResults; | ||
} | ||
else { | ||
yield someExecutionResult; | ||
} | ||
} | ||
function mapSourceToResponse(exeContext, resultOrStream) { | ||
@@ -777,3 +667,3 @@ if (!isAsyncIterable(resultOrStream)) { | ||
// "ExecuteQuery" algorithm, for which `execute` is also used. | ||
return flattenAsyncIterable(mapAsyncIterator(resultOrStream[Symbol.asyncIterator](), async (payload) => ensureAsyncIterable(await executeImpl(buildPerEventExecutionContext(exeContext, payload))))); | ||
return mapAsyncIterator(resultOrStream[Symbol.asyncIterator](), (payload) => executeImpl(buildPerEventExecutionContext(exeContext, payload))); | ||
} | ||
@@ -837,3 +727,3 @@ /** | ||
} | ||
const { fields: rootFields } = collectFields(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const rootFields = collectFields(schema, fragments, variableValues, rootType, operation.selectionSet); | ||
const [responseName, fieldNodes] = [...rootFields.entries()][0]; | ||
@@ -882,335 +772,2 @@ const fieldName = fieldNodes[0].name.value; | ||
} | ||
function executeDeferredFragment(exeContext, parentType, sourceValue, fields, label, path, parentContext) { | ||
const asyncPayloadRecord = new DeferredFragmentRecord({ | ||
label, | ||
path, | ||
parentContext, | ||
exeContext, | ||
}); | ||
let promiseOrData; | ||
try { | ||
promiseOrData = executeFields(exeContext, parentType, sourceValue, path, fields, asyncPayloadRecord); | ||
if (isPromise(promiseOrData)) { | ||
promiseOrData = promiseOrData.then(null, e => { | ||
asyncPayloadRecord.errors.push(e); | ||
return null; | ||
}); | ||
} | ||
} | ||
catch (e) { | ||
asyncPayloadRecord.errors.push(e); | ||
promiseOrData = null; | ||
} | ||
asyncPayloadRecord.addData(promiseOrData); | ||
} | ||
function executeStreamField(path, itemPath, item, exeContext, fieldNodes, info, itemType, label, parentContext) { | ||
const asyncPayloadRecord = new StreamRecord({ | ||
label, | ||
path: itemPath, | ||
parentContext, | ||
exeContext, | ||
}); | ||
let completedItem; | ||
try { | ||
try { | ||
if (isPromise(item)) { | ||
completedItem = item.then(resolved => completeValue(exeContext, itemType, fieldNodes, info, itemPath, resolved, asyncPayloadRecord)); | ||
} | ||
else { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord); | ||
} | ||
if (isPromise(completedItem)) { | ||
// Note: we don't rely on a `catch` method, but we do expect "thenable" | ||
// to take a second callback for the error case. | ||
completedItem = completedItem.then(undefined, rawError => { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return handledError; | ||
}); | ||
} | ||
} | ||
catch (rawError) { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
completedItem = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
} | ||
} | ||
catch (error) { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
asyncPayloadRecord.addItems(null); | ||
return asyncPayloadRecord; | ||
} | ||
let completedItems; | ||
if (isPromise(completedItem)) { | ||
completedItems = completedItem.then(value => [value], error => { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return null; | ||
}); | ||
} | ||
else { | ||
completedItems = [completedItem]; | ||
} | ||
asyncPayloadRecord.addItems(completedItems); | ||
return asyncPayloadRecord; | ||
} | ||
async function executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath) { | ||
let item; | ||
try { | ||
const { value, done } = await iterator.next(); | ||
if (done) { | ||
asyncPayloadRecord.setIsCompletedIterator(); | ||
return { done, value: undefined }; | ||
} | ||
item = value; | ||
} | ||
catch (rawError) { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
// don't continue if iterator throws | ||
return { done: true, value }; | ||
} | ||
let completedItem; | ||
try { | ||
completedItem = completeValue(exeContext, itemType, fieldNodes, info, itemPath, item, asyncPayloadRecord); | ||
if (isPromise(completedItem)) { | ||
completedItem = completedItem.then(undefined, rawError => { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
const handledError = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return handledError; | ||
}); | ||
} | ||
return { done: false, value: completedItem }; | ||
} | ||
catch (rawError) { | ||
const error = locatedError(rawError, fieldNodes, pathToArray(itemPath)); | ||
const value = handleFieldError(error, itemType, asyncPayloadRecord.errors); | ||
filterSubsequentPayloads(exeContext, itemPath, asyncPayloadRecord); | ||
return { done: false, value }; | ||
} | ||
} | ||
async function executeStreamIterator(initialIndex, iterator, exeContext, fieldNodes, info, itemType, path, label, parentContext) { | ||
let index = initialIndex; | ||
let previousAsyncPayloadRecord = parentContext !== null && parentContext !== void 0 ? parentContext : undefined; | ||
while (true) { | ||
const itemPath = addPath(path, index, undefined); | ||
const asyncPayloadRecord = new StreamRecord({ | ||
label, | ||
path: itemPath, | ||
parentContext: previousAsyncPayloadRecord, | ||
iterator, | ||
exeContext, | ||
}); | ||
let iteration; | ||
try { | ||
iteration = await executeStreamIteratorItem(iterator, exeContext, fieldNodes, info, itemType, asyncPayloadRecord, itemPath); | ||
} | ||
catch (error) { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
asyncPayloadRecord.addItems(null); | ||
// entire stream has errored and bubbled upwards | ||
if (iterator === null || iterator === void 0 ? void 0 : iterator.return) { | ||
iterator.return().catch(() => { | ||
// ignore errors | ||
}); | ||
} | ||
return; | ||
} | ||
const { done, value: completedItem } = iteration; | ||
let completedItems; | ||
if (isPromise(completedItem)) { | ||
completedItems = completedItem.then(value => [value], error => { | ||
asyncPayloadRecord.errors.push(error); | ||
filterSubsequentPayloads(exeContext, path, asyncPayloadRecord); | ||
return null; | ||
}); | ||
} | ||
else { | ||
completedItems = [completedItem]; | ||
} | ||
asyncPayloadRecord.addItems(completedItems); | ||
if (done) { | ||
break; | ||
} | ||
previousAsyncPayloadRecord = asyncPayloadRecord; | ||
index++; | ||
} | ||
} | ||
function filterSubsequentPayloads(exeContext, nullPath, currentAsyncRecord) { | ||
const nullPathArray = pathToArray(nullPath); | ||
exeContext.subsequentPayloads.forEach(asyncRecord => { | ||
var _a; | ||
if (asyncRecord === currentAsyncRecord) { | ||
// don't remove payload from where error originates | ||
return; | ||
} | ||
for (let i = 0; i < nullPathArray.length; i++) { | ||
if (asyncRecord.path[i] !== nullPathArray[i]) { | ||
// asyncRecord points to a path unaffected by this payload | ||
return; | ||
} | ||
} | ||
// asyncRecord path points to nulled error field | ||
if (isStreamPayload(asyncRecord) && ((_a = asyncRecord.iterator) === null || _a === void 0 ? void 0 : _a.return)) { | ||
asyncRecord.iterator.return().catch(() => { | ||
// ignore error | ||
}); | ||
} | ||
exeContext.subsequentPayloads.delete(asyncRecord); | ||
}); | ||
} | ||
function getCompletedIncrementalResults(exeContext) { | ||
const incrementalResults = []; | ||
for (const asyncPayloadRecord of exeContext.subsequentPayloads) { | ||
const incrementalResult = {}; | ||
if (!asyncPayloadRecord.isCompleted) { | ||
continue; | ||
} | ||
exeContext.subsequentPayloads.delete(asyncPayloadRecord); | ||
if (isStreamPayload(asyncPayloadRecord)) { | ||
const items = asyncPayloadRecord.items; | ||
if (asyncPayloadRecord.isCompletedIterator) { | ||
// async iterable resolver just finished but there may be pending payloads | ||
continue; | ||
} | ||
incrementalResult.items = items; | ||
} | ||
else { | ||
const data = asyncPayloadRecord.data; | ||
incrementalResult.data = data !== null && data !== void 0 ? data : null; | ||
} | ||
incrementalResult.path = asyncPayloadRecord.path; | ||
if (asyncPayloadRecord.label) { | ||
incrementalResult.label = asyncPayloadRecord.label; | ||
} | ||
if (asyncPayloadRecord.errors.length > 0) { | ||
incrementalResult.errors = asyncPayloadRecord.errors; | ||
} | ||
incrementalResults.push(incrementalResult); | ||
} | ||
return incrementalResults; | ||
} | ||
function yieldSubsequentPayloads(exeContext) { | ||
let isDone = false; | ||
async function next() { | ||
if (isDone) { | ||
return { value: undefined, done: true }; | ||
} | ||
await Promise.race(Array.from(exeContext.subsequentPayloads).map(p => p.promise)); | ||
if (isDone) { | ||
// a different call to next has exhausted all payloads | ||
return { value: undefined, done: true }; | ||
} | ||
const incremental = getCompletedIncrementalResults(exeContext); | ||
const hasNext = exeContext.subsequentPayloads.size > 0; | ||
if (!incremental.length && hasNext) { | ||
return next(); | ||
} | ||
if (!hasNext) { | ||
isDone = true; | ||
} | ||
return { | ||
value: incremental.length ? { incremental, hasNext } : { hasNext }, | ||
done: false, | ||
}; | ||
} | ||
function returnStreamIterators() { | ||
const promises = []; | ||
exeContext.subsequentPayloads.forEach(asyncPayloadRecord => { | ||
var _a; | ||
if (isStreamPayload(asyncPayloadRecord) && ((_a = asyncPayloadRecord.iterator) === null || _a === void 0 ? void 0 : _a.return)) { | ||
promises.push(asyncPayloadRecord.iterator.return()); | ||
} | ||
}); | ||
return Promise.all(promises); | ||
} | ||
return { | ||
[Symbol.asyncIterator]() { | ||
return this; | ||
}, | ||
next, | ||
async return() { | ||
await returnStreamIterators(); | ||
isDone = true; | ||
return { value: undefined, done: true }; | ||
}, | ||
async throw(error) { | ||
await returnStreamIterators(); | ||
isDone = true; | ||
return Promise.reject(error); | ||
}, | ||
}; | ||
} | ||
class DeferredFragmentRecord { | ||
constructor(opts) { | ||
this.type = 'defer'; | ||
this.label = opts.label; | ||
this.path = pathToArray(opts.path); | ||
this.parentContext = opts.parentContext; | ||
this.errors = []; | ||
this._exeContext = opts.exeContext; | ||
this._exeContext.subsequentPayloads.add(this); | ||
this.isCompleted = false; | ||
this.data = null; | ||
this.promise = new Promise(resolve => { | ||
this._resolve = MaybePromise => { | ||
resolve(MaybePromise); | ||
}; | ||
}).then(data => { | ||
this.data = data; | ||
this.isCompleted = true; | ||
}); | ||
} | ||
addData(data) { | ||
var _a, _b, _c; | ||
const parentData = (_a = this.parentContext) === null || _a === void 0 ? void 0 : _a.promise; | ||
if (parentData) { | ||
(_b = this._resolve) === null || _b === void 0 ? void 0 : _b.call(this, parentData.then(() => data)); | ||
return; | ||
} | ||
(_c = this._resolve) === null || _c === void 0 ? void 0 : _c.call(this, data); | ||
} | ||
} | ||
class StreamRecord { | ||
constructor(opts) { | ||
this.type = 'stream'; | ||
this.items = null; | ||
this.label = opts.label; | ||
this.path = pathToArray(opts.path); | ||
this.parentContext = opts.parentContext; | ||
this.iterator = opts.iterator; | ||
this.errors = []; | ||
this._exeContext = opts.exeContext; | ||
this._exeContext.subsequentPayloads.add(this); | ||
this.isCompleted = false; | ||
this.items = null; | ||
this.promise = new Promise(resolve => { | ||
this._resolve = MaybePromise => { | ||
resolve(MaybePromise); | ||
}; | ||
}).then(items => { | ||
this.items = items; | ||
this.isCompleted = true; | ||
}); | ||
} | ||
addItems(items) { | ||
var _a, _b, _c; | ||
const parentData = (_a = this.parentContext) === null || _a === void 0 ? void 0 : _a.promise; | ||
if (parentData) { | ||
(_b = this._resolve) === null || _b === void 0 ? void 0 : _b.call(this, parentData.then(() => items)); | ||
return; | ||
} | ||
(_c = this._resolve) === null || _c === void 0 ? void 0 : _c.call(this, items); | ||
} | ||
setIsCompletedIterator() { | ||
this.isCompletedIterator = true; | ||
} | ||
} | ||
function isStreamPayload(asyncPayload) { | ||
return asyncPayload.type === 'stream'; | ||
} | ||
/** | ||
@@ -1240,4 +797,1 @@ * This method looks up the field on the given type definition. | ||
} | ||
export function isIncrementalResult(result) { | ||
return 'incremental' in result; | ||
} |
export * from './execute.js'; | ||
export * from './values.js'; | ||
export * from './normalizedExecutor.js'; |
{ | ||
"name": "@graphql-tools/executor", | ||
"version": "0.0.3-alpha-20221101131317-20a4af5d", | ||
"version": "0.0.3-alpha-20221101140152-8ae0755c", | ||
"sideEffects": false, | ||
@@ -9,6 +9,4 @@ "peerDependencies": { | ||
"dependencies": { | ||
"@repeaterjs/repeater": "3.0.4", | ||
"@graphql-tools/utils": "9.0.0-alpha-20221101131317-20a4af5d", | ||
"@graphql-typed-document-node/core": "3.1.1", | ||
"value-or-promise": "1.0.1" | ||
"@graphql-tools/utils": "9.0.0-alpha-20221101140152-8ae0755c", | ||
"@graphql-typed-document-node/core": "3.1.1" | ||
}, | ||
@@ -15,0 +13,0 @@ "repository": { |
@@ -1,10 +0,4 @@ | ||
import { GraphQLFormattedError, FieldNode, FragmentDefinitionNode, OperationDefinitionNode, GraphQLField, GraphQLFieldResolver, GraphQLObjectType, GraphQLResolveInfo, GraphQLTypeResolver, GraphQLSchema } from 'graphql'; | ||
import type { GraphQLError } from 'graphql'; | ||
import { Path, Maybe, MaybePromise } from '@graphql-tools/utils'; | ||
import { GraphQLFormattedError, GraphQLError, FieldNode, FragmentDefinitionNode, OperationDefinitionNode, GraphQLField, GraphQLFieldResolver, GraphQLObjectType, GraphQLResolveInfo, GraphQLTypeResolver, GraphQLSchema } from 'graphql'; | ||
import { Maybe, Path, MaybePromise, ExecutionResult } from '@graphql-tools/utils'; | ||
import { TypedDocumentNode } from '@graphql-typed-document-node/core'; | ||
export interface SingularExecutionResult<TData = any, TExtensions = any> { | ||
errors?: ReadonlyArray<GraphQLError>; | ||
data?: TData | null; | ||
extensions?: TExtensions; | ||
} | ||
/** | ||
@@ -35,3 +29,3 @@ * Terminology | ||
*/ | ||
export interface ExecutionContext<TVariables = any, TContext = any> { | ||
export interface ExecutionContext<TContext = any> { | ||
schema: GraphQLSchema; | ||
@@ -42,3 +36,5 @@ fragments: Record<string, FragmentDefinitionNode>; | ||
operation: OperationDefinitionNode; | ||
variableValues: TVariables; | ||
variableValues: { | ||
[variable: string]: unknown; | ||
}; | ||
fieldResolver: GraphQLFieldResolver<any, TContext>; | ||
@@ -48,5 +44,4 @@ typeResolver: GraphQLTypeResolver<any, TContext>; | ||
errors: Array<GraphQLError>; | ||
subsequentPayloads: Set<AsyncPayloadRecord>; | ||
} | ||
export interface FormattedExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> { | ||
export interface FormattedExecutionResult<TData = any, TExtensions = any> { | ||
errors?: ReadonlyArray<GraphQLFormattedError>; | ||
@@ -56,50 +51,2 @@ data?: TData | null; | ||
} | ||
export interface IncrementalExecutionResults<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> { | ||
initialResult: InitialIncrementalExecutionResult<TData, TExtensions>; | ||
subsequentResults: AsyncGenerator<SubsequentIncrementalExecutionResult<TData, TExtensions>, void, void>; | ||
} | ||
export interface InitialIncrementalExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> extends SingularExecutionResult<TData, TExtensions> { | ||
hasNext: boolean; | ||
incremental?: ReadonlyArray<IncrementalResult<TData, TExtensions>>; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedInitialIncrementalExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> extends FormattedExecutionResult<TData, TExtensions> { | ||
hasNext: boolean; | ||
incremental?: ReadonlyArray<FormattedIncrementalResult<TData, TExtensions>>; | ||
extensions?: TExtensions; | ||
} | ||
export interface SubsequentIncrementalExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> { | ||
hasNext: boolean; | ||
incremental?: ReadonlyArray<IncrementalResult<TData, TExtensions>>; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedSubsequentIncrementalExecutionResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> { | ||
hasNext: boolean; | ||
incremental?: ReadonlyArray<FormattedIncrementalResult<TData, TExtensions>>; | ||
extensions?: TExtensions; | ||
} | ||
export interface IncrementalDeferResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> extends SingularExecutionResult<TData, TExtensions> { | ||
path?: ReadonlyArray<string | number>; | ||
label?: string; | ||
} | ||
export interface FormattedIncrementalDeferResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> extends FormattedExecutionResult<TData, TExtensions> { | ||
path?: ReadonlyArray<string | number>; | ||
label?: string; | ||
} | ||
export interface IncrementalStreamResult<TData = Array<unknown>, TExtensions = Record<string, unknown>> { | ||
errors?: ReadonlyArray<GraphQLError>; | ||
items?: TData | null; | ||
path?: ReadonlyArray<string | number>; | ||
label?: string; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedIncrementalStreamResult<TData = Array<unknown>, TExtensions = Record<string, unknown>> { | ||
errors?: ReadonlyArray<GraphQLFormattedError>; | ||
items?: TData | null; | ||
path?: ReadonlyArray<string | number>; | ||
label?: string; | ||
extensions?: TExtensions; | ||
} | ||
export declare type IncrementalResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> = IncrementalDeferResult<TData, TExtensions> | IncrementalStreamResult<TData, TExtensions>; | ||
export declare type FormattedIncrementalResult<TData = Record<string, unknown>, TExtensions = Record<string, unknown>> = FormattedIncrementalDeferResult<TData, TExtensions> | FormattedIncrementalStreamResult<TData, TExtensions>; | ||
export interface ExecutionArgs<TData = any, TVariables = any, TContext = any> { | ||
@@ -117,9 +64,7 @@ schema: GraphQLSchema; | ||
/** | ||
* Implements the "Executing requests" section of the GraphQL specification, | ||
* including `@defer` and `@stream` as proposed in | ||
* https://github.com/graphql/graphql-spec/pull/742 | ||
* Implements the "Executing requests" section of the GraphQL specification. | ||
* | ||
* This function returns a Promise of an IncrementalExecutionResults | ||
* object. This object either consists of a single ExecutionResult, or an | ||
* object containing an `initialResult` and a stream of `subsequentResults`. | ||
* Returns either a synchronous ExecutionResult (if all encountered resolvers | ||
* are synchronous), or a Promise of an ExecutionResult that will eventually be | ||
* resolved and never rejected. | ||
* | ||
@@ -129,3 +74,7 @@ * If the arguments to this function do not result in a legal execution context, | ||
*/ | ||
export declare function execute<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<SingularExecutionResult<TData> | IncrementalExecutionResults<TData>>; | ||
export declare function execute<TData = { | ||
[key: string]: any; | ||
}, TVariables = { | ||
[key: string]: any; | ||
}, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): MaybePromise<ExecutionResult<TData>>; | ||
/** | ||
@@ -136,3 +85,3 @@ * Also implements the "Executing requests" section of the GraphQL specification. | ||
*/ | ||
export declare function executeSync(args: ExecutionArgs): SingularExecutionResult; | ||
export declare function executeSync(args: ExecutionArgs): ExecutionResult; | ||
/** | ||
@@ -154,3 +103,7 @@ * Essential assertions before executing to provide developer feedback for | ||
*/ | ||
export declare function buildExecutionContext<TData = any, TVariables = any, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): ReadonlyArray<GraphQLError> | ExecutionContext; | ||
export declare function buildExecutionContext<TData = { | ||
[key: string]: any; | ||
}, TVariables = { | ||
[key: string]: any; | ||
}, TContext = any>(args: ExecutionArgs<TData, TVariables, TContext>): ReadonlyArray<GraphQLError> | ExecutionContext; | ||
/** | ||
@@ -160,3 +113,3 @@ * TODO: consider no longer exporting this function | ||
*/ | ||
export declare function buildResolveInfo(exeContext: ExecutionContext, fieldDef: GraphQLField<unknown, unknown>, fieldNodes: Array<FieldNode>, parentType: GraphQLObjectType, path: Path): GraphQLResolveInfo; | ||
export declare function buildResolveInfo(exeContext: ExecutionContext, fieldDef: GraphQLField<unknown, unknown>, fieldNodes: ReadonlyArray<FieldNode>, parentType: GraphQLObjectType, path: Path): GraphQLResolveInfo; | ||
/** | ||
@@ -181,5 +134,3 @@ * If a resolveType function is not given, then a default resolve behavior is | ||
/** | ||
* Implements the "Subscribe" algorithm described in the GraphQL specification, | ||
* including `@defer` and `@stream` as proposed in | ||
* https://github.com/graphql/graphql-spec/pull/742 | ||
* Implements the "Subscribe" algorithm described in the GraphQL specification. | ||
* | ||
@@ -192,25 +143,15 @@ * Returns a Promise which resolves to either an AsyncIterator (if successful) | ||
* If the client-provided arguments to this function do not result in a | ||
* compliant subscription, a GraphQL Response (ExecutionResult) with descriptive | ||
* errors and no data will be returned. | ||
* compliant subscription, a GraphQL Response (ExecutionResult) with | ||
* descriptive errors and no data will be returned. | ||
* | ||
* If the source stream could not be created due to faulty subscription resolver | ||
* logic or underlying systems, the promise will resolve to a single | ||
* If the source stream could not be created due to faulty subscription | ||
* resolver logic or underlying systems, the promise will resolve to a single | ||
* ExecutionResult containing `errors` and no `data`. | ||
* | ||
* If the operation succeeded, the promise resolves to an AsyncIterator, which | ||
* yields a stream of result representing the response stream. | ||
* yields a stream of ExecutionResults representing the response stream. | ||
* | ||
* Each result may be an ExecutionResult with no `hasNext` (if executing the | ||
* event did not use `@defer` or `@stream`), or an | ||
* `InitialIncrementalExecutionResult` or `SubsequentIncrementalExecutionResult` | ||
* (if executing the event used `@defer` or `@stream`). In the case of | ||
* incremental execution results, each event produces a single | ||
* `InitialIncrementalExecutionResult` followed by one or more | ||
* `SubsequentIncrementalExecutionResult`s; all but the last have `hasNext: true`, | ||
* and the last has `hasNext: false`. There is no interleaving between results | ||
* generated from the same original event. | ||
* | ||
* Accepts an object with named arguments. | ||
* Accepts either an object with named arguments, or individual arguments. | ||
*/ | ||
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>>; | ||
export declare function subscribe(args: ExecutionArgs): MaybePromise<AsyncIterable<ExecutionResult> | ExecutionResult>; | ||
/** | ||
@@ -244,46 +185,3 @@ * Implements the "CreateSourceEventStream" algorithm described in the | ||
*/ | ||
export declare function createSourceEventStream(args: ExecutionArgs): MaybePromise<AsyncIterable<unknown> | SingularExecutionResult>; | ||
declare class DeferredFragmentRecord { | ||
type: 'defer'; | ||
errors: Array<GraphQLError>; | ||
label: string | undefined; | ||
path: Array<string | number>; | ||
promise: Promise<void>; | ||
data: Record<string, unknown> | null; | ||
parentContext: AsyncPayloadRecord | undefined; | ||
isCompleted: boolean; | ||
_exeContext: ExecutionContext; | ||
_resolve?: (arg: MaybePromise<Record<string, unknown> | null>) => void; | ||
constructor(opts: { | ||
label: string | undefined; | ||
path: Path | undefined; | ||
parentContext: AsyncPayloadRecord | undefined; | ||
exeContext: ExecutionContext; | ||
}); | ||
addData(data: MaybePromise<Record<string, unknown> | null>): void; | ||
} | ||
declare class StreamRecord { | ||
type: 'stream'; | ||
errors: Array<GraphQLError>; | ||
label: string | undefined; | ||
path: Array<string | number>; | ||
items: Array<unknown> | null; | ||
promise: Promise<void>; | ||
parentContext: AsyncPayloadRecord | undefined; | ||
iterator: AsyncIterator<unknown> | undefined; | ||
isCompletedIterator?: boolean; | ||
isCompleted: boolean; | ||
_exeContext: ExecutionContext; | ||
_resolve?: (arg: MaybePromise<Array<unknown> | null>) => void; | ||
constructor(opts: { | ||
label: string | undefined; | ||
path: Path | undefined; | ||
iterator?: AsyncIterator<unknown>; | ||
parentContext: AsyncPayloadRecord | undefined; | ||
exeContext: ExecutionContext; | ||
}); | ||
addItems(items: MaybePromise<Array<unknown> | null>): void; | ||
setIsCompletedIterator(): void; | ||
} | ||
declare type AsyncPayloadRecord = DeferredFragmentRecord | StreamRecord; | ||
export declare function createSourceEventStream(args: ExecutionArgs): MaybePromise<AsyncIterable<unknown> | ExecutionResult>; | ||
/** | ||
@@ -301,3 +199,1 @@ * This method looks up the field on the given type definition. | ||
export declare function getFieldDef(schema: GraphQLSchema, parentType: GraphQLObjectType, fieldNode: FieldNode): Maybe<GraphQLField<unknown, unknown>>; | ||
export declare function isIncrementalResult<TData>(result: SingularExecutionResult<TData> | IncrementalExecutionResults<TData>): result is IncrementalExecutionResults<TData>; | ||
export {}; |
export * from './execute.js'; | ||
export * from './values.js'; | ||
export * from './normalizedExecutor.js'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
3
122981
23
2291
+ Added@graphql-tools/utils@9.0.0-alpha-20221101140152-8ae0755c(transitive)
- Removed@repeaterjs/repeater@3.0.4
- Removedvalue-or-promise@1.0.1
- Removed@babel/runtime@7.26.7(transitive)
- Removed@changesets/apply-release-plan@7.0.8(transitive)
- Removed@changesets/assemble-release-plan@6.0.5(transitive)
- Removed@changesets/changelog-git@0.2.0(transitive)
- Removed@changesets/cli@2.27.12(transitive)
- Removed@changesets/config@3.0.5(transitive)
- Removed@changesets/errors@0.2.0(transitive)
- Removed@changesets/get-dependents-graph@2.1.2(transitive)
- Removed@changesets/get-release-plan@4.0.6(transitive)
- Removed@changesets/get-version-range-type@0.4.0(transitive)
- Removed@changesets/git@3.0.2(transitive)
- Removed@changesets/logger@0.1.1(transitive)
- Removed@changesets/parse@0.4.0(transitive)
- Removed@changesets/pre@2.0.1(transitive)
- Removed@changesets/read@0.6.2(transitive)
- Removed@changesets/should-skip-package@0.1.1(transitive)
- Removed@changesets/types@4.1.06.0.0(transitive)
- Removed@changesets/write@0.3.2(transitive)
- Removed@graphql-tools/utils@9.0.0-alpha-20221101131317-20a4af5d(transitive)
- Removed@manypkg/find-root@1.1.0(transitive)
- Removed@manypkg/get-packages@1.1.3(transitive)
- Removed@nodelib/fs.scandir@2.1.5(transitive)
- Removed@nodelib/fs.stat@2.0.5(transitive)
- Removed@nodelib/fs.walk@1.2.8(transitive)
- Removed@repeaterjs/repeater@3.0.4(transitive)
- Removed@types/node@12.20.55(transitive)
- Removedansi-colors@4.1.3(transitive)
- Removedansi-regex@5.0.1(transitive)
- Removedargparse@1.0.10(transitive)
- Removedarray-union@2.1.0(transitive)
- Removedbetter-path-resolve@1.0.0(transitive)
- Removedbraces@3.0.3(transitive)
- Removedchardet@0.7.0(transitive)
- Removedci-info@3.9.0(transitive)
- Removedcross-spawn@7.0.6(transitive)
- Removeddetect-indent@6.1.0(transitive)
- Removeddir-glob@3.0.1(transitive)
- Removedenquirer@2.4.1(transitive)
- Removedesprima@4.0.1(transitive)
- Removedextendable-error@0.1.7(transitive)
- Removedexternal-editor@3.1.0(transitive)
- Removedfast-glob@3.3.3(transitive)
- Removedfastq@1.19.0(transitive)
- Removedfill-range@7.1.1(transitive)
- Removedfind-up@4.1.0(transitive)
- Removedfs-extra@7.0.18.1.0(transitive)
- Removedglob-parent@5.1.2(transitive)
- Removedglobby@11.1.0(transitive)
- Removedgraceful-fs@4.2.11(transitive)
- Removedhuman-id@1.0.2(transitive)
- Removediconv-lite@0.4.24(transitive)
- Removedignore@5.3.2(transitive)
- Removedis-extglob@2.1.1(transitive)
- Removedis-glob@4.0.3(transitive)
- Removedis-number@7.0.0(transitive)
- Removedis-subdir@1.2.0(transitive)
- Removedis-windows@1.0.2(transitive)
- Removedisexe@2.0.0(transitive)
- Removedjs-yaml@3.14.1(transitive)
- Removedjsonfile@4.0.0(transitive)
- Removedlocate-path@5.0.0(transitive)
- Removedlodash.startcase@4.4.0(transitive)
- Removedmerge2@1.4.1(transitive)
- Removedmicromatch@4.0.8(transitive)
- Removedmri@1.2.0(transitive)
- Removedos-tmpdir@1.0.2(transitive)
- Removedoutdent@0.5.0(transitive)
- Removedp-filter@2.1.0(transitive)
- Removedp-limit@2.3.0(transitive)
- Removedp-locate@4.1.0(transitive)
- Removedp-map@2.1.0(transitive)
- Removedp-try@2.2.0(transitive)
- Removedpackage-manager-detector@0.2.9(transitive)
- Removedpath-exists@4.0.0(transitive)
- Removedpath-key@3.1.1(transitive)
- Removedpath-type@4.0.0(transitive)
- Removedpicocolors@1.1.1(transitive)
- Removedpicomatch@2.3.1(transitive)
- Removedpify@4.0.1(transitive)
- Removedprettier@2.8.8(transitive)
- Removedqueue-microtask@1.2.3(transitive)
- Removedread-yaml-file@1.1.0(transitive)
- Removedregenerator-runtime@0.14.1(transitive)
- Removedresolve-from@5.0.0(transitive)
- Removedreusify@1.0.4(transitive)
- Removedrun-parallel@1.2.0(transitive)
- Removedsafer-buffer@2.1.2(transitive)
- Removedsemver@7.7.0(transitive)
- Removedshebang-command@2.0.0(transitive)
- Removedshebang-regex@3.0.0(transitive)
- Removedsignal-exit@4.1.0(transitive)
- Removedslash@3.0.0(transitive)
- Removedspawndamnit@3.0.1(transitive)
- Removedsprintf-js@1.0.3(transitive)
- Removedstrip-ansi@6.0.1(transitive)
- Removedstrip-bom@3.0.0(transitive)
- Removedterm-size@2.2.1(transitive)
- Removedtmp@0.0.33(transitive)
- Removedto-regex-range@5.0.1(transitive)
- Removeduniversalify@0.1.2(transitive)
- Removedvalue-or-promise@1.0.1(transitive)
- Removedwhich@2.0.2(transitive)
Updated@graphql-tools/utils@9.0.0-alpha-20221101140152-8ae0755c