UNPKG

@daiso-tech/core

Version:

The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.

698 lines 26 kB
/** * @module Cache */ import {} from "vitest"; import {} from "../../../cache/contracts/_module-exports.js"; import { TimeSpan } from "../../../utilities/_module-exports.js"; /** * The `databaseCacheAdapterTestSuite` function simplifies the process of testing your custom implementation of {@link IDatabaseCacheAdapter | `IDatabaseCacheAdapter`} with `vitest`. * * IMPORT_PATH: `"@daiso-tech/core/cache/test-utilities"` * @group TestUtilities * @example * ```ts * import { afterEach, beforeEach, describe, expect, test } from "vitest"; * import Sqlite, { type Database } from "better-sqlite3"; * import { databaseCacheAdapterTestSuite } from "@daiso-tech/core/cache/test-utilities"; * import { SqliteCacheAdapter } from "@daiso-tech/core/cache/adapters"; * import { Serde } from "@daiso-tech/core/serde"; * import { SuperJsonSerdeAdapter } from "@daiso-tech/core/serde/adapters"; * * describe("class: SqliteCacheAdapter", () => { * let database: Database; * beforeEach(() => { * database = new Sqlite(":memory:"); * }); * afterEach(() => { * database.close(); * }); * databaseCacheAdapterTestSuite({ * createAdapter: async () => { * const adapter = new SqliteCacheAdapter({ * database: database, * tableName: "custom_table", * shouldRemoveExpiredKeys: false, * serde: new Serde(new SuperJsonSerdeAdapter()), * }); * await adapter.init(); * return adapter; * }, * test, * beforeEach, * expect, * describe, * }); * }); * ``` */ export function databaseCacheAdapterTestSuite(settings) { const { expect, test, createAdapter, describe, beforeEach } = settings; let adapter; beforeEach(async () => { adapter = await createAdapter(); }); describe("method: find", () => { test("Should return null when key doesnt exists", async () => { const findData = await adapter.find("a"); expect(findData).toBeNull(); }); test("Should return the value when key exists", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const findData = await adapter.find(insertData.key); const result = { expiration: insertData.expiration, value: insertData.value, }; expect(findData).toStrictEqual(result); }); }); describe("method: insert", () => { test("Should throw an error when key exists", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const promise = adapter.insert(insertData); await expect(promise).rejects.toBeDefined(); }); }); describe("method: upsert", () => { test("Should return null when key doesnt exist", async () => { const upsertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; const prevData = await adapter.upsert(upsertData); expect(prevData).toBeNull(); }); test("Should return previous key expiration when key exist", async () => { const upsertData1 = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.upsert(upsertData1); const upsertData2 = { key: "a", value: 2, expiration: TimeSpan.fromMilliseconds(50).toEndDate(), }; const prevData = await adapter.upsert(upsertData2); const result = { expiration: upsertData1.expiration, }; expect({ expiration: prevData?.expiration }).toStrictEqual(result); }); test("Should persist insertion when key doesnt exist", async () => { const upsertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.upsert(upsertData); const findData = await adapter.find(upsertData.key); const result = { value: upsertData.value, expiration: upsertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should persist update when key exist", async () => { const upsertData1 = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.upsert(upsertData1); const upsertData2 = { key: "a", value: 2, expiration: TimeSpan.fromMilliseconds(50).toEndDate(), }; await adapter.upsert(upsertData2); const findData = await adapter.find(upsertData2.key); const result = { value: upsertData2.value, expiration: upsertData2.expiration, }; expect(findData).toStrictEqual(result); }); }); describe("method: updateExpired", () => { test("Should not persist update when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, expiration: null, }; await adapter.updateExpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: insertData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 0 when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, expiration: null, }; const result = await adapter.updateExpired(updateData); expect(result).toBe(0); }); test("Should not persist update when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, expiration: null, }; await adapter.updateExpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: insertData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 0 update when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, expiration: null, }; const result = await adapter.updateExpired(updateData); expect(result).toBe(0); }); test("Should persist update when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, expiration: null, }; await adapter.updateExpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: updateData.value, expiration: updateData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 1 update when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, expiration: null, }; const result = await adapter.updateExpired(updateData); expect(result).toBe(1); }); }); describe("method: updateUnexpired", () => { test("Should persist update when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; await adapter.updateUnexpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: updateData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 1 when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; const result = await adapter.updateUnexpired(updateData); expect(result).toBe(1); }); test("Should persist update when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; await adapter.updateUnexpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: updateData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 1 update when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; const result = await adapter.updateUnexpired(updateData); expect(result).toBe(1); }); test("Should not persist update when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; await adapter.updateUnexpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: insertData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 0 update when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; const result = await adapter.updateUnexpired(updateData); expect(result).toBe(0); }); }); describe("method: incrementUnexpired", () => { test("Should persist update when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; await adapter.incrementUnexpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: insertData.value + updateData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 1 when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; const result = await adapter.incrementUnexpired(updateData); expect(result).toBe(1); }); test("Should persist update when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; await adapter.incrementUnexpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: insertData.value + updateData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 1 update when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; const result = await adapter.incrementUnexpired(updateData); expect(result).toBe(1); }); test("Should not persist update when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; await adapter.incrementUnexpired(updateData); const findData = await adapter.find(updateData.key); const result = { value: insertData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 0 update when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); const updateData = { key: "a", value: 2, }; const result = await adapter.incrementUnexpired(updateData); expect(result).toBe(0); }); test("Should throw an error when incrementing a number error", async () => { await adapter.insert({ key: "a", value: "A", expiration: null, }); const promise = adapter.incrementUnexpired({ key: "a", value: 2, }); await expect(promise).rejects.toBeDefined(); }); }); describe("method: removeExpiredMany", () => { test("Should not persist removal when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); await adapter.removeExpiredMany([insertData.key]); const findData = await adapter.find(insertData.key); const result = { value: insertData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 0 when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); const result = await adapter.removeExpiredMany([insertData.key]); expect(result).toBe(0); }); test("Should not persist removal when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); await adapter.removeExpiredMany([insertData.key]); const findData = await adapter.find(insertData.key); const result = { value: insertData.value, expiration: insertData.expiration, }; expect(findData).toStrictEqual(result); }); test("Should return 0 removal when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); const result = await adapter.removeExpiredMany([insertData.key]); expect(result).toBe(0); }); test("Should persist removal when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); await adapter.removeExpiredMany([insertData.key]); const findData = await adapter.find(insertData.key); expect(findData).toBeNull(); }); test("Should return number of removed keys when all keys has expiration and are expired", async () => { const insertData1 = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; const insertData2 = { key: "b", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData1); await adapter.insert(insertData2); const result = await adapter.removeExpiredMany([ insertData1.key, insertData2.key, ]); expect(result).toBe(2); }); }); describe("method: removeUnexpiredMany", () => { test("Should persist removal when key has no expiration", async () => { const insertData = { key: "a", value: 1, expiration: null, }; await adapter.insert(insertData); await adapter.removeUnexpiredMany([insertData.key]); const findData = await adapter.find(insertData.key); expect(findData).toBeNull(); }); test("Should return number of removed keys when all keys has no expiration", async () => { const insertData1 = { key: "a", value: 1, expiration: null, }; const insertData2 = { key: "b", value: 1, expiration: null, }; await adapter.insert(insertData1); await adapter.insert(insertData2); const result = await adapter.removeUnexpiredMany([ insertData1.key, insertData2.key, ]); expect(result).toBe(2); }); test("Should persist removal when key has expiration but not expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData); await adapter.removeUnexpiredMany([insertData.key]); const findData = await adapter.find(insertData.key); expect(findData).toBeNull(); }); test("Should return number of removed keys when all key has expiration but not expired", async () => { const insertData1 = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; const insertData2 = { key: "b", value: 1, expiration: TimeSpan.fromMilliseconds(25).toEndDate(), }; await adapter.insert(insertData1); await adapter.insert(insertData2); const result = await adapter.removeUnexpiredMany([ insertData1.key, insertData2.key, ]); expect(result).toBe(2); }); test("Should not persist removal when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); await adapter.removeUnexpiredMany([insertData.key]); const findData = await adapter.find(insertData.key); const result = { expiration: insertData.expiration, value: insertData.value, }; expect(findData).toStrictEqual(result); }); test("Should return 0 removal when key has expiration and expired", async () => { const insertData = { key: "a", value: 1, expiration: TimeSpan.fromMilliseconds(25).toStartDate(), }; await adapter.insert(insertData); const result = await adapter.removeUnexpiredMany([insertData.key]); expect(result).toBe(0); }); }); describe("method: removeAll", () => { test("Should remove all keys", async () => { await adapter.insert({ key: "cache/a", value: 1, expiration: null, }); await adapter.insert({ key: "cache/b", value: 2, expiration: null, }); await adapter.insert({ key: "c", value: 3, expiration: null, }); await adapter.removeAll(); expect([ await adapter.find("cache/a"), await adapter.find("cache/b"), await adapter.find("c"), ]).toEqual([null, null, null]); }); }); describe("method: removeByKeyPrefix", () => { test("Should remove the keys that mathc the prefix", async () => { await adapter.insert({ key: "cache/a", value: 1, expiration: null, }); await adapter.insert({ key: "cache/b", value: 2, expiration: null, }); await adapter.insert({ key: "c", value: 3, expiration: null, }); await adapter.removeByKeyPrefix("cache"); const result = [ await adapter.find("cache/a"), await adapter.find("cache/b"), await adapter.find("c"), ]; expect(result).toStrictEqual([ null, null, { value: 3, expiration: null, }, ]); }); }); } //# sourceMappingURL=database-cache-dapter.test-suite.js.map