Skip to content

Commit 2e2b1b2

Browse files
committed
use undefined for empty
1 parent e55c1a6 commit 2e2b1b2

File tree

2 files changed

+62
-45
lines changed

2 files changed

+62
-45
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: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,8 @@ export interface ExecutionContext {
141141
fieldResolver: GraphQLFieldResolver<any, any>;
142142
typeResolver: GraphQLTypeResolver<any, any>;
143143
subscribeFieldResolver: GraphQLFieldResolver<any, any>;
144-
errors: Array<GraphQLError>;
145-
cancellableStreams: Set<StreamRecord>;
144+
errors: Array<GraphQLError> | undefined;
145+
cancellableStreams: Set<StreamRecord> | undefined;
146146
}
147147

148148
export interface ExecutionArgs {
@@ -163,7 +163,7 @@ export interface StreamUsage {
163163
fieldGroup: FieldGroup;
164164
}
165165

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

168168
const UNEXPECTED_EXPERIMENTAL_DIRECTIVES =
169169
'The provided schema unexpectedly contains experimental directives (@defer or @stream). These directives may only be utilized if experimental execution features are explicitly enabled.';
@@ -329,20 +329,20 @@ function executeOperation(
329329
}
330330

331331
function withError(
332-
errors: Array<GraphQLError>,
332+
errors: Array<GraphQLError> | undefined,
333333
error: GraphQLError,
334334
): ReadonlyArray<GraphQLError> {
335-
return errors.length === 0 ? [error] : [...errors, error];
335+
return errors === undefined ? [error] : [...errors, error];
336336
}
337337

338338
function buildDataResponse(
339339
exeContext: ExecutionContext,
340340
data: ObjMap<unknown>,
341-
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord>,
341+
incrementalDataRecords: ReadonlyArray<IncrementalDataRecord> | undefined,
342342
): ExecutionResult | ExperimentalIncrementalExecutionResults {
343343
const { errors } = exeContext;
344-
if (incrementalDataRecords.length === 0) {
345-
return errors.length > 0 ? { errors, data } : { data };
344+
if (incrementalDataRecords === undefined) {
345+
return errors !== undefined ? { errors, data } : { data };
346346
}
347347

348348
return buildIncrementalResponse(
@@ -454,8 +454,8 @@ export function buildExecutionContext(
454454
fieldResolver: fieldResolver ?? defaultFieldResolver,
455455
typeResolver: typeResolver ?? defaultTypeResolver,
456456
subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver,
457-
errors: [],
458-
cancellableStreams: new Set(),
457+
errors: undefined,
458+
cancellableStreams: undefined,
459459
};
460460
}
461461

@@ -466,7 +466,7 @@ function buildPerEventExecutionContext(
466466
return {
467467
...exeContext,
468468
rootValue: payload,
469-
errors: [],
469+
errors: undefined,
470470
};
471471
}
472472

@@ -552,16 +552,16 @@ function executeFieldsSerially(
552552
appendNewIncrementalDataRecords(acc, result[1]);
553553
return acc;
554554
},
555-
[Object.create(null), []] as GraphQLResult<ObjMap<unknown>>,
555+
[Object.create(null), undefined] as GraphQLResult<ObjMap<unknown>>,
556556
);
557557
}
558558

559559
function appendNewIncrementalDataRecords(
560560
acc: GraphQLResult<unknown>,
561-
newRecords: ReadonlyArray<IncrementalDataRecord>,
561+
newRecords: ReadonlyArray<IncrementalDataRecord> | undefined,
562562
): void {
563-
if (newRecords.length > 0) {
564-
acc[1] = acc[1].length === 0 ? newRecords : [...acc[1], ...newRecords];
563+
if (newRecords !== undefined) {
564+
acc[1] = acc[1] === undefined ? newRecords : [...acc[1], ...newRecords];
565565
}
566566
}
567567

@@ -721,7 +721,7 @@ function executeField(
721721
path,
722722
incrementalContext,
723723
);
724-
return [null, []];
724+
return [null, undefined];
725725
});
726726
}
727727
return completed;
@@ -734,7 +734,7 @@ function executeField(
734734
path,
735735
incrementalContext,
736736
);
737-
return [null, []];
737+
return [null, undefined];
738738
}
739739
}
740740

@@ -783,7 +783,13 @@ function handleFieldError(
783783

784784
// Otherwise, error protection is applied, logging the error and resolving
785785
// a null value for this field if one is encountered.
786-
(incrementalContext ?? exeContext).errors.push(error);
786+
const context = incrementalContext ?? exeContext;
787+
let errors = context.errors;
788+
if (errors === undefined) {
789+
errors = [];
790+
context.errors = errors;
791+
}
792+
errors.push(error);
787793
}
788794

