diff --git a/README.md b/README.md index f9ea6b2..752af37 100644 --- a/README.md +++ b/README.md @@ -104,7 +104,7 @@ const storage = { async getItem(cacheKey: string) { return redis.get(cacheKey) }, - async setItem(cacheKey: string, cacheValue: any) { + async setItem(cacheKey: string, cacheValue: any, persistOptions: PersistOptions) { // Use px or ex depending on whether you use milliseconds or seconds for your ttl // It is recommended to set ttl to your maxTimeToLive (it has to be more than it) await redis.set(cacheKey, cacheValue, 'px', ttl) @@ -178,6 +178,16 @@ const result = await swr.persist(cacheKey, cacheValue) The value will be passed through the `serialize` method you optionally provided when you instantiated the `swr` helper. +Additional options can be passed as a third argument and propagated to the storage's `setItem` method. + +```typescript +const cacheKey = 'your-cache-key' +const cacheValue = { something: 'useful' } +const persistOptions = { overrideOption: 1000 } +const result = await swr.persist(cacheKey, cacheValue, persistOptions) +``` + + #### Manually read from cache There is a convenience static method made available if you need to simply read from the underlying storage without triggering revalidation. Sometimes you just want to know if there is a value in the cache for a given key. diff --git a/src/index.test.ts b/src/index.test.ts index 0801589..ebcff82 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -672,6 +672,44 @@ describe('createStaleWhileRevalidateCache', () => { }) expect(fn).toHaveBeenCalledTimes(1) }) + + it('should persist given cache value for given key with custom storage configuration', async () => { + const swr = createStaleWhileRevalidateCache(validConfig) + + const key = 'persist key' + const value = 'value' + const options = { + ttl: 1000, + } + + expect(mockedLocalStorage.getItem(key)).toEqual(null) + expect(mockedLocalStorage.getItem(createTimeCacheKey(key))).toEqual(null) + + const spy = jest.spyOn(mockedLocalStorage, 'setItem') + await swr.persist(key, value, options) + + expect(spy).toHaveBeenCalledWith(key, value, options) + + expect(mockedLocalStorage.getItem(key)).toEqual(value) + expect(mockedLocalStorage.getItem(createTimeCacheKey(key))).toEqual( + expect.any(String) + ) + + const fn = jest.fn(() => 'something else') + const result = await swr(key, fn) + + expect(result).toMatchObject({ + value, + status: 'stale', + minTimeToStale: 0, + maxTimeToLive: Infinity, + now: expect.any(Number), + cachedAt: expect.any(Number), + expireAt: Infinity, + staleAt: expect.any(Number), + }) + expect(fn).toHaveBeenCalledTimes(1) + }) }) describe('swr.delete()', () => { diff --git a/src/index.ts b/src/index.ts index aa0bef5..bcc9342 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ import type { RetrieveCachedValueResponse, StaleWhileRevalidateCache, StaticMethods, + PersistOptions, } from '../types' import { CacheResponseStatus, EmitterEvents } from './constants' import { @@ -62,20 +63,22 @@ export function createStaleWhileRevalidateCache( cacheTime, serialize, storage, + persistOptions, }: { cacheKey: IncomingCacheKey cacheValue: CacheValue cacheTime: number serialize: NonNullable storage: Config['storage'] + persistOptions?: PersistOptions }): Promise { const key = getCacheKey(cacheKey) const timeKey = createTimeCacheKey(key) try { await Promise.all([ - storage.setItem(key, serialize(cacheValue)), - storage.setItem(timeKey, cacheTime.toString()), + storage.setItem(key, serialize(cacheValue), persistOptions), + storage.setItem(timeKey, cacheTime.toString(), persistOptions), ]) } catch (error) { emitter.emit(EmitterEvents.cacheSetFailed, { cacheKey, error }) @@ -314,7 +317,8 @@ export function createStaleWhileRevalidateCache( const persist: StaticMethods['persist'] = ( cacheKey: IncomingCacheKey, - cacheValue: CacheValue + cacheValue: CacheValue, + persistOptions?: PersistOptions ) => { return persistValue({ cacheKey, @@ -322,6 +326,7 @@ export function createStaleWhileRevalidateCache( cacheTime: Date.now(), serialize: cacheConfig.serialize, storage: cacheConfig.storage, + persistOptions, }) } diff --git a/types/index.d.ts b/types/index.d.ts index 03b44cd..b366f30 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,6 +1,10 @@ export interface Storage { getItem(key: string): unknown | null | Promise - setItem(key: string, value: unknown): void | Promise + setItem( + key: string, + value: unknown, + persistOptions?: PersistOptions + ): void | Promise removeItem?: (key: string) => unknown | null | Promise [key: string]: any } @@ -42,6 +46,8 @@ export type ResponseEnvelope = { staleAt: number } +export type PersistOptions = Record + export type StaleWhileRevalidateCache = ( cacheKey: IncomingCacheKey, fn: () => CacheValue | Promise, @@ -55,6 +61,7 @@ export type StaticMethods = { ) => Promise> persist: ( cacheKey: IncomingCacheKey, - cacheValue: CacheValue + cacheValue: CacheValue, + persistOptions?: PersistOptions ) => Promise }