Skip to content

Commit a043386

Browse files
committed
use undefined for empty
1 parent 59e1f92 commit a043386

File tree

2 files changed

+63
-46
lines changed

2 files changed

+63
-46
lines changed

src/execution/IncrementalPublisher.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export interface FormattedCompletedResult {
174174
export function buildIncrementalResponse(
175175
context: IncrementalPublisherContext,
176176
result: ObjMap<unknown>,
177-
errors: ReadonlyArray<GraphQLError>,
177+
errors: ReadonlyArray<GraphQLError> | undefined,
178178
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>,
179179
): ExperimentalIncrementalExecutionResults {
180180
const incrementalPublisher = new IncrementalPublisher(context);
@@ -186,7 +186,7 @@ export function buildIncrementalResponse(
186186
}
187187

188188
interface IncrementalPublisherContext {
189-
cancellableStreams: Set<StreamRecord>;
189+
cancellableStreams?: Set<StreamRecord> | undefined;
190190
}
191191

192192
/**
@@ -220,7 +220,7 @@ class IncrementalPublisher {
220220

221221
buildResponse(
222222
data: ObjMap<unknown>,
223-
errors: ReadonlyArray<GraphQLError>,
223+
errors: ReadonlyArray<GraphQLError> | undefined,
224224
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>,
225225
): ExperimentalIncrementalExecutionResults {
226226
this._addIncrementalDataRecords(incrementalDataRecords);
@@ -229,7 +229,7 @@ class IncrementalPublisher {
229229
const pending = this._pendingSourcesToResults();
230230

231231
const initialResult: InitialIncrementalExecutionResult =
232-
errors.length === 0
232+
errors === undefined
233233
? { data, pending, hasNext: true }
234234
: { errors, data, pending, hasNext: true };
235235

@@ -441,8 +441,12 @@ class IncrementalPublisher {
441441
};
442442

443443
const returnStreamIterators = async (): Promise<void> => {
444+
const cancellableStreams = this._context.cancellableStreams;
445+
if (cancellableStreams === undefined) {
446+
return;
447+
}
444448
const promises: Array<Promise<unknown>> = [];
445-
for (const streamRecord of this._context.cancellableStreams) {
449+
for (const streamRecord of cancellableStreams) {
446450
if (streamRecord.earlyReturn !== undefined) {
447451
promises.push(streamRecord.earlyReturn());
448452
}
@@ -516,7 +520,7 @@ class IncrementalPublisher {
516520
);
517521
}
518522

519-
if (deferredGroupedFieldSetResult.incrementalDataRecords.length > 0) {
523+
if (deferredGroupedFieldSetResult.incrementalDataRecords !== undefined) {
520524
this._addIncrementalDataRecords(
521525
deferredGroupedFieldSetResult.incrementalDataRecords,
522526
);
@@ -586,14 +590,20 @@ class IncrementalPublisher {
586590
if (streamItemsResult.result === undefined) {
587591
this._completed.push({ id });
588592
this._pending.delete(streamRecord);
589-
this._context.cancellableStreams.delete(streamRecord);
593+
const cancellableStreams = this._context.cancellableStreams;
594+
if (cancellableStreams !== undefined) {
595+
cancellableStreams.delete(streamRecord);
596+
}
590597
} else if (streamItemsResult.result === null) {
591598
this._completed.push({
592599
id,
593600
errors: streamItemsResult.errors,
594601
});
595602
this._pending.delete(streamRecord);
596-
this._context.cancellableStreams.delete(streamRecord);
603+
const cancellableStreams = this._context.cancellableStreams;
604+
if (cancellableStreams !== undefined) {
605+
cancellableStreams.delete(streamRecord);
606+
}
597607
streamRecord.earlyReturn?.().catch(() => {
598608
/* c8 ignore next 1 */
599609
// ignore error
@@ -606,7 +616,7 @@ class IncrementalPublisher {
606616

607617
this._incremental.push(incrementalEntry);
608618

609-
if (streamItemsResult.incrementalDataRecords.length > 0) {
619+
if (streamItemsResult.incrementalDataRecords !== undefined) {
610620
this._addIncrementalDataRecords(
611621
streamItemsResult.incrementalDataRecords,
612622
);
@@ -663,7 +673,7 @@ function isDeferredGroupedFieldSetRecord(
663673
export interface IncrementalContext {
664674
deferUsageSet: DeferUsageSet | undefined;
665675
path: Path | undefined;
666-
errors: Array<GraphQLError>;
676+
errors?: Array<GraphQLError> | undefined;
667677
}
668678

669679
export type DeferredGroupedFieldSetResult =
@@ -680,7 +690,7 @@ interface ReconcilableDeferredGroupedFieldSetResult {
680690
deferredFragmentRecords: ReadonlyArray<DeferredFragmentRecord>;
681691
path: Array<string | number>;
682692
result: BareDeferredGroupedFieldSetResult;
683-
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>;
693+
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord> | undefined;
684694
sent?: true | undefined;
685695
}
686696

@@ -718,7 +728,6 @@ export class DeferredGroupedFieldSetRecord {
718728
const incrementalContext: IncrementalContext = {
719729
deferUsageSet,
720730
path,
721-
errors: [],
722731
};
723732

724733
for (const deferredFragmentRecord of deferredFragmentRecords) {
@@ -786,7 +795,7 @@ interface NonReconcilableStreamItemsResult {
786795
interface NonTerminatingStreamItemsResult {
787796
streamRecord: StreamRecord;
788797
result: BareStreamItemsResult;
789-
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>;
798+
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord> | undefined;
790799
}
791800

792801
interface TerminatingStreamItemsResult {
@@ -826,7 +835,6 @@ export class StreamItemsRecord {
826835
const incrementalContext: IncrementalContext = {
827836
deferUsageSet: undefined,
828837
path: itemPath,
829-
errors: [],
830838
};
831839

832840
this._result = executor(incrementalContext);
@@ -850,7 +858,7 @@ export class StreamItemsRecord {
850858
? {
851859
...result,
852860
incrementalDataRecords:
853-
result.incrementalDataRecords.length === 0
861+
result.incrementalDataRecords === undefined
854862
? [this.nextStreamItems]
855863
: [this.nextStreamItems, ...result.incrementalDataRecords],
856864
}

src/execution/execute.ts

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -140,8 +140,8 @@ export interface ExecutionContext {
140140
fieldResolver: GraphQLFieldResolver<any, any>;
141141
typeResolver: GraphQLTypeResolver<any, any>;
142142
subscribeFieldResolver: GraphQLFieldResolver<any, any>;
143-
errors: Array<GraphQLError>;
144-
cancellableStreams: Set<StreamRecord>;
143+
errors: Array<GraphQLError> | undefined;
144+
cancellableStreams: Set<StreamRecord> | undefined;
145145
}
146146

147147
export interface ExecutionArgs {
@@ -162,7 +162,7 @@ export interface StreamUsage {
162162
fieldGroup: FieldGroup;
163163
}
164164

165-
type GraphQLResult<T> = [T, ReadonlyArray<IncrementalDataRecord>];
165+
type GraphQLResult<T> = [T, ReadonlyArray<IncrementalDataRecord> | undefined];
166166

167167
const UNEXPECTED_EXPERIMENTAL_DIRECTIVES =
168168
'The provided schema unexpectedly contains experimental directives (@defer or @stream). These directives may only be utilized if experimental execution features are explicitly enabled.';
@@ -324,20 +324,20 @@ function executeImpl(
324324
}
325325

326326
function withError(
327-
errors: Array<GraphQLError>,
327+
errors: Array<GraphQLError> | undefined,
328328
error: GraphQLError,
329329
): ReadonlyArray<GraphQLError> {
330-
return errors.length === 0 ? [error] : [...errors, error];
330+
return errors === undefined ? [error] : [...errors, error];
331331
}
332332

333333
function buildDataResponse(
334334
exeContext: ExecutionContext,
335335
data: ObjMap<unknown>,
336-
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>,
336+
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord> | undefined,
337337
): ExecutionResult | ExperimentalIncrementalExecutionResults {
338338
const { errors } = exeContext;
339-
if (incrementalDataRecords.length === 0) {
340-
return errors.length > 0 ? { errors, data } : { data };
339+
if (incrementalDataRecords === undefined) {
340+
return errors !== undefined ? { errors, data } : { data };
341341
}
342342

343343
return buildIncrementalResponse(
@@ -449,8 +449,8 @@ export function buildExecutionContext(
449449
fieldResolver: fieldResolver ?? defaultFieldResolver,
450450
typeResolver: typeResolver ?? defaultTypeResolver,
451451
subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver,
452-
errors: [],
453-
cancellableStreams: new Set(),
452+
errors: undefined,
453+
cancellableStreams: undefined,
454454
};
455455
}
456456

@@ -461,7 +461,7 @@ function buildPerEventExecutionContext(
461461
return {
462462
...exeContext,
463463
rootValue: payload,
464-
errors: [],
464+
errors: undefined,
465465
};
466466
}
467467

@@ -547,16 +547,16 @@ function executeFieldsSerially(
547547
appendNewIncrementalDataRecords(acc, result[1]);
548548
return acc;
549549
},
550-
[Object.create(null), []] as GraphQLResult<ObjMap<unknown>>,
550+
[Object.create(null), undefined] as GraphQLResult<ObjMap<unknown>>,
551551
);
552552
}
553553

554554
function appendNewIncrementalDataRecords(
555555
acc: GraphQLResult<unknown>,
556-
newRecords: ReadonlyArray<IncrementalDataRecord>,
556+
newRecords: ReadonlyArray<IncrementalDataRecord> | undefined,
557557
): void {
558-
if (newRecords.length > 0) {
559-
acc[1] = acc[1].length === 0 ? newRecords : [...acc[1], ...newRecords];
558+
if (newRecords !== undefined) {
559+
acc[1] = acc[1] === undefined ? newRecords : [...acc[1], ...newRecords];
560560
}
561561
}
562562

@@ -573,7 +573,7 @@ function executeFields(
573573
incrementalContext: IncrementalContext | undefined,
574574
deferMap: ReadonlyMap<DeferUsage, DeferredFragmentRecord> | undefined,
575575
): PromiseOrValue<GraphQLResult<ObjMap<unknown>>> {
576-
const acc: GraphQLResult<ObjMap<unknown>> = [Object.create(null), []];
576+
const acc: GraphQLResult<ObjMap<unknown>> = [Object.create(null), undefined];
577577
const promises: Array<Promise<void>> = [];
578578

579579
try {
@@ -715,7 +715,7 @@ function executeField(
715715
path,
716716
incrementalContext,
717717
);
718-
return [null, []];
718+
return [null, undefined];
719719
});
720720
}
721721
return completed;
@@ -728,7 +728,7 @@ function executeField(
728728
path,
729729
incrementalContext,
730730
);
731-
return [null, []];
731+
return [null, undefined];
732732
}
733733
}
734734

@@ -777,7 +777,13 @@ function handleFieldError(
777777

778778
// Otherwise, error protection is applied, logging the error and resolving
779779
// a null value for this field if one is encountered.
780-
(incrementalContext ?? exeContext).errors.push(error);
780+
const context = incrementalContext ?? exeContext;
781+
let errors = context.errors;
782+
if (errors === undefined) {
783+
errors = [];
784+
context.errors = errors;
785+
}
786+
errors.push(error);
781787
}
782788

783789
/**
@@ -839,7 +845,7 @@ function completeValue(
839845

840846
// If result value is null or undefined then return null.
841847
if (result == null) {
842-
return [null, []];
848+
return [null, undefined];
843849
}
844850

845851
// If field type is List, complete each item in the list with the inner type
@@ -859,7 +865,7 @@ function completeValue(
859865
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
860866
// returning null if serialization is not possible.
861867
if (isLeafType(returnType)) {
862-
return [completeLeafValue(returnType, result), []];
868+
return [completeLeafValue(returnType, result), undefined];
863869
}
864870

865871
// If field type is an abstract type, Interface or Union, determine the
@@ -934,7 +940,7 @@ async function completePromisedValue(
934940
path,
935941
incrementalContext,
936942
);
937-
return [null, []];
943+
return [null, undefined];
938944
}
939945
}
940946

@@ -1024,7 +1030,7 @@ async function completeAsyncIteratorValue(
10241030
): Promise<GraphQLResult<ReadonlyArray<unknown>>> {
10251031
let containsPromise = false;
10261032
const completedResults: Array<unknown> = [];
1027-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1033+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
10281034
let index = 0;
10291035
// eslint-disable-next-line no-constant-condition
10301036
while (true) {
@@ -1101,7 +1107,7 @@ async function completeAsyncIteratorValueWithPossibleStream(
11011107
): Promise<GraphQLResult<ReadonlyArray<unknown>>> {
11021108
let containsPromise = false;
11031109
const completedResults: Array<unknown> = [];
1104-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1110+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
11051111
let index = 0;
11061112
const initialCount = streamUsage.initialCount;
11071113
// eslint-disable-next-line no-constant-condition
@@ -1113,6 +1119,9 @@ async function completeAsyncIteratorValueWithPossibleStream(
11131119
earlyReturn: asyncIterator.return?.bind(asyncIterator),
11141120
});
11151121

1122+
if (exeContext.cancellableStreams === undefined) {
1123+
exeContext.cancellableStreams = new Set();
1124+
}
11161125
exeContext.cancellableStreams.add(streamRecord);
11171126

11181127
const firstStreamItems = firstAsyncStreamItems(
@@ -1294,7 +1303,7 @@ function completeIterableValue(
12941303
// where the list contains no Promises by avoiding creating another Promise.
12951304
let containsPromise = false;
12961305
const completedResults: Array<unknown> = [];
1297-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1306+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
12981307
let index = 0;
12991308
for (const item of items) {
13001309
// No need to modify the info object containing the path,
@@ -1355,7 +1364,7 @@ function completeIterableValueWithPossibleStream(
13551364
// where the list contains no Promises by avoiding creating another Promise.
13561365
let containsPromise = false;
13571366
const completedResults: Array<unknown> = [];
1358-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1367+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
13591368
let index = 0;
13601369
const initialCount = streamUsage.initialCount;
13611370
const iterator = items[Symbol.iterator]();
@@ -2326,7 +2335,7 @@ function buildDeferredGroupedFieldSetResult(
23262335
deferredFragmentRecords,
23272336
path: pathToArray(path),
23282337
result:
2329-
errors.length === 0 ? { data: result[0] } : { data: result[0], errors },
2338+
errors === undefined ? { data: result[0] } : { data: result[0], errors },
23302339
incrementalDataRecords: result[1],
23312340
};
23322341
}
@@ -2542,7 +2551,7 @@ function completeStreamItems(
25422551
itemPath,
25432552
incrementalContext,
25442553
);
2545-
return [null, []] as GraphQLResult<unknown>;
2554+
return [null, undefined] as GraphQLResult<unknown>;
25462555
})
25472556
.then(
25482557
(resolvedItem) =>
@@ -2581,7 +2590,7 @@ function completeStreamItems(
25812590
itemPath,
25822591
incrementalContext,
25832592
);
2584-
result = [null, []];
2593+
result = [null, undefined];
25852594
}
25862595
} catch (error) {
25872596
return {
@@ -2602,7 +2611,7 @@ function completeStreamItems(
26022611
itemPath,
26032612
incrementalContext,
26042613
);
2605-
return [null, []] as GraphQLResult<unknown>;
2614+
return [null, undefined] as GraphQLResult<unknown>;
26062615
})
26072616
.then(
26082617
(resolvedItem) =>
@@ -2631,7 +2640,7 @@ function buildStreamItemsResult(
26312640
return {
26322641
streamRecord,
26332642
result:
2634-
errors.length === 0
2643+
errors === undefined
26352644
? { items: [result[0]] }
26362645
: {
26372646
items: [result[0]],

0 commit comments

Comments
 (0)