Skip to content

Commit cd4a139

Browse files
committed
Support hasNext on payloads
1 parent 34d36ab commit cd4a139

File tree

3 files changed

+67
-3
lines changed

3 files changed

+67
-3
lines changed

packages/relay-runtime/network/RelayNetworkTypes.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export type GraphQLResponseWithData = {|
5151
+extensions?: PayloadExtensions,
5252
+label?: string,
5353
+path?: Array<string | number>,
54+
+hasNext?: boolean,
5455
|};
5556

5657
export type GraphQLResponseWithoutData = {|
@@ -59,6 +60,7 @@ export type GraphQLResponseWithoutData = {|
5960
+extensions?: PayloadExtensions,
6061
+label?: string,
6162
+path?: Array<string | number>,
63+
+hasNext?: boolean,
6264
|};
6365

6466
export type GraphQLResponseWithExtensionsOnly = {|
@@ -72,6 +74,7 @@ export type GraphQLResponseWithExtensionsOnly = {|
7274
// does not necessarily indicate that there was an error.
7375
+data: null,
7476
+extensions: PayloadExtensions,
77+
+hasNext?: boolean,
7578
|};
7679

7780
export type GraphQLSingularResponse =

packages/relay-runtime/query/__tests__/fetchQueryInternal-test.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,30 @@ describe('getObservableForActiveRequest', () => {
964964
expect(events).toEqual(['next']);
965965
});
966966

967+
it('calls next asynchronously with subsequent non-final payloads (OSS)', () => {
968+
fetchQuery(environment, query).subscribe({});
969+
const observable = getObservableForActiveRequest(
970+
environment,
971+
query.request,
972+
);
973+
expect(observable).not.toEqual(null);
974+
if (!observable) {
975+
return;
976+
}
977+
978+
response = {
979+
...response,
980+
extensions: {},
981+
hasNext: true,
982+
};
983+
984+
observable.subscribe(observer);
985+
expect(events).toEqual([]);
986+
987+
environment.mock.nextValue(gqlQuery, response);
988+
expect(events).toEqual(['next']);
989+
});
990+
967991
it('calls complete asynchronously with subsequent final payload', () => {
968992
fetchQuery(environment, query).subscribe({});
969993
const observable = getObservableForActiveRequest(
@@ -982,6 +1006,30 @@ describe('getObservableForActiveRequest', () => {
9821006
expect(events).toEqual(['complete']);
9831007
});
9841008

1009+
it('calls complete asynchronously with subsequent final payload (OSS)', () => {
1010+
fetchQuery(environment, query).subscribe({});
1011+
const observable = getObservableForActiveRequest(
1012+
environment,
1013+
query.request,
1014+
);
1015+
expect(observable).not.toEqual(null);
1016+
if (!observable) {
1017+
return;
1018+
}
1019+
1020+
response = {
1021+
...response,
1022+
extensions: {},
1023+
hasNext: false,
1024+
};
1025+
1026+
observable.subscribe(observer);
1027+
expect(events).toEqual([]);
1028+
1029+
environment.mock.nextValue(gqlQuery, response);
1030+
expect(events).toEqual(['complete']);
1031+
});
1032+
9851033
describe('when loading @module', () => {
9861034
let operationLoader;
9871035
let resolveModule;

packages/relay-runtime/store/RelayModernQueryExecutor.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ class Executor {
400400
if (responsesWithData.length === 0) {
401401
// no results with data, nothing to process
402402
// this can occur with extensions-only payloads
403-
const isFinal = responses.some(x => x.extensions?.is_final === true);
403+
const isFinal = responses.some(x => responseIsFinal(x));
404404
if (isFinal) {
405405
this._state = 'loading_final';
406406
this._updateActiveState();
@@ -1019,7 +1019,7 @@ class Executor {
10191019
incrementalPlaceholders: null,
10201020
moduleImportPayloads: null,
10211021
source: RelayRecordSource.create(),
1022-
isFinal: response.extensions?.is_final === true,
1022+
isFinal: responseIsFinal(response),
10231023
};
10241024
this._publishQueue.commitPayload(
10251025
this._operation,
@@ -1296,7 +1296,7 @@ function normalizeResponse(
12961296
return {
12971297
...relayPayload,
12981298
errors,
1299-
isFinal: response.extensions?.is_final === true,
1299+
isFinal: responseIsFinal(response),
13001300
};
13011301
}
13021302

@@ -1318,4 +1318,17 @@ function validateOptimisticResponsePayload(
13181318
}
13191319
}
13201320

1321+
/**
1322+
* Check for both FB specific (extensions?.is_final)
1323+
* and spec-complaint (hasNext) properties.
1324+
*/
1325+
function responseIsFinal(response: GraphQLSingularResponse): boolean {
1326+
if (response.extensions?.is_final === true) {
1327+
return true;
1328+
} else if (response.hasNext === false) {
1329+
return true;
1330+
}
1331+
return false;
1332+
}
1333+
13211334
module.exports = {execute};

0 commit comments

Comments
 (0)