Skip to content

Commit 01b4c0c

Browse files
committed
add cache.forceFetch, a fetch() that cannot return undefined
Fix: #329
1 parent aaaa7d7 commit 01b4c0c

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

src/index.ts

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ export namespace LRUCache {
306306
* various states.
307307
*
308308
* - inflight: there is another fetch() for this key which is in process
309-
* - get: there is no fetchMethod, so {@link LRUCache#get} was called.
309+
* - get: there is no {@link OptionsBase.fetchMethod}, so
310+
* {@link LRUCache#get} was called.
310311
* - miss: the item is not in cache, and will be fetched.
311312
* - hit: the item is in the cache, and was resolved immediately.
312313
* - stale: the item is in the cache, but stale.
@@ -812,7 +813,9 @@ export namespace LRUCache {
812813
* Changing any of these will alter the defaults for subsequent method calls,
813814
* but is otherwise safe.
814815
*/
815-
export class LRUCache<K extends {}, V extends {}, FC = unknown> implements Map<K,V> {
816+
export class LRUCache<K extends {}, V extends {}, FC = unknown>
817+
implements Map<K, V>
818+
{
816819
// properties coming in from the options of these, only max and maxSize
817820
// really *need* to be protected. The rest can be modified, as they just
818821
// set defaults for various methods.
@@ -2180,6 +2183,56 @@ export class LRUCache<K extends {}, V extends {}, FC = unknown> implements Map<K
21802183
}
21812184
}
21822185

2186+
/**
2187+
* In some cases, `cache.fetch()` may resolve to `undefined`, either because
2188+
* a {@link LRUCache.OptionsBase#fetchMethod} was not provided (turning
2189+
* `cache.fetch(k)` into just an async wrapper around `cache.get(k)`) or
2190+
* because `ignoreFetchAbort` was specified (either to the constructor or
2191+
* in the {@link LRUCache.FetchOptions}). Also, the
2192+
* {@link OptionsBase.fetchMethod} may return `undefined` or `void`, making
2193+
* the test even more complicated.
2194+
*
2195+
* Because inferring the cases where `undefined` might be returned are so
2196+
* cumbersome, but testing for `undefined` can also be annoying, this method
2197+
* can be used, which will reject if `this.fetch()` resolves to undefined.
2198+
*/
2199+
forceFetch(
2200+
k: K,
2201+
fetchOptions: unknown extends FC
2202+
? LRUCache.FetchOptions<K, V, FC>
2203+
: FC extends undefined | void
2204+
? LRUCache.FetchOptionsNoContext<K, V>
2205+
: LRUCache.FetchOptionsWithContext<K, V, FC>
2206+
): Promise<V>
2207+
// this overload not allowed if context is required
2208+
forceFetch(
2209+
k: unknown extends FC
2210+
? K
2211+
: FC extends undefined | void
2212+
? K
2213+
: never,
2214+
fetchOptions?: unknown extends FC
2215+
? LRUCache.FetchOptions<K, V, FC>
2216+
: FC extends undefined | void
2217+
? LRUCache.FetchOptionsNoContext<K, V>
2218+
: never
2219+
): Promise<V>
2220+
async forceFetch(
2221+
k: K,
2222+
fetchOptions: LRUCache.FetchOptions<K, V, FC> = {}
2223+
): Promise<V> {
2224+
const v = await this.fetch(
2225+
k,
2226+
fetchOptions as unknown extends FC
2227+
? LRUCache.FetchOptions<K, V, FC>
2228+
: FC extends undefined | void
2229+
? LRUCache.FetchOptionsNoContext<K, V>
2230+
: LRUCache.FetchOptionsWithContext<K, V, FC>
2231+
)
2232+
if (v === undefined) throw new Error('fetch() returned undefined')
2233+
return v
2234+
}
2235+
21832236
/**
21842237
* Return a value from the cache. Will update the recency of the cache
21852238
* entry found.

test/fetch.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -673,7 +673,7 @@ t.test('abort, but then keep on fetching anyway', async t => {
673673
t.equal(ac.signal.reason, er)
674674
t.equal(cache.get(1), 1)
675675

676-
const p2 = cache.fetch(2)
676+
const p2 = cache.forceFetch(2)
677677
t.equal(cache.get(2), undefined)
678678
cache.delete(2)
679679
t.equal(cache.get(2), undefined)
@@ -696,6 +696,9 @@ t.test('abort, but then keep on fetching anyway', async t => {
696696
const p4 = cache.fetch(4)
697697
clock.advance(100)
698698
t.equal(await p4, undefined)
699+
const p5 = cache.forceFetch(4)
700+
clock.advance(100)
701+
await t.rejects(p5, { message: 'fetch() returned undefined' })
699702
t.same(e.valList, before, 'did not update values with undefined')
700703
})
701704

0 commit comments

Comments
 (0)