Comparing version 17.0.0-alpha.3.canary.pr.4035.3404abc2382e32f6a3ab26f08a9ed54554678fa9 to 17.0.0-alpha.3.canary.pr.4097.291dd92c9059c6bcc88ff1fa21058a8ac519cf83
@@ -22,6 +22,6 @@ import type { Maybe } from '../jsutils/Maybe.js'; | ||
import type { | ||
CancellableStreamRecord, | ||
ExecutionResult, | ||
ExperimentalIncrementalExecutionResults, | ||
} from './IncrementalPublisher.js'; | ||
import { StreamRecord } from './IncrementalPublisher.js'; | ||
} from './types.js'; | ||
/** | ||
@@ -64,4 +64,5 @@ * Terminology | ||
subscribeFieldResolver: GraphQLFieldResolver<any, any>; | ||
errors?: Array<GraphQLError> | undefined; | ||
cancellableStreams?: Set<StreamRecord> | undefined; | ||
enableEarlyExecution: boolean; | ||
errors: Array<GraphQLError> | undefined; | ||
cancellableStreams: Set<CancellableStreamRecord> | undefined; | ||
} | ||
@@ -80,2 +81,3 @@ export interface ExecutionArgs { | ||
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, any>>; | ||
enableEarlyExecution?: Maybe<boolean>; | ||
} | ||
@@ -82,0 +84,0 @@ export interface StreamUsage { |
import type { ObjMap } from '../jsutils/ObjMap.js'; | ||
import type { Path } from '../jsutils/Path.js'; | ||
import type { PromiseOrValue } from '../jsutils/PromiseOrValue.js'; | ||
import type { GraphQLError } from '../error/GraphQLError.js'; | ||
import type { | ||
GraphQLError, | ||
GraphQLFormattedError, | ||
} from '../error/GraphQLError.js'; | ||
import type { DeferUsageSet } from './buildFieldPlan.js'; | ||
/** | ||
* The result of GraphQL execution. | ||
* | ||
* - `errors` is included when any errors occurred as a non-empty array. | ||
* - `data` is the result of a successful execution of the query. | ||
* - `hasNext` is true if a future payload is expected. | ||
* - `extensions` is reserved for adding non-standard properties. | ||
* - `incremental` is a list of the results from defer/stream directives. | ||
*/ | ||
export interface ExecutionResult< | ||
TData = ObjMap<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> { | ||
errors?: ReadonlyArray<GraphQLError>; | ||
data?: TData | null; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedExecutionResult< | ||
TData = ObjMap<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> { | ||
errors?: ReadonlyArray<GraphQLFormattedError>; | ||
data?: TData | null; | ||
extensions?: TExtensions; | ||
} | ||
export interface ExperimentalIncrementalExecutionResults< | ||
TData = unknown, | ||
TExtensions = ObjMap<unknown>, | ||
> { | ||
initialResult: InitialIncrementalExecutionResult<TData, TExtensions>; | ||
subsequentResults: AsyncGenerator< | ||
SubsequentIncrementalExecutionResult<TData, TExtensions>, | ||
void, | ||
void | ||
>; | ||
} | ||
export interface InitialIncrementalExecutionResult< | ||
TData = ObjMap<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> extends ExecutionResult<TData, TExtensions> { | ||
data: TData; | ||
pending: ReadonlyArray<PendingResult>; | ||
hasNext: true; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedInitialIncrementalExecutionResult< | ||
TData = ObjMap<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> extends FormattedExecutionResult<TData, TExtensions> { | ||
data: TData; | ||
pending: ReadonlyArray<PendingResult>; | ||
hasNext: boolean; | ||
extensions?: TExtensions; | ||
} | ||
export interface SubsequentIncrementalExecutionResult< | ||
TData = unknown, | ||
TExtensions = ObjMap<unknown>, | ||
> { | ||
pending?: ReadonlyArray<PendingResult>; | ||
incremental?: ReadonlyArray<IncrementalResult<TData, TExtensions>>; | ||
completed?: ReadonlyArray<CompletedResult>; | ||
hasNext: boolean; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedSubsequentIncrementalExecutionResult< | ||
TData = unknown, | ||
TExtensions = ObjMap<unknown>, | ||
> { | ||
hasNext: boolean; | ||
pending?: ReadonlyArray<PendingResult>; | ||
incremental?: ReadonlyArray<FormattedIncrementalResult<TData, TExtensions>>; | ||
completed?: ReadonlyArray<FormattedCompletedResult>; | ||
extensions?: TExtensions; | ||
} | ||
interface BareDeferredGroupedFieldSetResult<TData = ObjMap<unknown>> { | ||
errors?: ReadonlyArray<GraphQLError>; | ||
data: TData; | ||
} | ||
export interface IncrementalDeferResult< | ||
TData = ObjMap<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> extends BareDeferredGroupedFieldSetResult<TData> { | ||
id: string; | ||
subPath?: ReadonlyArray<string | number>; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedIncrementalDeferResult< | ||
TData = ObjMap<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> { | ||
errors?: ReadonlyArray<GraphQLFormattedError>; | ||
data: TData; | ||
id: string; | ||
subPath?: ReadonlyArray<string | number>; | ||
extensions?: TExtensions; | ||
} | ||
interface BareStreamItemsResult<TData = ReadonlyArray<unknown>> { | ||
errors?: ReadonlyArray<GraphQLError>; | ||
items: TData; | ||
} | ||
export interface IncrementalStreamResult< | ||
TData = ReadonlyArray<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> extends BareStreamItemsResult<TData> { | ||
id: string; | ||
subPath?: ReadonlyArray<string | number>; | ||
extensions?: TExtensions; | ||
} | ||
export interface FormattedIncrementalStreamResult< | ||
TData = Array<unknown>, | ||
TExtensions = ObjMap<unknown>, | ||
> { | ||
errors?: ReadonlyArray<GraphQLFormattedError>; | ||
items: TData; | ||
id: string; | ||
subPath?: ReadonlyArray<string | number>; | ||
extensions?: TExtensions; | ||
} | ||
export type IncrementalResult<TData = unknown, TExtensions = ObjMap<unknown>> = | ||
| IncrementalDeferResult<TData, TExtensions> | ||
| IncrementalStreamResult<TData, TExtensions>; | ||
export type FormattedIncrementalResult< | ||
TData = unknown, | ||
TExtensions = ObjMap<unknown>, | ||
> = | ||
| FormattedIncrementalDeferResult<TData, TExtensions> | ||
| FormattedIncrementalStreamResult<TData, TExtensions>; | ||
export interface PendingResult { | ||
id: string; | ||
path: ReadonlyArray<string | number>; | ||
label?: string; | ||
} | ||
export interface CompletedResult { | ||
id: string; | ||
errors?: ReadonlyArray<GraphQLError>; | ||
} | ||
export interface FormattedCompletedResult { | ||
path: ReadonlyArray<string | number>; | ||
label?: string; | ||
errors?: ReadonlyArray<GraphQLError>; | ||
} | ||
CancellableStreamRecord, | ||
ExperimentalIncrementalExecutionResults, | ||
IncrementalDataRecord, | ||
} from './types.js'; | ||
export declare function buildIncrementalResponse( | ||
@@ -157,117 +15,4 @@ context: IncrementalPublisherContext, | ||
interface IncrementalPublisherContext { | ||
cancellableStreams?: Set<StreamRecord> | undefined; | ||
cancellableStreams: Set<CancellableStreamRecord> | undefined; | ||
} | ||
export interface IncrementalContext { | ||
deferUsageSet: DeferUsageSet | undefined; | ||
path: Path | undefined; | ||
errors?: Array<GraphQLError> | undefined; | ||
} | ||
export type DeferredGroupedFieldSetResult = | ||
| ReconcilableDeferredGroupedFieldSetResult | ||
| NonReconcilableDeferredGroupedFieldSetResult; | ||
export declare function isDeferredGroupedFieldSetResult( | ||
subsequentResult: DeferredGroupedFieldSetResult | StreamItemsResult, | ||
): subsequentResult is DeferredGroupedFieldSetResult; | ||
interface ReconcilableDeferredGroupedFieldSetResult { | ||
deferredFragmentRecords: ReadonlyArray<DeferredFragmentRecord>; | ||
path: Array<string | number>; | ||
result: BareDeferredGroupedFieldSetResult; | ||
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>; | ||
sent?: true | undefined; | ||
} | ||
interface NonReconcilableDeferredGroupedFieldSetResult { | ||
result: null; | ||
errors: ReadonlyArray<GraphQLError>; | ||
deferredFragmentRecords: ReadonlyArray<DeferredFragmentRecord>; | ||
path: Array<string | number>; | ||
} | ||
export declare function isNonReconcilableDeferredGroupedFieldSetResult( | ||
deferredGroupedFieldSetResult: DeferredGroupedFieldSetResult, | ||
): deferredGroupedFieldSetResult is NonReconcilableDeferredGroupedFieldSetResult; | ||
/** @internal */ | ||
export declare class DeferredGroupedFieldSetRecord { | ||
path: Path | undefined; | ||
deferredFragmentRecords: ReadonlyArray<DeferredFragmentRecord>; | ||
result: PromiseOrValue<DeferredGroupedFieldSetResult>; | ||
constructor(opts: { | ||
path: Path | undefined; | ||
deferUsageSet: DeferUsageSet; | ||
deferredFragmentRecords: ReadonlyArray<DeferredFragmentRecord>; | ||
executor: ( | ||
incrementalContext: IncrementalContext, | ||
) => PromiseOrValue<DeferredGroupedFieldSetResult>; | ||
}); | ||
} | ||
/** @internal */ | ||
export declare class DeferredFragmentRecord { | ||
path: Path | undefined; | ||
label: string | undefined; | ||
deferredGroupedFieldSetRecords: Array<DeferredGroupedFieldSetRecord>; | ||
results: Array<DeferredGroupedFieldSetResult>; | ||
reconcilableResults: Array<ReconcilableDeferredGroupedFieldSetResult>; | ||
parent: DeferredFragmentRecord | undefined; | ||
children: Set<DeferredFragmentRecord>; | ||
id?: string | undefined; | ||
constructor(opts: { | ||
path: Path | undefined; | ||
label: string | undefined; | ||
parent: DeferredFragmentRecord | undefined; | ||
}); | ||
} | ||
/** @internal */ | ||
export declare class StreamRecord { | ||
label: string | undefined; | ||
path: Path; | ||
earlyReturn: (() => Promise<unknown>) | undefined; | ||
id?: string | undefined; | ||
constructor(opts: { | ||
label: string | undefined; | ||
path: Path; | ||
earlyReturn?: (() => Promise<unknown>) | undefined; | ||
}); | ||
} | ||
interface NonReconcilableStreamItemsResult { | ||
streamRecord: StreamRecord; | ||
result: null; | ||
errors: ReadonlyArray<GraphQLError>; | ||
} | ||
interface NonTerminatingStreamItemsResult { | ||
streamRecord: StreamRecord; | ||
result: BareStreamItemsResult; | ||
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>; | ||
} | ||
interface TerminatingStreamItemsResult { | ||
streamRecord: StreamRecord; | ||
result?: never; | ||
incrementalDataRecords?: never; | ||
errors?: never; | ||
} | ||
export type StreamItemsResult = | ||
| NonReconcilableStreamItemsResult | ||
| NonTerminatingStreamItemsResult | ||
| TerminatingStreamItemsResult; | ||
export declare function isNonTerminatingStreamItemsResult( | ||
streamItemsResult: StreamItemsResult, | ||
): streamItemsResult is NonTerminatingStreamItemsResult; | ||
/** @internal */ | ||
export declare class StreamItemsRecord { | ||
streamRecord: StreamRecord; | ||
nextStreamItems: StreamItemsRecord | undefined; | ||
private _result; | ||
constructor(opts: { | ||
streamRecord: StreamRecord; | ||
itemPath?: Path | undefined; | ||
executor: ( | ||
incrementalContext: IncrementalContext, | ||
) => PromiseOrValue<StreamItemsResult>; | ||
}); | ||
getResult(): PromiseOrValue<StreamItemsResult>; | ||
private _prependNextStreamItems; | ||
} | ||
export type IncrementalDataRecord = | ||
| DeferredGroupedFieldSetRecord | ||
| StreamItemsRecord; | ||
export type IncrementalDataRecordResult = | ||
| DeferredGroupedFieldSetResult | ||
| StreamItemsResult; | ||
export {}; |
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
exports.StreamItemsRecord = | ||
exports.isNonTerminatingStreamItemsResult = | ||
exports.StreamRecord = | ||
exports.DeferredFragmentRecord = | ||
exports.DeferredGroupedFieldSetRecord = | ||
exports.isNonReconcilableDeferredGroupedFieldSetResult = | ||
exports.isDeferredGroupedFieldSetResult = | ||
exports.buildIncrementalResponse = | ||
void 0; | ||
const isPromise_js_1 = require('../jsutils/isPromise.js'); | ||
exports.buildIncrementalResponse = void 0; | ||
const invariant_js_1 = require('../jsutils/invariant.js'); | ||
const Path_js_1 = require('../jsutils/Path.js'); | ||
const promiseWithResolvers_js_1 = require('../jsutils/promiseWithResolvers.js'); | ||
const IncrementalGraph_js_1 = require('./IncrementalGraph.js'); | ||
const types_js_1 = require('./types.js'); | ||
function buildIncrementalResponse( | ||
@@ -39,13 +32,8 @@ context, | ||
this._nextId = 0; | ||
this._pending = new Set(); | ||
this._completedResultQueue = []; | ||
this._newPending = new Set(); | ||
this._incremental = []; | ||
this._completed = []; | ||
this._reset(); | ||
this._incrementalGraph = new IncrementalGraph_js_1.IncrementalGraph(); | ||
} | ||
buildResponse(data, errors, incrementalDataRecords) { | ||
this._addIncrementalDataRecords(incrementalDataRecords); | ||
this._pruneEmpty(); | ||
const pending = this._pendingSourcesToResults(); | ||
this._incrementalGraph.addIncrementalDataRecords(incrementalDataRecords); | ||
const newPending = this._incrementalGraph.getNewPending(); | ||
const pending = this._pendingSourcesToResults(newPending); | ||
const initialResult = | ||
@@ -60,99 +48,6 @@ errors === undefined | ||
} | ||
_addIncrementalDataRecords(incrementalDataRecords) { | ||
for (const incrementalDataRecord of incrementalDataRecords) { | ||
if (isDeferredGroupedFieldSetRecord(incrementalDataRecord)) { | ||
for (const deferredFragmentRecord of incrementalDataRecord.deferredFragmentRecords) { | ||
this._addDeferredFragmentRecord(deferredFragmentRecord); | ||
} | ||
const result = incrementalDataRecord.result; | ||
if ((0, isPromise_js_1.isPromise)(result)) { | ||
// eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
result.then((resolved) => { | ||
this._enqueueCompletedDeferredGroupedFieldSet(resolved); | ||
}); | ||
} else { | ||
this._enqueueCompletedDeferredGroupedFieldSet(result); | ||
} | ||
continue; | ||
} | ||
const streamRecord = incrementalDataRecord.streamRecord; | ||
if (streamRecord.id === undefined) { | ||
this._newPending.add(streamRecord); | ||
} | ||
const result = incrementalDataRecord.getResult(); | ||
if ((0, isPromise_js_1.isPromise)(result)) { | ||
// eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
result.then((resolved) => { | ||
this._enqueueCompletedStreamItems(resolved); | ||
}); | ||
} else { | ||
this._enqueueCompletedStreamItems(result); | ||
} | ||
} | ||
} | ||
_addDeferredFragmentRecord(deferredFragmentRecord) { | ||
const parent = deferredFragmentRecord.parent; | ||
if (parent === undefined) { | ||
if (deferredFragmentRecord.id !== undefined) { | ||
return; | ||
} | ||
this._newPending.add(deferredFragmentRecord); | ||
return; | ||
} | ||
if (parent.children.has(deferredFragmentRecord)) { | ||
return; | ||
} | ||
parent.children.add(deferredFragmentRecord); | ||
this._addDeferredFragmentRecord(parent); | ||
} | ||
_pruneEmpty() { | ||
const maybeEmptyNewPending = this._newPending; | ||
this._newPending = new Set(); | ||
for (const node of maybeEmptyNewPending) { | ||
if (isDeferredFragmentRecord(node)) { | ||
if (node.deferredGroupedFieldSetRecords.length > 0) { | ||
this._newPending.add(node); | ||
continue; | ||
} | ||
for (const child of node.children) { | ||
this._addNonEmptyNewPending(child); | ||
} | ||
} else { | ||
this._newPending.add(node); | ||
} | ||
} | ||
} | ||
_addNonEmptyNewPending(deferredFragmentRecord) { | ||
if (deferredFragmentRecord.deferredGroupedFieldSetRecords.length > 0) { | ||
this._newPending.add(deferredFragmentRecord); | ||
return; | ||
} | ||
/* c8 ignore next 5 */ | ||
// TODO: add test case for this, if when skipping an empty deferred fragment, the empty fragment has nested children. | ||
for (const child of deferredFragmentRecord.children) { | ||
this._addNonEmptyNewPending(child); | ||
} | ||
} | ||
_enqueueCompletedDeferredGroupedFieldSet(result) { | ||
let hasPendingParent = false; | ||
for (const deferredFragmentRecord of result.deferredFragmentRecords) { | ||
if (deferredFragmentRecord.id !== undefined) { | ||
hasPendingParent = true; | ||
} | ||
deferredFragmentRecord.results.push(result); | ||
} | ||
if (hasPendingParent) { | ||
this._completedResultQueue.push(result); | ||
this._trigger(); | ||
} | ||
} | ||
_enqueueCompletedStreamItems(result) { | ||
this._completedResultQueue.push(result); | ||
this._trigger(); | ||
} | ||
_pendingSourcesToResults() { | ||
_pendingSourcesToResults(newPending) { | ||
const pendingResults = []; | ||
for (const pendingSource of this._newPending) { | ||
for (const pendingSource of newPending) { | ||
const id = String(this._getNextId()); | ||
this._pending.add(pendingSource); | ||
pendingSource.id = id; | ||
@@ -168,3 +63,2 @@ const pendingResult = { | ||
} | ||
this._newPending.clear(); | ||
return pendingResults; | ||
@@ -178,59 +72,50 @@ } | ||
const _next = async () => { | ||
while (!isDone) { | ||
let pending = []; | ||
let completedResult; | ||
while ( | ||
(completedResult = this._completedResultQueue.shift()) !== undefined | ||
) { | ||
if (isDeferredGroupedFieldSetResult(completedResult)) { | ||
this._handleCompletedDeferredGroupedFieldSet(completedResult); | ||
} else { | ||
this._handleCompletedStreamItems(completedResult); | ||
} | ||
pending = [...pending, ...this._pendingSourcesToResults()]; | ||
if (isDone) { | ||
await this._returnAsyncIteratorsIgnoringErrors(); | ||
return { value: undefined, done: true }; | ||
} | ||
const context = { | ||
pending: [], | ||
incremental: [], | ||
completed: [], | ||
}; | ||
const completedIncrementalData = | ||
this._incrementalGraph.completedIncrementalData(); | ||
// use the raw iterator rather than 'for await ... of' so as not to trigger the | ||
// '.return()' method on the iterator when exiting the loop with the next value | ||
const asyncIterator = completedIncrementalData[Symbol.asyncIterator](); | ||
let iteration = await asyncIterator.next(); | ||
while (!iteration.done) { | ||
for (const completedResult of iteration.value) { | ||
this._handleCompletedIncrementalData(completedResult, context); | ||
} | ||
if (this._incremental.length > 0 || this._completed.length > 0) { | ||
const hasNext = this._pending.size > 0; | ||
const { incremental, completed } = context; | ||
if (incremental.length > 0 || completed.length > 0) { | ||
const hasNext = this._incrementalGraph.hasNext(); | ||
if (!hasNext) { | ||
// eslint-disable-next-line require-atomic-updates | ||
isDone = true; | ||
} | ||
const subsequentIncrementalExecutionResult = { hasNext }; | ||
const pending = context.pending; | ||
if (pending.length > 0) { | ||
subsequentIncrementalExecutionResult.pending = pending; | ||
} | ||
if (this._incremental.length > 0) { | ||
subsequentIncrementalExecutionResult.incremental = | ||
this._incremental; | ||
if (incremental.length > 0) { | ||
subsequentIncrementalExecutionResult.incremental = incremental; | ||
} | ||
if (this._completed.length > 0) { | ||
subsequentIncrementalExecutionResult.completed = this._completed; | ||
if (completed.length > 0) { | ||
subsequentIncrementalExecutionResult.completed = completed; | ||
} | ||
this._incremental = []; | ||
this._completed = []; | ||
return { value: subsequentIncrementalExecutionResult, done: false }; | ||
} | ||
// eslint-disable-next-line no-await-in-loop | ||
await this._signalled; | ||
iteration = await asyncIterator.next(); | ||
} | ||
await returnStreamIterators().catch(() => { | ||
// ignore errors | ||
}); | ||
await this._returnAsyncIteratorsIgnoringErrors(); | ||
return { value: undefined, done: true }; | ||
}; | ||
const returnStreamIterators = async () => { | ||
const cancellableStreams = this._context.cancellableStreams; | ||
if (cancellableStreams === undefined) { | ||
return; | ||
} | ||
const promises = []; | ||
for (const streamRecord of cancellableStreams) { | ||
if (streamRecord.earlyReturn !== undefined) { | ||
promises.push(streamRecord.earlyReturn()); | ||
} | ||
} | ||
await Promise.all(promises); | ||
}; | ||
const _return = async () => { | ||
isDone = true; | ||
await returnStreamIterators(); | ||
await this._returnAsyncIterators(); | ||
return { value: undefined, done: true }; | ||
@@ -240,3 +125,3 @@ }; | ||
isDone = true; | ||
await returnStreamIterators(); | ||
await this._returnAsyncIterators(); | ||
return Promise.reject(error); | ||
@@ -253,44 +138,53 @@ }; | ||
} | ||
_trigger() { | ||
this._resolve(); | ||
this._reset(); | ||
_handleCompletedIncrementalData(completedIncrementalData, context) { | ||
if ( | ||
(0, types_js_1.isDeferredGroupedFieldSetResult)(completedIncrementalData) | ||
) { | ||
this._handleCompletedDeferredGroupedFieldSet( | ||
completedIncrementalData, | ||
context, | ||
); | ||
} else { | ||
this._handleCompletedStreamItems(completedIncrementalData, context); | ||
} | ||
const newPending = this._incrementalGraph.getNewPending(); | ||
context.pending.push(...this._pendingSourcesToResults(newPending)); | ||
} | ||
_reset() { | ||
// promiseWithResolvers uses void only as a generic type parameter | ||
// see: https://typescript-eslint.io/rules/no-invalid-void-type/ | ||
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type | ||
const { promise: signalled, resolve } = (0, | ||
promiseWithResolvers_js_1.promiseWithResolvers)(); | ||
this._resolve = resolve; | ||
this._signalled = signalled; | ||
} | ||
_handleCompletedDeferredGroupedFieldSet(deferredGroupedFieldSetResult) { | ||
_handleCompletedDeferredGroupedFieldSet( | ||
deferredGroupedFieldSetResult, | ||
context, | ||
) { | ||
if ( | ||
isNonReconcilableDeferredGroupedFieldSetResult( | ||
(0, types_js_1.isNonReconcilableDeferredGroupedFieldSetResult)( | ||
deferredGroupedFieldSetResult, | ||
) | ||
) { | ||
for (const deferredFragmentRecord of deferredGroupedFieldSetResult.deferredFragmentRecords) { | ||
for (const deferredFragmentRecord of deferredGroupedFieldSetResult | ||
.deferredGroupedFieldSetRecord.deferredFragmentRecords) { | ||
const id = deferredFragmentRecord.id; | ||
if (id !== undefined) { | ||
this._completed.push({ | ||
id, | ||
errors: deferredGroupedFieldSetResult.errors, | ||
}); | ||
this._pending.delete(deferredFragmentRecord); | ||
if ( | ||
!this._incrementalGraph.removeDeferredFragment(deferredFragmentRecord) | ||
) { | ||
// This can occur if multiple deferred grouped field sets error for a fragment. | ||
continue; | ||
} | ||
id !== undefined || (0, invariant_js_1.invariant)(false); | ||
context.completed.push({ | ||
id, | ||
errors: deferredGroupedFieldSetResult.errors, | ||
}); | ||
this._incrementalGraph.removeDeferredFragment(deferredFragmentRecord); | ||
} | ||
return; | ||
} | ||
for (const deferredFragmentRecord of deferredGroupedFieldSetResult.deferredFragmentRecords) { | ||
deferredFragmentRecord.reconcilableResults.push( | ||
deferredGroupedFieldSetResult, | ||
); | ||
this._incrementalGraph.addCompletedReconcilableDeferredGroupedFieldSet( | ||
deferredGroupedFieldSetResult, | ||
); | ||
const incrementalDataRecords = | ||
deferredGroupedFieldSetResult.incrementalDataRecords; | ||
if (incrementalDataRecords !== undefined) { | ||
this._incrementalGraph.addIncrementalDataRecords(incrementalDataRecords); | ||
} | ||
if (deferredGroupedFieldSetResult.incrementalDataRecords.length > 0) { | ||
this._addIncrementalDataRecords( | ||
deferredGroupedFieldSetResult.incrementalDataRecords, | ||
); | ||
} | ||
for (const deferredFragmentRecord of deferredGroupedFieldSetResult.deferredFragmentRecords) { | ||
for (const deferredFragmentRecord of deferredGroupedFieldSetResult | ||
.deferredGroupedFieldSetRecord.deferredFragmentRecords) { | ||
const id = deferredFragmentRecord.id; | ||
@@ -304,21 +198,16 @@ // TODO: add test case for this. | ||
} | ||
const fragmentResults = deferredFragmentRecord.reconcilableResults; | ||
if ( | ||
deferredFragmentRecord.deferredGroupedFieldSetRecords.length !== | ||
fragmentResults.length | ||
) { | ||
const reconcilableResults = | ||
this._incrementalGraph.completeDeferredFragment(deferredFragmentRecord); | ||
if (reconcilableResults === undefined) { | ||
continue; | ||
} | ||
for (const fragmentResult of fragmentResults) { | ||
if (fragmentResult.sent) { | ||
continue; | ||
} | ||
fragmentResult.sent = true; | ||
const incremental = context.incremental; | ||
for (const reconcilableResult of reconcilableResults) { | ||
const { bestId, subPath } = this._getBestIdAndSubPath( | ||
id, | ||
deferredFragmentRecord, | ||
fragmentResult, | ||
reconcilableResult, | ||
); | ||
const incrementalEntry = { | ||
...fragmentResult.result, | ||
...reconcilableResult.result, | ||
id: bestId, | ||
@@ -329,47 +218,34 @@ }; | ||
} | ||
this._incremental.push(incrementalEntry); | ||
incremental.push(incrementalEntry); | ||
} | ||
this._completed.push({ id }); | ||
this._pending.delete(deferredFragmentRecord); | ||
for (const child of deferredFragmentRecord.children) { | ||
this._newPending.add(child); | ||
for (const childResult of child.results) { | ||
if (!(0, isPromise_js_1.isPromise)(childResult)) { | ||
this._completedResultQueue.push(childResult); | ||
} | ||
} | ||
} | ||
context.completed.push({ id }); | ||
} | ||
this._pruneEmpty(); | ||
} | ||
_handleCompletedStreamItems(streamItemsResult) { | ||
_handleCompletedStreamItems(streamItemsResult, context) { | ||
const streamRecord = streamItemsResult.streamRecord; | ||
const id = streamRecord.id; | ||
// TODO: Consider adding invariant or non-null assertion, as this should never happen. Since the stream is converted into a linked list | ||
// for ordering purposes, if an entry errors, additional entries will not be processed. | ||
/* c8 ignore next 3 */ | ||
if (id === undefined) { | ||
return; | ||
} | ||
if (streamItemsResult.result === undefined) { | ||
this._completed.push({ id }); | ||
this._pending.delete(streamRecord); | ||
const cancellableStreams = this._context.cancellableStreams; | ||
if (cancellableStreams !== undefined) { | ||
cancellableStreams.delete(streamRecord); | ||
} | ||
} else if (streamItemsResult.result === null) { | ||
this._completed.push({ | ||
id !== undefined || (0, invariant_js_1.invariant)(false); | ||
if (streamItemsResult.errors !== undefined) { | ||
context.completed.push({ | ||
id, | ||
errors: streamItemsResult.errors, | ||
}); | ||
this._pending.delete(streamRecord); | ||
const cancellableStreams = this._context.cancellableStreams; | ||
if (cancellableStreams !== undefined) { | ||
cancellableStreams.delete(streamRecord); | ||
this._incrementalGraph.removeStream(streamRecord); | ||
if ((0, types_js_1.isCancellableStreamRecord)(streamRecord)) { | ||
this._context.cancellableStreams !== undefined || | ||
(0, invariant_js_1.invariant)(false); | ||
this._context.cancellableStreams.delete(streamRecord); | ||
streamRecord.earlyReturn().catch(() => { | ||
/* c8 ignore next 1 */ | ||
// ignore error | ||
}); | ||
} | ||
streamRecord.earlyReturn?.().catch(() => { | ||
/* c8 ignore next 1 */ | ||
// ignore error | ||
}); | ||
} else if (streamItemsResult.result === undefined) { | ||
context.completed.push({ id }); | ||
this._incrementalGraph.removeStream(streamRecord); | ||
if ((0, types_js_1.isCancellableStreamRecord)(streamRecord)) { | ||
this._context.cancellableStreams !== undefined || | ||
(0, invariant_js_1.invariant)(false); | ||
this._context.cancellableStreams.delete(streamRecord); | ||
} | ||
} else { | ||
@@ -380,8 +256,7 @@ const incrementalEntry = { | ||
}; | ||
this._incremental.push(incrementalEntry); | ||
if (streamItemsResult.incrementalDataRecords.length > 0) { | ||
this._addIncrementalDataRecords( | ||
context.incremental.push(incrementalEntry); | ||
if (streamItemsResult.incrementalDataRecords !== undefined) { | ||
this._incrementalGraph.addIncrementalDataRecords( | ||
streamItemsResult.incrementalDataRecords, | ||
); | ||
this._pruneEmpty(); | ||
} | ||
@@ -399,3 +274,4 @@ } | ||
let bestId = initialId; | ||
for (const deferredFragmentRecord of deferredGroupedFieldSetResult.deferredFragmentRecords) { | ||
for (const deferredFragmentRecord of deferredGroupedFieldSetResult | ||
.deferredGroupedFieldSetRecord.deferredFragmentRecords) { | ||
if (deferredFragmentRecord === initialDeferredFragmentRecord) { | ||
@@ -425,100 +301,21 @@ continue; | ||
} | ||
} | ||
function isDeferredFragmentRecord(subsequentResultRecord) { | ||
return subsequentResultRecord instanceof DeferredFragmentRecord; | ||
} | ||
function isDeferredGroupedFieldSetRecord(incrementalDataRecord) { | ||
return incrementalDataRecord instanceof DeferredGroupedFieldSetRecord; | ||
} | ||
function isDeferredGroupedFieldSetResult(subsequentResult) { | ||
return 'deferredFragmentRecords' in subsequentResult; | ||
} | ||
exports.isDeferredGroupedFieldSetResult = isDeferredGroupedFieldSetResult; | ||
function isNonReconcilableDeferredGroupedFieldSetResult( | ||
deferredGroupedFieldSetResult, | ||
) { | ||
return deferredGroupedFieldSetResult.result === null; | ||
} | ||
exports.isNonReconcilableDeferredGroupedFieldSetResult = | ||
isNonReconcilableDeferredGroupedFieldSetResult; | ||
/** @internal */ | ||
class DeferredGroupedFieldSetRecord { | ||
constructor(opts) { | ||
const { path, deferUsageSet, deferredFragmentRecords, executor } = opts; | ||
this.path = path; | ||
this.deferredFragmentRecords = deferredFragmentRecords; | ||
const incrementalContext = { | ||
deferUsageSet, | ||
path, | ||
}; | ||
for (const deferredFragmentRecord of deferredFragmentRecords) { | ||
deferredFragmentRecord.deferredGroupedFieldSetRecords.push(this); | ||
async _returnAsyncIterators() { | ||
await this._incrementalGraph.completedIncrementalData().return(); | ||
const cancellableStreams = this._context.cancellableStreams; | ||
if (cancellableStreams === undefined) { | ||
return; | ||
} | ||
this.result = deferredFragmentRecords.some( | ||
(deferredFragmentRecord) => deferredFragmentRecord.id !== undefined, | ||
) | ||
? executor(incrementalContext) | ||
: Promise.resolve().then(() => executor(incrementalContext)); | ||
} | ||
} | ||
exports.DeferredGroupedFieldSetRecord = DeferredGroupedFieldSetRecord; | ||
/** @internal */ | ||
class DeferredFragmentRecord { | ||
constructor(opts) { | ||
this.path = opts.path; | ||
this.label = opts.label; | ||
this.deferredGroupedFieldSetRecords = []; | ||
this.results = []; | ||
this.reconcilableResults = []; | ||
this.parent = opts.parent; | ||
this.children = new Set(); | ||
} | ||
} | ||
exports.DeferredFragmentRecord = DeferredFragmentRecord; | ||
/** @internal */ | ||
class StreamRecord { | ||
constructor(opts) { | ||
const { label, path, earlyReturn } = opts; | ||
this.label = label; | ||
this.path = path; | ||
this.earlyReturn = earlyReturn; | ||
} | ||
} | ||
exports.StreamRecord = StreamRecord; | ||
function isNonTerminatingStreamItemsResult(streamItemsResult) { | ||
return streamItemsResult.result != null; | ||
} | ||
exports.isNonTerminatingStreamItemsResult = isNonTerminatingStreamItemsResult; | ||
/** @internal */ | ||
class StreamItemsRecord { | ||
constructor(opts) { | ||
const { streamRecord, itemPath, executor } = opts; | ||
this.streamRecord = streamRecord; | ||
const incrementalContext = { | ||
deferUsageSet: undefined, | ||
path: itemPath, | ||
}; | ||
this._result = executor(incrementalContext); | ||
} | ||
getResult() { | ||
if ((0, isPromise_js_1.isPromise)(this._result)) { | ||
return this._result.then((resolved) => | ||
this._prependNextStreamItems(resolved), | ||
); | ||
const promises = []; | ||
for (const streamRecord of cancellableStreams) { | ||
if (streamRecord.earlyReturn !== undefined) { | ||
promises.push(streamRecord.earlyReturn()); | ||
} | ||
} | ||
return this._prependNextStreamItems(this._result); | ||
await Promise.all(promises); | ||
} | ||
_prependNextStreamItems(result) { | ||
return isNonTerminatingStreamItemsResult(result) && | ||
this.nextStreamItems !== undefined | ||
? { | ||
...result, | ||
incrementalDataRecords: [ | ||
this.nextStreamItems, | ||
...result.incrementalDataRecords, | ||
], | ||
} | ||
: result; | ||
async _returnAsyncIteratorsIgnoringErrors() { | ||
await this._returnAsyncIterators().catch(() => { | ||
// Ignore errors | ||
}); | ||
} | ||
} | ||
exports.StreamItemsRecord = StreamItemsRecord; |
@@ -26,3 +26,3 @@ export { pathToArray as responsePathAsArray } from '../jsutils/Path.js'; | ||
FormattedIncrementalResult, | ||
} from './IncrementalPublisher.js'; | ||
} from './types.js'; | ||
export { | ||
@@ -29,0 +29,0 @@ getArgumentValues, |
@@ -8,3 +8,3 @@ import type { Maybe } from './jsutils/Maybe.js'; | ||
import type { GraphQLSchema } from './type/schema.js'; | ||
import type { ExecutionResult } from './execution/IncrementalPublisher.js'; | ||
import type { ExecutionResult } from './execution/types.js'; | ||
/** | ||
@@ -11,0 +11,0 @@ * This is the primary entry point function for fulfilling GraphQL operations |
{ | ||
"name": "graphql", | ||
"version": "17.0.0-alpha.3.canary.pr.4035.3404abc2382e32f6a3ab26f08a9ed54554678fa9", | ||
"version": "17.0.0-alpha.3.canary.pr.4097.291dd92c9059c6bcc88ff1fa21058a8ac519cf83", | ||
"description": "A Query Language and Runtime which can target any service.", | ||
@@ -35,7 +35,7 @@ "license": "MIT", | ||
"publishConfig": { | ||
"tag": "canary-pr-4035" | ||
"tag": "canary-pr-4097" | ||
}, | ||
"main": "index", | ||
"module": "index.mjs", | ||
"deprecated": "You are using canary version build from https://github.com/graphql/graphql-js/pull/4035, no gurantees provided so please use your own discretion." | ||
"deprecated": "You are using canary version build from https://github.com/graphql/graphql-js/pull/4097, no gurantees provided so please use your own discretion." | ||
} |
@@ -64,3 +64,3 @@ 'use strict'; | ||
new GraphQLError_js_1.GraphQLError( | ||
'Stream directive not supported on subscription operations. Disable `@defer` by setting the `if` argument to `false`.', | ||
'Stream directive not supported on subscription operations. Disable `@stream` by setting the `if` argument to `false`.', | ||
{ nodes: node }, | ||
@@ -67,0 +67,0 @@ ), |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
1450316
421
44909