import { Injectable, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import Redis from 'ioredis'; @Injectable() export class CacheService implements OnModuleInit { private redis: Redis; constructor(private configService: ConfigService) {} onModuleInit() { const redisUrl = this.configService.get('REDIS_URL', 'redis://localhost:6379'); this.redis = new Redis(redisUrl); } async get(key: string): Promise { const value = await this.redis.get(key); return value ? JSON.parse(value) : null; } async set(key: string, value: any, ttlSeconds?: number): Promise { const serialized = JSON.stringify(value); if (ttlSeconds) { await this.redis.setex(key, ttlSeconds, serialized); } else { await this.redis.set(key, serialized); } } async del(key: string): Promise { await this.redis.del(key); } async delPattern(pattern: string): Promise { const keys = await this.redis.keys(pattern); if (keys.length > 0) { await this.redis.del(...keys); } } async exists(key: string): Promise { return (await this.redis.exists(key)) === 1; } // Cache key builders for consistency buildKey(prefix: string, userId: string, ...parts: string[]): string { return [prefix, userId, ...parts].join(':'); } // Common cache patterns async getOrSet( key: string, fetcher: () => Promise, ttlSeconds: number = 300, ): Promise { const cached = await this.get(key); if (cached !== null) { return cached; } const fresh = await fetcher(); await this.set(key, fresh, ttlSeconds); return fresh; } }