diff --git a/.gitignore b/.gitignore index d609405..d2f2a73 100644 --- a/.gitignore +++ b/.gitignore @@ -173,4 +173,4 @@ local.sqlite local.sqlite-shm local.sqlite-wal -.beth/ \ No newline at end of file +beth-cache.sqlite \ No newline at end of file diff --git a/src/beth/cache.ts b/src/beth/cache.ts index 23322eb..4478519 100644 --- a/src/beth/cache.ts +++ b/src/beth/cache.ts @@ -19,7 +19,7 @@ class BethPersistCache { constructor() { this.callBackMap = new Map(); this.inMemoryDataCache = new Map(); - this.jsonDataCache = new Database("./.beth/beth-cache.sqlite"); + this.jsonDataCache = new Database("beth-cache.sqlite"); this.intervals = new Set(); this.pendingMap = new Map(); this.keys = new Set(); @@ -82,7 +82,7 @@ class BethPersistCache { promise.then((value) => { this.pendingMap.delete(key); - console.log(`Seeding ${cache} Cache:`, key, value); + console.log(`Seeding ${cache} Cache:`, key); if (cache === "memory") { this.inMemoryDataCache.set(key, value); } else if (cache === "json") { diff --git a/src/beth/test/cache.test.tsx b/src/beth/test/cache.test.tsx index 017d5dc..c838ef9 100644 --- a/src/beth/test/cache.test.tsx +++ b/src/beth/test/cache.test.tsx @@ -22,6 +22,16 @@ test("static json cache", async () => { expect(html).toBe(`

number: 1

number: 1

`); + // This should result in no 'cache hit' log, because the render cache is never reset from the previous render + const html2 = await ( + <> + + + + ); + + expect(html2).toBe(`

number: 1

number: 1

`); + // even in a new render we get the same results const Test = () => ; @@ -304,3 +314,239 @@ test("memory cache revalidate tag", async () => { expect(html3).toBe(`

number: 3

number: 3

`); }); + +test("request during interval revalidation", async () => { + let count = 0; + const getCount = async () => + new Promise((resolve) => setTimeout(() => resolve(++count), 100)); + const cachedGetCount = persistedCache(getCount, "getCount7", { + revalidate: 1, + }); + + const Component = async () => { + const data = await cachedGetCount(); + return

number: {data}

; + }; + + const html = await renderToString(() => ( + <> + + + + )); + + expect(html).toBe(`

number: 1

number: 1

`); + + // cache request goes off during revalidation + // should result in 'pending cache hit' log + updated data + + await new Promise((resolve) => + setTimeout(async () => { + const html3 = await renderToString(() => ( + <> + + + + )); + + expect(html3).toBe(`

number: 2

number: 2

`); + + resolve(void 0); + }, 1010) + ); +}); + +test("request during tag revalidation", async () => { + let count = 0; + const getCount = async () => + new Promise((resolve) => setTimeout(() => resolve(++count), 100)); + const cachedGetCount = persistedCache(getCount, "getCount8", { + tags: ["tag1"], + }); + + const Component = async () => { + const data = await cachedGetCount(); + return

number: {data}

; + }; + + const html = await renderToString(() => ( + <> + + + + )); + + expect(html).toBe(`

number: 1

number: 1

`); + + setTimeout(() => { + count++; + revalidateTag("tag1"); + }, 1000); + + // cache request goes off during revalidation + // should result in 'pending cache hit' log + updated data + + await new Promise((resolve) => + setTimeout(async () => { + const html3 = await renderToString(() => ( + <> + + + + )); + + expect(html3).toBe(`

number: 3

number: 3

`); + + resolve(void 0); + }, 1010) + ); +}); + +test("interval during tag revalidation", async () => { + let count = 0; + const getCount = async () => + new Promise((resolve) => setTimeout(() => resolve(++count), 300)); + const cachedGetCount = persistedCache(getCount, "getCount9", { + tags: ["tag1"], + revalidate: 1, + }); + + const Component = async () => { + const data = await cachedGetCount(); + return

number: {data}

; + }; + + const html = await renderToString(() => ( + <> + + + + )); + + expect(html).toBe(`

number: 1

number: 1

`); + + setTimeout(() => { + count++; + revalidateTag("tag1"); + }, 900); + + // should see pending cache hit for interval revalidation + + // cache request goes off during revalidation + // should result in 2nd 'pending cache hit' log + updated data + + await new Promise((resolve) => + setTimeout(async () => { + const html3 = await renderToString(() => ( + <> + + + + )); + + expect(html3).toBe(`

number: 3

number: 3

`); + + resolve(void 0); + }, 1100) + ); +}); + +test("interval during tag revalidation", async () => { + let count = 0; + const getCount = async () => + new Promise((resolve) => setTimeout(() => resolve(++count), 300)); + const cachedGetCount = persistedCache(getCount, "getCount10", { + tags: ["tag1"], + revalidate: 1, + }); + + const Component = async () => { + const data = await cachedGetCount(); + return

number: {data}

; + }; + + const html = await renderToString(() => ( + <> + + + + )); + + expect(html).toBe(`

number: 1

number: 1

`); + + setTimeout(() => { + count++; + revalidateTag("tag1"); + }, 1100); + + // should see pending cache hit for tag revalidation + + // cache request goes off during revalidation + // should result in 2nd 'pending cache hit' log + updated data + + await new Promise((resolve) => + setTimeout(async () => { + const html3 = await renderToString(() => ( + <> + + + + )); + + expect(html3).toBe(`

number: 3

number: 3

`); + + resolve(void 0); + }, 1150) + ); +}); + +test("complex object storage to memory", async () => { + const getData = async () => ({ + a: 1, + b: 2, + c: { + d: 3, + e: [4, 5, 6], + }, + }); + + const cachedGetData = persistedCache(getData, "getData1", { + persist: "memory", + }); + + const data = await cachedGetData(); + + expect(data).toStrictEqual({ + a: 1, + b: 2, + c: { + d: 3, + e: [4, 5, 6], + }, + }); +}); +test("complex object storage to json", async () => { + const getData = async () => ({ + a: 1, + b: 2, + c: { + d: 3, + e: [4, 5, 6], + }, + }); + + const cachedGetData = persistedCache(getData, "getData2", { + persist: "json", + }); + + const data = await cachedGetData(); + + expect(data).toStrictEqual({ + a: 1, + b: 2, + c: { + d: 3, + e: [4, 5, 6], + }, + }); +});