Skip to content

Commit

Permalink
Implement in-memory cache
Browse files Browse the repository at this point in the history
  • Loading branch information
maxima-net committed Aug 24, 2022
1 parent bf238a2 commit 52c29cd
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/core/cache/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export type SetCacheOptions = {
absoluteExpirationMs: number;
slidingExpirationMs?: never;
} | {
absoluteExpirationMs?: never;
slidingExpirationMs: number;
};

export interface Cache<K = string> {
get<T = unknown>(key: K): T | undefined;
set(key: K, value: unknown, options?: SetCacheOptions): void;
}
51 changes: 51 additions & 0 deletions src/core/cache/inMemoryCache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { Cache, SetCacheOptions } from './cache';

interface CacheEntry {
value: unknown;
watcherId: ReturnType<typeof setTimeout>;
options: SetCacheOptions;
}

export class InMemoryCache<K = string> implements Cache<K> {
private static readonly defaultCacheOptions: SetCacheOptions = {
absoluteExpirationMs: 1000 * 60 * 30,
};

private readonly cacheMap: Map<K, CacheEntry> = new Map();

constructor(
private readonly defaultCacheOptions: SetCacheOptions = InMemoryCache.defaultCacheOptions
) { }

get<T = unknown>(key: K): T | undefined {
const entry = this.cacheMap.get(key);
if (!entry)
return undefined;

const isSlidingExpiration = this.getTimeoutAndIsSlidingExpiration(entry.options)[1];
if (isSlidingExpiration)
this.set(key, entry.value, entry.options);

return entry.value as T | undefined;
}

set(key: K, value: unknown, options = this.defaultCacheOptions): void {
const oldEntry = this.cacheMap.get(key);
if (oldEntry)
clearTimeout(oldEntry.watcherId);

const [timeout] = this.getTimeoutAndIsSlidingExpiration(options);
const watcherId = setTimeout(() => {
this.cacheMap.delete(key);
}, timeout);

const entry: CacheEntry = { value, watcherId, options };
this.cacheMap.set(key, entry);
}

private getTimeoutAndIsSlidingExpiration(options: SetCacheOptions): [timeout: number, isSlidingExpiration: boolean] {
return options.slidingExpirationMs !== undefined
? [options.slidingExpirationMs, true]
: [options.absoluteExpirationMs, false];
}
}
1 change: 1 addition & 0 deletions src/core/cache/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type { Cache, SetCacheOptions } from './cache';

0 comments on commit 52c29cd

Please sign in to comment.