Skip to content

Commit

Permalink
feat(bypass): enable bypass of cache.set or cache.get via input or env
Browse files Browse the repository at this point in the history
  • Loading branch information
uladkasach committed Jun 6, 2024
1 parent c6cbc51 commit 677a950
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 2 deletions.
Empty file modified .husky/commit-msg
100644 → 100755
Empty file.
12 changes: 12 additions & 0 deletions src/logic/serde/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,15 @@ export const defaultKeySerializationMethod: KeySerializationMethod<any> = ({
}) => 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;
};
40 changes: 39 additions & 1 deletion src/logic/wrappers/withSimpleCaching.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {
} from '../options/getCacheFromCacheOption';
import {
defaultKeySerializationMethod,
defaultShouldBypassGetMethod,
defaultShouldBypassSetMethod,
defaultValueSerializationMethod,
KeySerializationMethod,
noOp,
Expand Down Expand Up @@ -34,6 +36,33 @@ export interface WithSimpleCachingOptions<
value?: (cached: NotUndefined<ReturnType<C['get']>>) => ReturnType<L>;
};
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<L>) => 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<L>) => boolean;
};
}

/**
Expand Down Expand Up @@ -69,6 +98,10 @@ export const withSimpleCaching = <
value: deserializeValue = noOp, // default deserialize value to noOp
} = {},
secondsUntilExpiration,
bypass = {
get: defaultShouldBypassGetMethod,
set: defaultShouldBypassSetMethod,
},
}: WithSimpleCachingOptions<L, C>,
): L => {
return ((...args: Parameters<L>): ReturnType<L> => {
Expand All @@ -79,12 +112,17 @@ export const withSimpleCaching = <
const cache = getCacheFromCacheOption({ forInput: args, cacheOption });

// see if its already cached
const cachedValue: ReturnType<C['get']> = cache.get(key);
const cachedValue: ReturnType<C['get']> = 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<L> = 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 });
Expand Down
40 changes: 39 additions & 1 deletion src/logic/wrappers/withSimpleCachingAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import {
} from '../options/getCacheFromCacheOption';
import {
defaultKeySerializationMethod,
defaultShouldBypassGetMethod,
defaultShouldBypassSetMethod,
defaultValueSerializationMethod,
KeySerializationMethod,
noOp,
Expand Down Expand Up @@ -63,6 +65,33 @@ export interface WithSimpleCachingAsyncOptions<
) => Awaited<ReturnType<L>>;
};
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<L>) => 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<L>) => boolean;
};
}

/**
Expand Down Expand Up @@ -129,6 +158,10 @@ export const withSimpleCachingAsync = <
} = {},
deserialize: { value: deserializeValue = noOp } = {},
secondsUntilExpiration,
bypass = {
get: defaultShouldBypassGetMethod,
set: defaultShouldBypassSetMethod,
},
}: WithSimpleCachingAsyncOptions<L, C>,
): L => {
// add async caching to the logic
Expand All @@ -145,12 +178,17 @@ export const withSimpleCachingAsync = <
});

// see if its already cached
const cachedValue: Awaited<ReturnType<C['get']>> = await cache.get(key);
const cachedValue: Awaited<ReturnType<C['get']>> = 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<ReturnType<L>> = 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 });
Expand Down

0 comments on commit 677a950

Please sign in to comment.