Created
April 7, 2023 18:01
-
-
Save dmmulroy/33c31bef81554b099726b3a680dad974 to your computer and use it in GitHub Desktop.
SwrLruCache.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Cache, Key, State } from 'swr' | |
/** | |
* SwrLruCache is a Least Recently Used (LRU) cache implementing the SWR {@link Cache} | |
* interface. It manages fetched data and errors while limiting the number of | |
* stored items. This optimizes memory usage by evicting the least accessed | |
* items when capacity is reached. | |
*/ | |
export class SwrLruCache<Data = unknown, Error = unknown> | |
implements Cache<Data> | |
{ | |
private readonly cache = new Map<Key, State<Data, Error>>() | |
constructor(private readonly capacity: number) {} | |
/** | |
* Returns an iterable iterator over the keys in the cache. | |
* | |
* @returns {IterableIterator<string>} - An iterator of the cache keys. | |
*/ | |
public keys(): IterableIterator<string> { | |
// We need to cast here because the SWR Cache is incorrectly typed and should | |
// return an IterableIterator<Key> instead of an IterableIterator<string>. | |
// This is safe to do as the only place .keys() is called internally in SWR | |
// is here: https://github.com/vercel/swr/blob/main/_internal/utils/mutate.ts#L75 | |
return this.cache.keys() as IterableIterator<string> | |
} | |
/** | |
* Retrieves the data and error associated with the given key from the cache. | |
* | |
* @param {Key} key - The key of the cache entry to retrieve. | |
* @returns {State<Data, Error> | undefined} - The cache entry, or undefined if not found. | |
*/ | |
public get(key: Key): State<Data, Error> | undefined { | |
const value = this.cache.get(key) | |
if (value === undefined) { | |
return undefined | |
} | |
this.setMostRecentlyUsed(key, value) | |
return value | |
} | |
/** | |
* Sets the data and error associated with the given key in the cache. | |
* If the cache size exceeds its capacity after the insertion, the least recently used item is removed. | |
* | |
* @param {Key} key - The key of the cache entry to set. | |
* @param {State<Data, Error>} value - The value to be stored in the cache. | |
*/ | |
public set(key: Key, value: State<Data, Error>): void { | |
this.setMostRecentlyUsed(key, value) | |
if (this.cache.size > this.capacity) { | |
const oldestKey = this.cache.keys().next().value | |
this.cache.delete(oldestKey) | |
} | |
} | |
/** | |
* Removes the cache entry associated with the given key. | |
* @param {Key} key - The key of the cache entry to delete. | |
*/ | |
public delete(key: Key): void { | |
this.cache.delete(key) | |
} | |
/** | |
* Set the given key-value pair as the most recently used in the cache. | |
* | |
* The `delete` method is called before the `set` method to ensure that the | |
* key-value pair is moved to the end of the Map's key insertion order. | |
* Since the LRU cache evicts the least recently used item based on the | |
* insertion order of the keys, calling `delete` first makes sure that the | |
* most recently accessed key is placed at the end, thus preserving the LRU | |
* eviction strategy. | |
* | |
* @param {Key} key - The key to be set as the most recently used. | |
* @param {State<Data, Error>} value - The value associated with the key. | |
*/ | |
private setMostRecentlyUsed(key: Key, value: State<Data, Error>): void { | |
this.cache.delete(key) | |
this.cache.set(key, value) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment