From 677a950107b5db687f33996c1fb22e8e4a338ab0 Mon Sep 17 00:00:00 2001 From: Ulad Kasach Date: Thu, 6 Jun 2024 06:24:55 -0400 Subject: [PATCH] feat(bypass): enable bypass of cache.set or cache.get via input or env --- .husky/commit-msg | 0 src/logic/serde/defaults.ts | 12 ++++++ src/logic/wrappers/withSimpleCaching.ts | 40 +++++++++++++++++++- src/logic/wrappers/withSimpleCachingAsync.ts | 40 +++++++++++++++++++- 4 files changed, 90 insertions(+), 2 deletions(-) mode change 100644 => 100755 .husky/commit-msg diff --git a/.husky/commit-msg b/.husky/commit-msg old mode 100644 new mode 100755 diff --git a/src/logic/serde/defaults.ts b/src/logic/serde/defaults.ts index 9f0d59b..d796cae 100644 --- a/src/logic/serde/defaults.ts +++ b/src/logic/serde/defaults.ts @@ -6,3 +6,15 @@ export const defaultKeySerializationMethod: KeySerializationMethod = ({ }) => JSON.stringify(forInput); export const defaultValueSerializationMethod = noOp; export const defaultValueDeserializationMethod = noOp; +export const defaultShouldBypassGetMethod = () => { + if (process.env.CACHE_BYPASS_GET) + return process.env.CACHE_BYPASS_GET === 'true'; + if (process.env.CACHE_BYPASS) return process.env.CACHE_BYPASS === 'true'; + return false; +}; +export const defaultShouldBypassSetMethod = () => { + if (process.env.CACHE_BYPASS_SET) + return process.env.CACHE_BYPASS_SET === 'true'; + if (process.env.CACHE_BYPASS) return process.env.CACHE_BYPASS === 'true'; + return false; +}; diff --git a/src/logic/wrappers/withSimpleCaching.ts b/src/logic/wrappers/withSimpleCaching.ts index c7a4339..05e968e 100644 --- a/src/logic/wrappers/withSimpleCaching.ts +++ b/src/logic/wrappers/withSimpleCaching.ts @@ -7,6 +7,8 @@ import { } from '../options/getCacheFromCacheOption'; import { defaultKeySerializationMethod, + defaultShouldBypassGetMethod, + defaultShouldBypassSetMethod, defaultValueSerializationMethod, KeySerializationMethod, noOp, @@ -34,6 +36,33 @@ export interface WithSimpleCachingOptions< value?: (cached: NotUndefined>) => ReturnType; }; secondsUntilExpiration?: number; + + /** + * whether to bypass the cached for either the set or get operation + */ + bypass?: { + /** + * whether to bypass the cache for the get + * + * note + * - equivalent to the result not already being cached + * + * default + * - process.env.CACHE_BYPASS_GET ? process.env.CACHE_BYPASS_GET === 'true' : process.env.CACHE_BYPASS === 'true' + */ + get?: (input: Parameters) => boolean; + + /** + * whether to bypass the cache for the set + * + * note + * - keeps whatever the previously cached value was, while returning the new value + * + * default + * - process.env.CACHE_BYPASS_SET ? process.env.CACHE_BYPASS_SET === 'true' : process.env.CACHE_BYPASS === 'true' + */ + set?: (input: Parameters) => boolean; + }; } /** @@ -69,6 +98,10 @@ export const withSimpleCaching = < value: deserializeValue = noOp, // default deserialize value to noOp } = {}, secondsUntilExpiration, + bypass = { + get: defaultShouldBypassGetMethod, + set: defaultShouldBypassSetMethod, + }, }: WithSimpleCachingOptions, ): L => { return ((...args: Parameters): ReturnType => { @@ -79,12 +112,17 @@ export const withSimpleCaching = < const cache = getCacheFromCacheOption({ forInput: args, cacheOption }); // see if its already cached - const cachedValue: ReturnType = cache.get(key); + const cachedValue: ReturnType = bypass.get?.(args) + ? undefined + : cache.get(key); if (isNotUndefined(cachedValue)) return deserializeValue(cachedValue); // if already cached, return it immediately // if its not, grab the output from the logic const output: ReturnType = logic(...args); + // if was asked to bypass cache.set, we can return the output now + if (bypass.set?.(args)) return output; + // set the output to the cache const serializedOutput = serializeValue(output); cache.set(key, serializedOutput, { secondsUntilExpiration }); diff --git a/src/logic/wrappers/withSimpleCachingAsync.ts b/src/logic/wrappers/withSimpleCachingAsync.ts index f8ef5bb..6e4f5a4 100644 --- a/src/logic/wrappers/withSimpleCachingAsync.ts +++ b/src/logic/wrappers/withSimpleCachingAsync.ts @@ -8,6 +8,8 @@ import { } from '../options/getCacheFromCacheOption'; import { defaultKeySerializationMethod, + defaultShouldBypassGetMethod, + defaultShouldBypassSetMethod, defaultValueSerializationMethod, KeySerializationMethod, noOp, @@ -63,6 +65,33 @@ export interface WithSimpleCachingAsyncOptions< ) => Awaited>; }; secondsUntilExpiration?: number; + + /** + * whether to bypass the cached for either the set or get operation + */ + bypass?: { + /** + * whether to bypass the cache for the get + * + * note + * - equivalent to the result not already being cached + * + * default + * - process.env.CACHE_BYPASS_GET ? process.env.CACHE_BYPASS_GET === 'true' : process.env.CACHE_BYPASS === 'true' + */ + get?: (input: Parameters) => boolean; + + /** + * whether to bypass the cache for the set + * + * note + * - keeps whatever the previously cached value was, while returning the new value + * + * default + * - process.env.CACHE_BYPASS_SET ? process.env.CACHE_BYPASS_SET === 'true' : process.env.CACHE_BYPASS === 'true' + */ + set?: (input: Parameters) => boolean; + }; } /** @@ -129,6 +158,10 @@ export const withSimpleCachingAsync = < } = {}, deserialize: { value: deserializeValue = noOp } = {}, secondsUntilExpiration, + bypass = { + get: defaultShouldBypassGetMethod, + set: defaultShouldBypassSetMethod, + }, }: WithSimpleCachingAsyncOptions, ): L => { // add async caching to the logic @@ -145,12 +178,17 @@ export const withSimpleCachingAsync = < }); // see if its already cached - const cachedValue: Awaited> = await cache.get(key); + const cachedValue: Awaited> = bypass.get?.(args) + ? undefined + : await cache.get(key); if (isNotUndefined(cachedValue)) return deserializeValue(cachedValue); // if already cached, return it immediately // if its not, grab the output from the logic const output: Awaited> = await logic(...args); + // if was asked to bypass cache.set, we can return the output now + if (bypass.set?.(args)) return output; + // set the output to the cache const serializedOutput = serializeValue(output); await cache.set(key, serializedOutput, { secondsUntilExpiration });