Skip to content

Commit 8c11555

Browse files
committed
Merge branch 'cache-config' into master
2 parents 67f704c + 7e93e27 commit 8c11555

5 files changed

Lines changed: 523 additions & 41 deletions

File tree

package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,8 @@
2424
"testonly": "jest",
2525
"typecheck": "tsc --noEmit && tsc --noEmit -p test"
2626
},
27-
"husky": {
28-
"hooks": {
29-
"pre-commit": "lint-staged"
30-
}
27+
"gitHooks": {
28+
"pre-commit": "lint-staged"
3129
},
3230
"lint-staged": {
3331
"*": "yarn 4c lint --fix"
@@ -77,7 +75,7 @@
7775
"eslint-plugin-react-hooks": "^4.2.0",
7876
"fetch-mock": "^9.11.0",
7977
"fetch-mock-jest": "^1.5.1",
80-
"husky": "^5.2.0",
78+
"hookem": "^2.0.1",
8179
"jest": "^26.6.3",
8280
"lint-staged": "^10.5.4",
8381
"prettier": "^2.2.1",

src/NetworkLayer.ts

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ExecuteFunction, Network } from 'relay-runtime';
22

3-
import createFetch from './createFetch';
3+
import createFetch, { BatchConfig } from './createFetch';
44
import type { SubscriptionClientOptions } from './createSubscribe';
55
import createSubscribe from './createSubscribe';
66

@@ -42,18 +42,7 @@ export interface NetworkLayerOptions {
4242
*
4343
* **Requires a Graphql server that understands batching"
4444
*/
45-
batch?:
46-
| boolean
47-
| {
48-
enabled: boolean;
49-
50-
/**
51-
* The amount of time to wait before a batch is closed and sent to the server.
52-
*
53-
* The default is `0ms`, or about the next tick of the event loop.
54-
*/
55-
timeoutMs?: number;
56-
};
45+
batch?: boolean | BatchConfig;
5746

5847
/** The authorization configuration or token for a convenient shorthand */
5948
authorization?:

src/createFetch.ts

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,16 @@ import {
1010
} from 'relay-runtime';
1111
import { Sink } from 'relay-runtime/lib/network/RelayObservable';
1212

13+
export interface BatchConfig {
14+
enabled: boolean;
15+
timeoutMs?: number;
16+
shouldRequestBeBatched?: (
17+
operation: RequestParameters,
18+
variables: Variables,
19+
cacheConfig?: CacheConfig,
20+
uploadables?: UploadableMap,
21+
) => boolean;
22+
}
1323
export interface FetchOptions {
1424
url?: string;
1525
init?: RequestInit | (() => RequestInit);
@@ -22,12 +32,7 @@ export interface FetchOptions {
2232
headerName?: string;
2333
scheme?: string;
2434
};
25-
batch?:
26-
| boolean
27-
| {
28-
enabled: boolean;
29-
timeoutMs?: number;
30-
};
35+
batch?: boolean | BatchConfig;
3136
}
3237

3338
export interface Data {
@@ -65,9 +70,9 @@ let batcher: null | {
6570
sinks: Sink<GraphQLResponse>[];
6671
} = null;
6772

68-
function normalizeBatch(batch: FetchOptions['batch'] = true) {
69-
const p = typeof batch === 'boolean' ? { enabled: batch } : {};
70-
return { timeoutMs: 0, ...p };
73+
function normalizeBatch(batch: FetchOptions['batch'] = true): BatchConfig {
74+
const p = typeof batch === 'boolean' ? { enabled: batch } : batch;
75+
return { timeoutMs: 0, shouldRequestBeBatched: () => true, ...p };
7176
}
7277

7378
function normalizeAuth(auth: FetchOptions['authorization'] = '') {
@@ -169,7 +174,7 @@ function createFetch({
169174
const resp = processJson(batchResp[idx]);
170175
sink.next!(resp);
171176
sink.complete!();
172-
} catch (err) {
177+
} catch (err: any) {
173178
sink.error!(err);
174179
}
175180
});
@@ -190,7 +195,7 @@ function createFetch({
190195
function fetchFn(
191196
operation: RequestParameters,
192197
variables: Variables,
193-
_cacheConfig?: CacheConfig,
198+
cacheConfig?: CacheConfig,
194199
uploadables?: UploadableMap,
195200
) {
196201
// We use observables directly here instead of the promise value
@@ -210,7 +215,13 @@ function createFetch({
210215
if (
211216
batching.enabled &&
212217
!uploadables &&
213-
operation.operationKind !== 'mutation'
218+
operation.operationKind !== 'mutation' &&
219+
batching.shouldRequestBeBatched!(
220+
operation,
221+
variables,
222+
cacheConfig,
223+
uploadables,
224+
)
214225
) {
215226
addToBatch(body as string, sink);
216227

test/NetworkLayer.test.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ describe('NetworkLayer', () => {
1818
// eslint-disable-next-line require-await
1919
async function run(
2020
layer: Network,
21-
{ files, kind = 'query', variables = {} }: any = {},
21+
{ files, kind = 'query', variables = {}, cacheConfig = {} }: any = {},
2222
) {
2323
const $req = layer.execute(
2424
{
@@ -33,7 +33,7 @@ describe('NetworkLayer', () => {
3333
metadata: {},
3434
},
3535
variables,
36-
{}, // cacheConfig
36+
cacheConfig,
3737
files,
3838
);
3939

@@ -145,6 +145,44 @@ describe('NetworkLayer', () => {
145145
expect(req2).toEqual(defaultResponse);
146146
});
147147

148+
it('should conditionally batch requests', async () => {
149+
const networkLayer = NetworkLayer.create({
150+
batch: {
151+
enabled: true,
152+
shouldRequestBeBatched(_op, _v, config) {
153+
if (config!.metadata?.donotBatch) return false;
154+
return true;
155+
},
156+
},
157+
});
158+
159+
fetchMock.post('/graphql', (_url: string, opts: any) => {
160+
const body = JSON.parse(opts.body);
161+
return Array.isArray(body)
162+
? Array(body.length).fill(defaultResponse)
163+
: defaultResponse;
164+
});
165+
166+
let [req1, req2] = await Promise.all([
167+
run(networkLayer),
168+
run(networkLayer),
169+
]);
170+
171+
expect(fetchMock).toHaveFetchedTimes(1);
172+
173+
[req1, , req2] = await Promise.all([
174+
run(networkLayer),
175+
run(networkLayer),
176+
run(networkLayer, { cacheConfig: { metadata: { donotBatch: true } } }),
177+
]);
178+
179+
expect(fetchMock).toHaveFetchedTimes(3);
180+
181+
expect(req1).toEqual(defaultResponse);
182+
183+
expect(req2).toEqual(defaultResponse);
184+
});
185+
148186
it('should error for invalid response', async () => {
149187
const networkLayer = NetworkLayer.create();
150188

0 commit comments

Comments
 (0)