From 9741c97b6b843aedc4fe4ab199151bddf919dd07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20S=C3=A1ez?= Date: Tue, 1 Nov 2022 11:57:08 -0700 Subject: [PATCH] new "setCache" --- .changeset/shaggy-shirts-chew.md | 5 ++ src/fineGrained.ts | 66 +++++++++++++++++++++++ test/fineGrained.spec.ts | 89 +++++++++++++++++++++++++++++++- test/utils.ts | 2 +- 4 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 .changeset/shaggy-shirts-chew.md diff --git a/.changeset/shaggy-shirts-chew.md b/.changeset/shaggy-shirts-chew.md new file mode 100644 index 0000000..448ad39 --- /dev/null +++ b/.changeset/shaggy-shirts-chew.md @@ -0,0 +1,5 @@ +--- +"@soundxyz/fine-grained-cache": minor +--- + +New "setCache" function returned alongside "getCached" diff --git a/src/fineGrained.ts b/src/fineGrained.ts index c491d17..396b91d 100644 --- a/src/fineGrained.ts +++ b/src/fineGrained.ts @@ -792,11 +792,77 @@ export function FineGrainedCache({ } } + async function setCache({ + populateMemoryCache = defaultUseMemoryCache, + ttl, + keys, + useSuperjson, + value, + }: { + populateMemoryCache: boolean; + ttl: StringValue | "Infinity"; + keys: string | [string, ...(string | number)[]]; + useSuperjson: boolean; + value: unknown; + }) { + const key = generateCacheKey(keys); + + const expirySeconds = ttl === "Infinity" ? -1 : getExpirySeconds(ttl); + + const stringifiedValue = useSuperjson ? superjson.stringify(value) : JSON.stringify(value); + + if (expirySeconds > 0) { + if (populateMemoryCache) memoryCache.set(key, value); + + if (pipelineRedisSET) { + await pipelinedRedisSet({ + key, + value: stringifiedValue, + ttl: expirySeconds, + }); + } else { + const tracing = enabledLogEvents?.REDIS_SET ? getTracing() : null; + + await redis.setex(key, expirySeconds, stringifiedValue).then(() => { + if (tracing) { + logMessage("REDIS_SET", { + key, + expirySeconds, + time: tracing(), + }); + } + }); + } + } else if (ttl === "Infinity") { + if (populateMemoryCache) memoryCache.set(key, value); + + if (pipelineRedisSET) { + await pipelinedRedisSet({ + key, + value: stringifiedValue, + }); + } else { + const tracing = enabledLogEvents?.REDIS_SET ? getTracing() : null; + + await redis.set(key, stringifiedValue).then(() => { + if (tracing) { + logMessage("REDIS_SET", { + key, + expirySeconds: "Infinity", + time: tracing(), + }); + } + }); + } + } + } + return { getCached, generateCacheKey, keyPrefix, memoryCache, invalidateCache, + setCache, }; } diff --git a/test/fineGrained.spec.ts b/test/fineGrained.spec.ts index 34a6c2e..3f3aac5 100644 --- a/test/fineGrained.spec.ts +++ b/test/fineGrained.spec.ts @@ -1,7 +1,7 @@ import test from "ava"; import { join } from "path"; import { CachedCallback, FineGrainedCache, LogEventArgs } from "../src"; -import { getCached, invalidateCache, logEverything, memoryCache, redis } from "./utils"; +import { getCached, invalidateCache, logEverything, memoryCache, redis, setCache } from "./utils"; import { createDeferredPromise } from "../src/utils"; import { setTimeout } from "timers/promises"; import { addMinutes, minutesToSeconds } from "date-fns"; @@ -631,3 +631,90 @@ test("pipelined sets", async (t) => { t.deepEqual(valuesOnGet, [111, 222]); }); + +test("setCache - regular", async (t) => { + const keys = "test"; + const ttl = "10 seconds" as const; + + const value = 123; + + await setCache({ + keys, + ttl, + useSuperjson: false, + value, + populateMemoryCache: false, + }); + + const data = await getCached( + () => { + throw Error("Unexpected missing data"); + }, + { + keys, + ttl, + useSuperjson: false, + } + ); + + t.is(data, value); +}); + +test("setCache - superjson", async (t) => { + const keys = "test"; + const ttl = "10 seconds" as const; + + const value = 456; + + await setCache({ + keys, + ttl, + useSuperjson: true, + value, + populateMemoryCache: false, + }); + + const data = await getCached( + () => { + throw Error("Unexpected missing data"); + }, + { + keys, + ttl, + useSuperjson: true, + } + ); + + t.is(data, value); +}); + +test("setCache - memory cache", async (t) => { + const keys = "test"; + const ttl = "10 seconds" as const; + + const value = 456; + + await setCache({ + keys, + ttl, + // On purpose mismatch, memory cache should override + useSuperjson: true, + value, + populateMemoryCache: true, + }); + + const data = await getCached( + () => { + throw Error("Unexpected missing data"); + }, + { + keys, + ttl, + // On purpose mismatch, memory cache should override + useSuperjson: false, + checkShortMemoryCache: true, + } + ); + + t.is(data, value); +}); diff --git a/test/utils.ts b/test/utils.ts index a4e5c8e..9294659 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -5,7 +5,7 @@ export const redis = new Redis({ port: 6389, }); -export const { memoryCache, getCached, invalidateCache, generateCacheKey, keyPrefix } = +export const { memoryCache, getCached, invalidateCache, generateCacheKey, keyPrefix, setCache } = FineGrainedCache({ redis, logEvents: {