789795
/**
@@ -845,7 +851,7 @@ function completeValue(
845851

846852
// If result value is null or undefined then return null.
847853
if (result == null) {
848-
return [null, []];
854+
return [null, undefined];
849855
}
850856

851857
// If field type is List, complete each item in the list with the inner type
@@ -865,7 +871,7 @@ function completeValue(
865871
// If field type is a leaf type, Scalar or Enum, serialize to a valid value,
866872
// returning null if serialization is not possible.
867873
if (isLeafType(returnType)) {
868-
return [completeLeafValue(returnType, result), []];
874+
return [completeLeafValue(returnType, result), undefined];
869875
}
870876

871877
// If field type is an abstract type, Interface or Union, determine the
@@ -940,7 +946,7 @@ async function completePromisedValue(
940946
path,
941947
incrementalContext,
942948
);
943-
return [null, []];
949+
return [null, undefined];
944950
}
945951
}
946952

@@ -1030,7 +1036,7 @@ async function completeAsyncIteratorValue(
10301036
): Promise<GraphQLResult<ReadonlyArray<unknown>>> {
10311037
let containsPromise = false;
10321038
const completedResults: Array<unknown> = [];
1033-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1039+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
10341040
let index = 0;
10351041
// eslint-disable-next-line no-constant-condition
10361042
while (true) {
@@ -1107,7 +1113,7 @@ async function completeAsyncIteratorValueWithPossibleStream(
11071113
): Promise<GraphQLResult<ReadonlyArray<unknown>>> {
11081114
let containsPromise = false;
11091115
const completedResults: Array<unknown> = [];
1110-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1116+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
11111117
let index = 0;
11121118
const initialCount = streamUsage.initialCount;
11131119
// eslint-disable-next-line no-constant-condition
@@ -1119,6 +1125,9 @@ async function completeAsyncIteratorValueWithPossibleStream(
11191125
earlyReturn: asyncIterator.return?.bind(asyncIterator),
11201126
});
11211127

1128+
if (exeContext.cancellableStreams === undefined) {
1129+
exeContext.cancellableStreams = new Set();
1130+
}
11221131
exeContext.cancellableStreams.add(streamRecord);
11231132

11241133
const firstStreamItems = firstAsyncStreamItems(
@@ -1300,7 +1309,7 @@ function completeIterableValue(
13001309
// where the list contains no Promises by avoiding creating another Promise.
13011310
let containsPromise = false;
13021311
const completedResults: Array<unknown> = [];
1303-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1312+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
13041313
let index = 0;
13051314
for (const item of items) {
13061315
// No need to modify the info object containing the path,
@@ -1361,7 +1370,7 @@ function completeIterableValueWithPossibleStream(
13611370
// where the list contains no Promises by avoiding creating another Promise.
13621371
let containsPromise = false;
13631372
const completedResults: Array<unknown> = [];
1364-
const acc: GraphQLResult<Array<unknown>> = [completedResults, []];
1373+
const acc: GraphQLResult<Array<unknown>> = [completedResults, undefined];
13651374
let index = 0;
13661375
const initialCount = streamUsage.initialCount;
13671376
const iterator = items[Symbol.iterator]();
@@ -2332,7 +2341,7 @@ function buildDeferredGroupedFieldSetResult(
23322341
deferredFragmentRecords,
23332342
path: pathToArray(path),
23342343
result:
2335-
errors.length === 0 ? { data: result[0] } : { data: result[0], errors },
2344+
errors === undefined ? { data: result[0] } : { data: result[0], errors },
23362345
incrementalDataRecords: result[1],
23372346
};
23382347
}
@@ -2548,7 +2557,7 @@ function completeStreamItems(
25482557
itemPath,
25492558
incrementalContext,
25502559
);
2551-
return [null, []] as GraphQLResult<unknown>;
2560+
return [null, undefined] as GraphQLResult<unknown>;
25522561
})
25532562
.then(
25542563
(resolvedItem) =>
@@ -2587,7 +2596,7 @@ function completeStreamItems(
25872596
itemPath,
25882597
incrementalContext,
25892598
);
2590-
result = [null, []];
2599+
result = [null, undefined];
25912600
}
25922601
} catch (error) {
25932602
return {
@@ -2608,7 +2617,7 @@ function completeStreamItems(
26082617
itemPath,
26092618
incrementalContext,
26102619
);
2611-
return [null, []] as GraphQLResult<unknown>;
2620+
return [null, undefined] as GraphQLResult<unknown>;
26122621
})
26132622
.then(
26142623
(resolvedItem) =>
@@ -2637,7 +2646,7 @@ function buildStreamItemsResult(
26372646
return {
26382647
streamRecord,
26392648
result:
2640-
errors.length === 0
2649+
errors === undefined
26412650
? { items: [result[0]] }
26422651
: {
26432652
items: [result[0]],

0 commit comments

Comments
 (0)