Spaces:
Sleeping
Sleeping
File size: 2,760 Bytes
05c5ed5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | import Redis, { type RedisOptions } from "ioredis";
import { Cache } from "./cache.interface";
import logger from "logger";
export interface RedisCacheOptions {
redis?: Redis;
redisUrl?: string;
redisOptions?: RedisOptions;
defaultTtlMs?: number;
keyPrefix?: string;
}
export class RedisCache implements Cache {
private redis: Redis;
private defaultTtlMs: number;
private keyPrefix: string;
constructor(options: RedisCacheOptions = {}) {
logger.info("RedisCache constructor");
if (options.redis) {
this.redis = options.redis;
} else if (options.redisUrl) {
this.redis = new Redis(options.redisUrl, options.redisOptions || {});
} else {
this.redis = new Redis(options.redisOptions || {});
}
this.defaultTtlMs = options.defaultTtlMs ?? Infinity;
this.keyPrefix = options.keyPrefix ?? "";
}
private getKey(key: string): string {
return this.keyPrefix + key;
}
async get<T>(key: string): Promise<T | undefined> {
const value = await this.redis.get(this.getKey(key));
if (!value) return undefined;
try {
return JSON.parse(value) as T;
} catch {
return value as T;
}
}
async set(key: string, value: unknown, ttlMs?: number): Promise<void> {
const ttl = ttlMs ?? this.defaultTtlMs;
const serialized = JSON.stringify(value);
if (isFinite(ttl)) {
await this.redis.psetex(this.getKey(key), ttl, serialized);
} else {
await this.redis.set(this.getKey(key), serialized);
}
}
async has(key: string): Promise<boolean> {
const exists = await this.redis.exists(this.getKey(key));
return exists === 1;
}
async delete(key: string): Promise<void> {
await this.redis.del(this.getKey(key));
}
async clear(): Promise<void> {
if (this.keyPrefix) {
const keys = await this.redis.keys(this.keyPrefix + "*");
if (keys.length > 0) {
await this.redis.del(...keys);
}
} else {
await this.redis.flushdb();
}
}
async getAll(): Promise<Map<string, unknown>> {
const result = new Map<string, unknown>();
const pattern = this.keyPrefix ? this.keyPrefix + "*" : "*";
const keys = await this.redis.keys(pattern);
if (keys.length === 0) return result;
const values = await this.redis.mget(...keys);
keys.forEach((key, index) => {
const value = values[index];
if (value !== null) {
const cleanKey = this.keyPrefix
? key.slice(this.keyPrefix.length)
: key;
try {
result.set(cleanKey, JSON.parse(value));
} catch {
result.set(cleanKey, value);
}
}
});
return result;
}
async disconnect(): Promise<void> {
this.redis.disconnect();
}
}
|