Query cache — cache database query results.
1const Redis = require("ioredis");2const redis = new Redis();34class QueryCache {5 constructor(options = {}) {6 this.prefix = options.prefix || "query:";7 this.defaultTTL = options.ttl || 300;8 }910 generateKey(query, params) {11 const hash = require("crypto")12 .createHash("md5")13 .update(JSON.stringify({ query, params }))14 .digest("hex");15 return `${this.prefix}${hash}`;16 }1718 async get(query, params) {19 const key = this.generateKey(query, params);20 const cached = await redis.get(key);21 return cached ? JSON.parse(cached) : null;22 }2324 async set(query, params, data, ttl) {25 const key = this.generateKey(query, params);26 await redis.setEx(key, ttl || this.defaultTTL, JSON.stringify(data));27 }2829 async invalidate(pattern) {30 const keys = await redis.keys(`${this.prefix}${pattern}`);31 if (keys.length) await redis.del(...keys);32 }33}3435// Wrap database queries36const queryCache = new QueryCache({ ttl: 600 });3738async function cachedQuery(query, params, options = {}) {39 const cached = await queryCache.get(query, params);40 if (cached) return cached;4142 const result = await db.query(query, params);43 await queryCache.set(query, params, result.rows, options.ttl);44 return result.rows;45}4647// Usage48const users = await cachedQuery(49 "SELECT * FROM users WHERE active = $1",50 [true]51);5253// Invalidate on write54app.post("/users", async (req, res) => {55 await db.query("INSERT INTO users ...", []);56 await queryCache.invalidate("users*");57 res.json({ ok: true });58});