createResource returns an object with methods instead of a read function (#12304)
Changes `createResource` to return an object with `read` and `preload` methods. Future methods may include `set`, `subscribe`, `invalidate`, and so on.
Andrew Clark committed
Feb 28, 2018 at 10:17 UTC
2cf9063318014dcc9a4839bb15ebb89a55198fce
2 files changed
+58
-57
packages/simple-cache-provider/src/SimpleCacheProvider.js
+36
-35
@@ -225,11 +225,11 @@ if (__DEV__) {
225
}
226
227
type primitive = string | number | boolean | void | null;
228
-type ResourceReader<K, V> = (Cache, K) => V;
228
230
-type Resource<K, V> = ResourceReader<K, V> & {
229
+type Resource<K, V> = {|
230
+ read(Cache, K): V,
231
preload(cache: Cache, key: K): void,
232
-};
232
+|};
233
234
// These declarations are used to express function overloading. I wish there
235
// were a more elegant way to do this in the function definition itself.
@@ -252,43 +252,44 @@ export function createResource<V, K, H: primitive>(
252
loadResource: K => Promise<V>,
253
hash: K => H,
254
): Resource<K, V> {
255
- // The read function itself serves as the resource type.
256
- function read(cache, key) {
257
- if (__DEV__) {
258
- warning(
259
- isCache(cache),
260
- 'read(): The first argument must be a cache. Instead received: %s',
261
- cache,
262
- );
263
- }
264
- if (hash === undefined) {
255
+ const resource = {
256
+ read(cache, key) {
257
if (__DEV__) {
266
- warnIfNonPrimitiveKey(key, 'read');
258
+ warning(
259
+ isCache(cache),
260
+ 'read(): The first argument must be a cache. Instead received: %s',
261
+ cache,
262
+ );
263
}
268
- return cache.read(read, key, loadResource, key);
269
- }
270
- const hashedKey = hash(key);
271
- return cache.read(read, hashedKey, loadResource, key);
272
- }
273
- read.preload = function(cache, key) {
274
- if (__DEV__) {
275
- warning(
276
- isCache(cache),
277
- 'preload(): The first argument must be a cache. Instead received: %s',
278
- cache,
279
- );
280
- }
281
- if (hash === undefined) {
264
+ if (hash === undefined) {
265
+ if (__DEV__) {
266
+ warnIfNonPrimitiveKey(key, 'read');
267
+ }
268
+ return cache.read(resource, key, loadResource, key);
269
+ }
270
+ const hashedKey = hash(key);
271
+ return cache.read(resource, hashedKey, loadResource, key);
272
+ },
273
+ preload(cache, key) {
274
if (__DEV__) {
283
- warnIfNonPrimitiveKey(key, 'preload');
275
+ warning(
276
+ isCache(cache),
277
+ 'preload(): The first argument must be a cache. Instead received: %s',
278
+ cache,
279
+ );
280
}
285
- cache.preload(read, key, loadResource, key);
286
- return;
287
- }
288
- const hashedKey = hash(key);
289
- cache.preload(read, hashedKey, loadResource, key);
281
+ if (hash === undefined) {
282
+ if (__DEV__) {
283
+ warnIfNonPrimitiveKey(key, 'preload');
284
+ }
285
+ cache.preload(resource, key, loadResource, key);
286
+ return;
287
+ }
288
+ const hashedKey = hash(key);
289
+ cache.preload(resource, hashedKey, loadResource, key);
290
+ },
291
};
291
- return read;
292
+ return resource;
293
}
294
295
// Global cache has no eviction policy (except for, ya know, a browser refresh).
packages/simple-cache-provider/src/__tests__/SimpleCacheProvider-test.js
+22
-22
@@ -23,18 +23,18 @@ describe('SimpleCacheProvider', () => {
23
function loadUpperCase(text) {
24
return Promise.resolve(text.toUpperCase());
25
}
26
- const readUpperCase = createResource(loadUpperCase);
26
+ const UpperCase = createResource(loadUpperCase);
27
const cache = createCache();
28
29
let suspender;
30
try {
31
- readUpperCase(cache, 'hello');
31
+ UpperCase.read(cache, 'hello');
32
} catch (v) {
33
suspender = v;
34
}
35
36
await suspender;
37
- const result = readUpperCase(cache, 'hello');
37
+ const result = UpperCase.read(cache, 'hello');
38
expect(result).toBe('HELLO');
39
});
40
@@ -52,12 +52,12 @@ describe('SimpleCacheProvider', () => {
52
return Promise.resolve(text.toUpperCase());
53
}
54
}
55
- const readUpperCase = createResource(loadUpperCase);
55
+ const UpperCase = createResource(loadUpperCase);
56
const cache = createCache();
57
58
let suspender;
59
try {
60
- readUpperCase(cache, 'hello');
60
+ UpperCase.read(cache, 'hello');
61
} catch (v) {
62
suspender = v;
63
}
@@ -68,17 +68,17 @@ describe('SimpleCacheProvider', () => {
68
} catch (e) {
69
error = e;
70
}
71
- expect(() => readUpperCase(cache, 'hello')).toThrow(error);
71
+ expect(() => UpperCase.read(cache, 'hello')).toThrow(error);
72
expect(error.message).toBe('oh no');
73
74
// On a subsequent read, it should still throw.
75
try {
76
- readUpperCase(cache, 'hello');
76
+ UpperCase.read(cache, 'hello');
77
} catch (v) {
78
suspender = v;
79
}
80
await suspender;
81
- expect(() => readUpperCase(cache, 'hello')).toThrow(error);
81
+ expect(() => UpperCase.read(cache, 'hello')).toThrow(error);
82
expect(error.message).toBe('oh no');
83
});
84
@@ -88,13 +88,13 @@ describe('SimpleCacheProvider', () => {
88
function loadUpperCase(text) {
89
return Promise.resolve(text.toUpperCase());
90
}
91
- const readUpperCase = createResource(loadUpperCase);
91
+ const UpperCase = createResource(loadUpperCase);
92
const cache = createCache();
93
94
- readUpperCase.preload(cache, 'hello');
94
+ UpperCase.preload(cache, 'hello');
95
// Wait for next tick
96
await Promise.resolve();
97
- const result = readUpperCase(cache, 'hello');
97
+ const result = UpperCase.read(cache, 'hello');
98
expect(result).toBe('HELLO');
99
});
100
@@ -104,14 +104,14 @@ describe('SimpleCacheProvider', () => {
104
function loadUpperCase(text) {
105
return Promise.reject(new Error('uh oh'));
106
}
107
- const readUpperCase = createResource(loadUpperCase);
107
+ const UpperCase = createResource(loadUpperCase);
108
const cache = createCache();
109
110
- readUpperCase.preload(cache, 'hello');
110
+ UpperCase.preload(cache, 'hello');
111
// Wait for next tick
112
await Promise.resolve();
113
114
- expect(() => readUpperCase(cache, 'hello')).toThrow('uh oh');
114
+ expect(() => UpperCase.read(cache, 'hello')).toThrow('uh oh');
115
});
116
117
it('accepts custom hash function', async () => {
@@ -123,18 +123,18 @@ describe('SimpleCacheProvider', () => {
123
function hash([a, b]) {
124
return `${a + b}`;
125
}
126
- const readSum = createResource(loadSum, hash);
126
+ const Sum = createResource(loadSum, hash);
127
const cache = createCache();
128
129
- readSum.preload(cache, [5, 5]);
130
- readSum.preload(cache, [1, 2]);
129
+ Sum.preload(cache, [5, 5]);
130
+ Sum.preload(cache, [1, 2]);
131
await Promise.resolve();
132
133
- expect(readSum(cache, [5, 5])).toEqual(10);
134
- expect(readSum(cache, [1, 2])).toEqual(3);
133
+ expect(Sum.read(cache, [5, 5])).toEqual(10);
134
+ expect(Sum.read(cache, [1, 2])).toEqual(3);
135
// The fact that the next line returns synchronously and doesn't throw, even
136
// though [3, 7] was not preloaded, proves that the hashing function works.
137
- expect(readSum(cache, [3, 7])).toEqual(10);
137
+ expect(Sum.read(cache, [3, 7])).toEqual(10);
138
});
139
140
it('warns if resourceType is a string or number', () => {
@@ -171,11 +171,11 @@ describe('SimpleCacheProvider', () => {
171
return Promise.resolve(a + b);
172
}
173
174
- const readSum = createResource(loadSum);
174
+ const Sum = createResource(loadSum);
175
const cache = createCache();
176
177
function fn() {
178
- readSum.preload(cache, [5, 5]);
178
+ Sum.preload(cache, [5, 5]);
179
}
180
181
if (__DEV__) {