Skip to content

Commit bcaf84d

Browse files
committed
cache: add .clear()
1 parent fee00b8 commit bcaf84d

File tree

6 files changed

+93
-0
lines changed

6 files changed

+93
-0
lines changed

packages/cache-redis/src/providers/RedisCacheProvider.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,13 @@ export class RedisCacheProvider implements CacheProvider {
8787
return this.redisProvider.keys(`${this.prefix(name)}:*`);
8888
}
8989

90+
public async clear(): Promise<void> {
91+
this.log.debug("Clearing all cache");
92+
const pattern = `${this.prefix()}:*`;
93+
const keys = await this.redisProvider.keys(pattern);
94+
await this.redisProvider.del(keys);
95+
}
96+
9097
protected prefix(...path: string[]): string {
9198
const parts = ["cache", ...path];
9299

packages/cache-redis/test/cache-redis.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
testCacheInvalidateByKey,
99
testCacheKeys,
1010
testCacheMissingProvider,
11+
testCacheProviderClear,
1112
testCacheReturnTypes,
1213
testCacheStop,
1314
testSimpleKeyMappingHandler,
@@ -61,3 +62,7 @@ test("$cache - keys (redis)", async () => {
6162
test("$cache - unique key with args (redis)", async () => {
6263
await testSimpleKeyMappingHandler();
6364
});
65+
66+
test("$cache - provider clear (redis)", async () => {
67+
await testCacheProviderClear(env(), provider);
68+
});

packages/cache/src/providers/CacheProvider.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,9 @@ export abstract class CacheProvider {
4646
public abstract has(name: string, key: string): Promise<boolean>;
4747

4848
public abstract keys(name: string, filter?: string): Promise<string[]>;
49+
50+
/**
51+
* Remove all keys from all cache names.
52+
*/
53+
public abstract clear(): Promise<void>;
4954
}

packages/cache/src/providers/MemoryCacheProvider.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,20 @@ export class MemoryCacheProvider implements CacheProvider {
100100
}
101101
return keys;
102102
}
103+
104+
public async clear(): Promise<void> {
105+
this.log.debug("Clearing all cache");
106+
107+
// Clear all timeouts before clearing the store
108+
for (const name of Object.keys(this.store)) {
109+
for (const key of Object.keys(this.store[name])) {
110+
const timeout = this.store[name][key]?.timeout;
111+
if (timeout) {
112+
this.dateTimeProvider.clearTimeout(timeout);
113+
}
114+
}
115+
}
116+
117+
this.store = {};
118+
}
103119
}

packages/cache/test/$cache.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
testCacheInvalidateByKey,
1414
testCacheKeys,
1515
testCacheMissingProvider,
16+
testCacheProviderClear,
1617
testCacheReturnTypes,
1718
testCacheStop,
1819
testSimpleKeyMappingHandler,
@@ -102,3 +103,7 @@ test("$cache - unique key", async () => {
102103
test("$cache - unique key with args", async () => {
103104
await testSimpleKeyMappingHandler();
104105
});
106+
107+
test("$cache - provider clear", async () => {
108+
await testCacheProviderClear();
109+
});

packages/cache/test/shared.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,3 +320,58 @@ export const testSimpleKeyMappingHandler = async (
320320
expect(await app.run("B")).toBe("B=2");
321321
expect(await app.run("C")).toBe("C=3");
322322
};
323+
324+
export const testCacheProviderClear = async (
325+
env: Env = {},
326+
cacheProvider: Service<CacheProvider> = MemoryCacheProvider,
327+
): Promise<void> => {
328+
class TestClearCache {
329+
cursor_a = 0;
330+
cursor_b = 0;
331+
332+
a = $cache({
333+
key: (args) => args.name,
334+
ttl: [5, "seconds"],
335+
handler: async (user: { name: string }) => {
336+
return `${user.name}:${this.cursor_a++}`;
337+
},
338+
});
339+
340+
b = $cache({
341+
key: (args) => args.name,
342+
handler: async (user: { name: string }) => {
343+
return `${user.name}:${this.cursor_b++}`;
344+
},
345+
});
346+
}
347+
348+
const app = Alepha.create({
349+
env,
350+
}).with({
351+
provide: CacheProvider,
352+
use: cacheProvider,
353+
});
354+
355+
const test = app.inject(TestClearCache);
356+
const provider = app.inject(CacheProvider);
357+
await app.start();
358+
359+
// Set some cache values
360+
expect(await test.a({ name: "A" })).toBe("A:0");
361+
expect(await test.a({ name: "A" })).toBe("A:0");
362+
expect(await test.a({ name: "B" })).toBe("B:1");
363+
expect(await test.b({ name: "C" })).toBe("C:0");
364+
expect(await test.b({ name: "C" })).toBe("C:0");
365+
366+
// Verify cache is working
367+
expect(await test.a({ name: "A" })).toBe("A:0");
368+
expect(await test.b({ name: "C" })).toBe("C:0");
369+
370+
// Clear all cache
371+
await provider.clear();
372+
373+
// Verify cache was cleared - new values should be generated
374+
expect(await test.a({ name: "A" })).toBe("A:2");
375+
expect(await test.a({ name: "B" })).toBe("B:3");
376+
expect(await test.b({ name: "C" })).toBe("C:1");
377+
};

0 commit comments

Comments
 (0)