Skip to content

Commit 0c5c2fb

Browse files
committed
support hasNext
1 parent b58a501 commit 0c5c2fb

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

packages/relay-runtime/network/RelayNetworkTypes.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import type {RequestParameters} from '../util/RelayConcreteNode';
1616
import type {CacheConfig, Variables} from '../util/RelayRuntimeTypes';
1717
import type RelayObservable, {ObservableFromValue} from './RelayObservable';
18+
import {boolean} from 'yargs';
1819

1920
/**
2021
* An interface for fetching the data for one or more (possibly interdependent)
@@ -51,6 +52,7 @@ export type GraphQLResponseWithData = {|
5152
+extensions?: PayloadExtensions,
5253
+label?: string,
5354
+path?: Array<string | number>,
55+
+hasNext?: boolean,
5456
|};
5557

5658
export type GraphQLResponseWithoutData = {|
@@ -59,6 +61,7 @@ export type GraphQLResponseWithoutData = {|
5961
+extensions?: PayloadExtensions,
6062
+label?: string,
6163
+path?: Array<string | number>,
64+
+hasNext?: boolean,
6265
|};
6366

6467
export type GraphQLResponseWithExtensionsOnly = {|
@@ -72,6 +75,7 @@ export type GraphQLResponseWithExtensionsOnly = {|
7275
// does not necessarily indicate that there was an error.
7376
+data: null,
7477
+extensions: PayloadExtensions,
78+
+hasNext?: boolean,
7579
|};
7680

7781
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)