/** * 간단한 메모리 캐시 구현 * 테이블 타입관리 성능 최적화용 */ interface CacheItem { data: T; timestamp: number; ttl: number; // Time to live in milliseconds } class MemoryCache { private cache = new Map>(); private readonly DEFAULT_TTL = 5 * 60 * 1000; // 5분 /** * 캐시에 데이터 저장 */ set(key: string, data: T, ttl: number = this.DEFAULT_TTL): void { this.cache.set(key, { data, timestamp: Date.now(), ttl, }); } /** * 캐시에서 데이터 조회 */ get(key: string): T | null { const item = this.cache.get(key); if (!item) { return null; } // TTL 체크 if (Date.now() - item.timestamp > item.ttl) { this.cache.delete(key); return null; } return item.data as T; } /** * 캐시에서 데이터 삭제 */ delete(key: string): boolean { return this.cache.delete(key); } /** * 패턴으로 캐시 삭제 (테이블 관련 캐시 일괄 삭제용) */ deleteByPattern(pattern: string): number { let deletedCount = 0; const regex = new RegExp(pattern); for (const key of this.cache.keys()) { if (regex.test(key)) { this.cache.delete(key); deletedCount++; } } return deletedCount; } /** * 만료된 캐시 정리 */ cleanup(): number { let cleanedCount = 0; const now = Date.now(); for (const [key, item] of this.cache.entries()) { if (now - item.timestamp > item.ttl) { this.cache.delete(key); cleanedCount++; } } return cleanedCount; } /** * 캐시 통계 */ getStats(): { totalKeys: number; expiredKeys: number; memoryUsage: string; } { const now = Date.now(); let expiredKeys = 0; for (const item of this.cache.values()) { if (now - item.timestamp > item.ttl) { expiredKeys++; } } return { totalKeys: this.cache.size, expiredKeys, memoryUsage: `${Math.round(JSON.stringify([...this.cache.entries()]).length / 1024)} KB`, }; } /** * 전체 캐시 초기화 */ clear(): void { this.cache.clear(); } } // 싱글톤 인스턴스 export const cache = new MemoryCache(); // 캐시 키 생성 헬퍼 export const CacheKeys = { TABLE_LIST: "table_list", TABLE_COLUMNS: (tableName: string, page: number, size: number) => `table_columns:${tableName}:${page}:${size}`, TABLE_COLUMN_COUNT: (tableName: string) => `table_column_count:${tableName}`, WEB_TYPE_OPTIONS: "web_type_options", COMMON_CODES: (category: string) => `common_codes:${category}`, } as const; // 자동 정리 스케줄러 (10분마다) setInterval( () => { const cleaned = cache.cleanup(); if (cleaned > 0) { console.log(`[Cache] 만료된 캐시 ${cleaned}개 정리됨`); } }, 10 * 60 * 1000 ); export default cache;