From a2ddeb28c3947f7656964dc37031acd331922677 Mon Sep 17 00:00:00 2001 From: Hazelnoot Date: Wed, 12 Nov 2025 00:48:58 -0500 Subject: [PATCH] separate get into get and getMaybe --- packages/backend/src/core/CacheService.ts | 12 +++++----- packages/backend/src/misc/QuantumKVCache.ts | 22 ++++++++++++++----- .../test/unit/misc/QuantumKVCacheTests.ts | 21 +++++++++++++++++- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/packages/backend/src/core/CacheService.ts b/packages/backend/src/core/CacheService.ts index 73b3b3ceea..e58a012b6a 100644 --- a/packages/backend/src/core/CacheService.ts +++ b/packages/backend/src/core/CacheService.ts @@ -553,7 +553,7 @@ export class CacheService implements OnApplicationShutdown { for (const uid of userIds) { const toAdd: MiUser[] = []; - const userById = this.userByIdCache.get(uid); + const userById = this.userByIdCache.getMaybe(uid); if (userById) toAdd.push(userById); if (toAdd.length > 0) { @@ -670,9 +670,9 @@ export class CacheService implements OnApplicationShutdown { // TODO should we filter for local/remote events? switch (type) { case 'follow': { - const follower = this.userByIdCache.get(body.followerId); + const follower = this.userByIdCache.getMaybe(body.followerId); if (follower) follower.followingCount++; - const followee = this.userByIdCache.get(body.followeeId); + const followee = this.userByIdCache.getMaybe(body.followeeId); if (followee) followee.followersCount++; await Promise.all([ this.userFollowingsCache.delete(body.followerId), @@ -683,9 +683,9 @@ export class CacheService implements OnApplicationShutdown { break; } case 'unfollow': { - const follower = this.userByIdCache.get(body.followerId); + const follower = this.userByIdCache.getMaybe(body.followerId); if (follower) follower.followingCount--; - const followee = this.userByIdCache.get(body.followeeId); + const followee = this.userByIdCache.getMaybe(body.followeeId); if (followee) followee.followersCount--; await Promise.all([ this.userFollowingsCache.delete(body.followerId), @@ -860,7 +860,7 @@ export class CacheService implements OnApplicationShutdown { const followeeId = typeof(followee) === 'string' ? followee : followee.id; // This lets us use whichever one is in memory, falling back to DB fetch via userFollowingsCache. - return this.userFollowersCache.get(followeeId)?.has(followerId) + return this.userFollowersCache.getMaybe(followeeId)?.has(followerId) ?? (await this.userFollowingsCache.fetch(followerId)).has(followeeId); } diff --git a/packages/backend/src/misc/QuantumKVCache.ts b/packages/backend/src/misc/QuantumKVCache.ts index 1f539fc217..72fae7b161 100644 --- a/packages/backend/src/misc/QuantumKVCache.ts +++ b/packages/backend/src/misc/QuantumKVCache.ts @@ -375,12 +375,24 @@ export class QuantumKVCache = Value> implements I } /** - * Gets a value from the local memory cache, or returns undefined if not found. + * Gets a value from the local memory cache, or throws KeyNotFoundError if not found. * Returns cached data only - does not make any fetches. - * TODO separate get/getMaybe */ @bindThis - public get(key: string): T | undefined { + public get(key: string): T { + const result = this.getMaybe(key); + if (result === undefined) { + throw new KeyNotFoundError(this.nameForError, key); + } + return result; + } + + /** + * Gets a value from the local memory cache, or returns undefined if not found. + * Returns cached data only - does not make any fetches. + */ + @bindThis + public getMaybe(key: string): T | undefined { return this.memoryCache.get(key); } @@ -393,7 +405,7 @@ export class QuantumKVCache = Value> implements I public getMany(keys: Iterable): [key: string, value: T | undefined][] { const results: [key: string, value: T | undefined][] = []; for (const key of keys) { - results.push([key, this.get(key)]); + results.push([key, this.getMaybe(key)]); } return results; } @@ -460,7 +472,7 @@ export class QuantumKVCache = Value> implements I // Spliterate into cached results / uncached keys. for (const key of keys) { - const fromCache = this.get(key); + const fromCache = this.getMaybe(key); if (fromCache) { results.push([key, fromCache]); } else { diff --git a/packages/backend/test/unit/misc/QuantumKVCacheTests.ts b/packages/backend/test/unit/misc/QuantumKVCacheTests.ts index 3695489c96..5d9428b6b7 100644 --- a/packages/backend/test/unit/misc/QuantumKVCacheTests.ts +++ b/packages/backend/test/unit/misc/QuantumKVCacheTests.ts @@ -220,10 +220,29 @@ describe(QuantumKVCache, () => { expect(result).toBe('bar'); }); + it('should throw KeyNotFoundError if missing', () => { + const cache = makeCache(); + + assert.throws(KeyNotFoundError, () => { + cache.get('foo'); + }); + }); + }); + + describe('getMaybe', () => { + it('should return value if present', async () => { + const cache = makeCache(); + await cache.set('foo', 'bar'); + + const result = cache.getMaybe('foo'); + + expect(result).toBe('bar'); + }); + it('should return undefined if missing', () => { const cache = makeCache(); - const result = cache.get('foo'); + const result = cache.getMaybe('foo'); expect(result).toBe(undefined); });