Skip to content

Commit 7ef09b4

Browse files
author
Ryan Spradlin
committed
Implement a new prime(key, value) API, to allow for directly priming
the cache with a given key and value.
1 parent c907bb1 commit 7ef09b4

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

README.md

+5
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ Clears the entire cache. To be used when some event results in unknown
196196
invalidations across this particular `DataLoader`. Returns itself for
197197
method chaining.
198198

199+
##### `prime(key, value)`
200+
201+
Primes the cache with the provided key and value. If the key already exists, the
202+
value will be updated. Returns itself for method chaining.
203+
199204

200205
## Using with GraphQL
201206

src/__tests__/dataloader-test.js

+49
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,22 @@ describe('Primary API', () => {
165165
expect(loadCalls).to.deep.equal([ [ 'A', 'B' ], [ 'A', 'B' ] ]);
166166
});
167167

168+
it('allows priming the cache', async () => {
169+
var [ identityLoader, loadCalls ] = idLoader();
170+
171+
identityLoader.prime('A', 'A');
172+
173+
var [ a, b ] = await Promise.all([
174+
identityLoader.load('A'),
175+
identityLoader.load('B')
176+
]);
177+
178+
expect(a).to.equal('A');
179+
expect(b).to.equal('B');
180+
181+
expect(loadCalls).to.deep.equal([ [ 'B' ] ]);
182+
});
183+
168184
});
169185

170186
describe('Represents Errors', () => {
@@ -249,6 +265,23 @@ describe('Represents Errors', () => {
249265
expect(loadCalls).to.deep.equal([ [ 1 ] ]);
250266
});
251267

268+
it('Handles priming the cache with an error', async () => {
269+
var [ identityLoader, loadCalls ] = idLoader();
270+
271+
identityLoader.prime(1, new Error('Error: 1'));
272+
273+
var caughtErrorA;
274+
try {
275+
await identityLoader.load(1);
276+
} catch (error) {
277+
caughtErrorA = error;
278+
}
279+
expect(caughtErrorA).to.be.instanceof(Error);
280+
expect((caughtErrorA: any).message).to.equal('Error: 1');
281+
282+
expect(loadCalls).to.deep.equal([]);
283+
});
284+
252285
it('Can clear values from cache after errors', async () => {
253286
var loadCalls = [];
254287
var errorLoader = new DataLoader(keys => {
@@ -485,6 +518,22 @@ describe('Accepts options', () => {
485518
expect(identityLoadCalls[0][0]).to.equal(keyA);
486519
});
487520

521+
it('Allows priming the cache with an object key', async () => {
522+
var [ identityLoader, loadCalls ] = idLoader({ cacheKeyFn: cacheKey });
523+
524+
var key1 = { id: 123 };
525+
var key2 = { id: 123 };
526+
527+
identityLoader.prime(key1, key1);
528+
529+
var value1 = await identityLoader.load(key1);
530+
var value2 = await identityLoader.load(key2);
531+
532+
expect(loadCalls).to.deep.equal([]);
533+
expect(value1).to.equal(key1);
534+
expect(value2).to.equal(key1);
535+
});
536+
488537
});
489538

490539
describe('Accepts custom cacheMap instance', () => {

src/index.js

+21-3
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010

1111
// A Function, which when given an Array of keys, returns a Promise of an Array
1212
// of values or Errors.
13-
type BatchLoadFn<K, V> = (keys: Array<K>) => Promise<Array<V | Error>>
13+
type BatchLoadFn<K, V> = (keys: Array<K>) => Promise<Array<V | Error>>;
1414

1515
type CacheMap<K, V> = {
1616
get(key: K): V | void;
1717
set(key: K, value: V): any;
1818
delete(key: K): any;
1919
clear(): any;
20-
}
20+
};
2121

2222
// Optionally turn off batching or caching or provide a cache key function or a
2323
// custom cache instance.
@@ -26,7 +26,7 @@ type Options<K, V> = {
2626
cache?: boolean,
2727
cacheMap?: CacheMap<K, Promise<V>>,
2828
cacheKeyFn?: (key: any) => any
29-
}
29+
};
3030

3131
/**
3232
* A `DataLoader` creates a public API for loading data from a particular
@@ -157,6 +157,24 @@ export default class DataLoader<K, V> {
157157
this._promiseCache.clear();
158158
return this;
159159
}
160+
161+
/**
162+
* Adds/updates the provied key and value in the cache. Returns itself for
163+
* method chaining.
164+
*/
165+
prime(key: K, value: V): DataLoader<K, V> {
166+
var cacheKeyFn = this._options && this._options.cacheKeyFn;
167+
var cacheKey = cacheKeyFn ? cacheKeyFn(key) : key;
168+
169+
// Cache a rejected promise if the value is an Error, in order to match the
170+
// behavior of load(key).
171+
var promise = value instanceof Error ?
172+
Promise.reject(value) :
173+
Promise.resolve(value);
174+
175+
this._promiseCache.set(cacheKey, promise);
176+
return this;
177+
}
160178
}
161179

162180
// Private: Enqueue a Job to be executed after all "PromiseJobs" Jobs.

0 commit comments

Comments
 (0)