mastercache
Version:
Multi-tier cache module for Node.js. Redis, Upstash, CloudfareKV, File, in-memory and others drivers
131 lines (114 loc) • 2.86 kB
text/typescript
import { LRUCache } from 'lru-cache';
import { BaseDriver } from './base-driver';
import type {
CreateDriverResult,
L1CacheDriver,
MemoryConfig as MemoryConfig,
} from '../types/main';
/**
* A memory caching driver
*/
export class MemoryDriver extends BaseDriver implements L1CacheDriver {
type = 'l1' as const;
#cache: LRUCache<string, string>;
declare config: MemoryConfig;
constructor(config: MemoryConfig & { cacheInstance?: LRUCache<string, string> } = {}) {
super(config);
if (config.cacheInstance) {
this.#cache = config.cacheInstance;
return;
}
this.#cache = new LRUCache({
max: config.maxItems ?? 1000,
maxEntrySize: config.maxEntrySize,
ttlAutopurge: true,
...(config.maxSize
? {
maxSize: config.maxSize,
sizeCalculation: (value) => Buffer.byteLength(value, 'utf-8'),
}
: {}),
});
}
/**
* Returns a new instance of the driver namespaced
*/
namespace(namespace: string) {
return new MemoryDriver({
...this.config,
cacheInstance: this.#cache,
prefix: this.createNamespacePrefix(namespace),
});
}
/**
* Get a value from the cache
*/
get(key: string) {
return this.#cache.get(this.getItemKey(key));
}
/**
* Get the value of a key and delete it
*
* Returns the value if the key exists, undefined otherwise
*/
pull(key: string) {
if (!this.has(key)) return undefined;
const value = this.get(key);
this.delete(key);
return value;
}
/**
* Put a value in the cache
* Returns true if the value was set, false otherwise
*/
set(key: string, value: string, ttl?: number) {
this.#cache.set(this.getItemKey(key), value, { ttl });
return true;
}
/**
* Returns the remaining ttl of a key
*/
getRemainingTtl(key: string) {
return this.#cache.getRemainingTTL(this.getItemKey(key));
}
/**
* Check if a key exists in the cache
*/
has(key: string) {
return this.#cache.has(this.getItemKey(key));
}
/**
* Remove all items from the cache
*/
async clear() {
for (const key of this.#cache.keys()) {
if (key.startsWith(this.prefix)) {
this.#cache.delete(key);
}
}
}
/**
* Delete a key from the cache
* Returns true if the key was deleted, false otherwise
*/
delete(key: string) {
return this.#cache.delete(this.getItemKey(key));
}
/**
* Delete multiple keys from the cache
*/
deleteMany(keys: string[]) {
for (const key of keys) this.delete(key);
return true;
}
async disconnect() {}
}
/**
* Create a new memory driver
*/
export function memoryDriver(options: MemoryConfig = {}): CreateDriverResult<MemoryDriver> {
return {
options,
factory: (config: MemoryConfig) => new MemoryDriver(config),
};
}