/** * Cache em memória com TTL. * * Simples, sem dependências externas. Usado para evitar consultas repetidas * ao banco para dados que mudam raramente (ex: configurações da empresa). * * Uso: * const cache = require('../services/cacheService'); * let valor = cache.get('chave'); * if (!valor) { * valor = await db.query(...); * cache.set('chave', valor, 60000); // TTL 60s * } */ const store = new Map(); /** * Armazena um valor no cache. * @param {string} key * @param {*} value * @param {number} [ttlMs=60000] - Tempo de vida em ms (padrão: 1 minuto) */ function set(key, value, ttlMs = 60000) { store.set(key, { value, expiresAt: Date.now() + ttlMs, }); } /** * Recupera um valor do cache. Retorna undefined se expirado ou inexistente. * @param {string} key * @returns {*|undefined} */ function get(key) { const entry = store.get(key); if (!entry) return undefined; if (Date.now() > entry.expiresAt) { store.delete(key); return undefined; } return entry.value; } /** * Invalida uma chave específica. * @param {string} key */ function del(key) { store.delete(key); } /** * Invalida todas as chaves que começam com o prefixo. * Útil para invalidar todo o cache de uma empresa (ex: 'config:5:'). * @param {string} prefix */ function delByPrefix(prefix) { for (const key of store.keys()) { if (key.startsWith(prefix)) { store.delete(key); } } } /** * Retorna estatísticas do cache para debug. */ function stats() { let total = 0, valid = 0; const now = Date.now(); for (const [, entry] of store) { total++; if (entry.expiresAt > now) valid++; } return { total, valid, expired: total - valid }; } // Limpeza periódica de entradas expiradas (evita vazamento de memória) const intervalo = setInterval(() => { const now = Date.now(); for (const [key, entry] of store) { if (entry.expiresAt <= now) store.delete(key); } }, 60000); if (intervalo.unref) intervalo.unref(); module.exports = { set, get, del, delByPrefix, stats };