UNPKG

johnycash

Version:

Easy distributed caching for Node.js

766 lines 23.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RedisCacheService = void 0; const util_1 = require("util"); class RedisCacheService { constructor(redis, logger) { this.asyncMulti = async (commands) => { const multi = this.redis.multi(commands); const data = await (0, util_1.promisify)(multi.exec).call(multi); return data; }; this.redis = redis; this.logger = logger || console; } async get(key) { try { const data = await this.redis.get(key); if (data) { return JSON.parse(data); } } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to get from redis cache.', { cacheKey: key, error: error?.toString(), }); } } finally { } return undefined; } async getMany(keys) { try { const items = await this.redis.mget(keys); const values = items.map(item => item ? JSON.parse(item) : null); return values; } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to get many keys from redis cache.', { cacheKeys: keys, exception: error?.toString(), }); } return []; } finally { } } async setnx(key, value, cacheNullable = true) { try { if (!cacheNullable && value == null) { return false; } const result = await this.redis.setnx(key, JSON.stringify(value)); return result === 1; } finally { } } async set(key, value, ttl = null, cacheNullable = true) { if (value === undefined) { return; } if (!cacheNullable && value == null) { return; } if (typeof ttl === 'number' && ttl <= 0) { return; } try { if (!ttl) { await this.redis.set(key, JSON.stringify(value)); } else { await this.redis.set(key, JSON.stringify(value), 'EX', ttl); } } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to set in redis cache.', { cacheKey: key, error: error?.toString(), }); } } finally { } } async setMany(keys, values, ttl, cacheNullable = true) { try { let commands = []; if (!cacheNullable) { commands = keys.map((key, index) => { if (values[index] == null) { return []; } return ['set', key, JSON.stringify(values[index]), 'EX', ttl.toString()]; }); commands = commands.filter(command => command.length !== 0); } else { commands = keys.map((key, index) => { return ['set', key, JSON.stringify(values[index]), 'EX', ttl.toString()]; }); } await this.asyncMulti(commands); } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to set many in redis cache.', { cacheKey: keys, error: error?.toString(), }); } } finally { } } async expire(key, ttl) { await this.redis.expire(key, ttl); } async pexpire(key, ttl) { await this.redis.pexpire(key, ttl); } async delete(key) { try { await this.redis.del(key); } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to delete from redis cache.', { cacheKey: key, error: error?.toString(), }); } } finally { } } async deleteMany(keys) { try { await this.redis.del(keys); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to delete multiple keys from redis cache.', { error: error?.toString(), }); } } finally { } } async deleteByPattern(keyPattern) { try { const stream = this.redis.scanStream({ match: keyPattern, count: 10, }); const dels = await new Promise((resolve, reject) => { let delKeys = []; stream.on('data', function (resultKeys) { delKeys = [...delKeys, ...resultKeys.map((key) => ['del', key])]; }); stream.on('end', () => { resolve(delKeys); }); stream.on('error', (err) => { reject(err); }); }); await this.asyncMulti(dels); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to delete from redis cache by pattern.', { error: error?.toString(), }); } } finally { } } async flushDb() { try { await this.redis.flushdb(); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to delete multiple keys from redis cache.', { error: error?.toString(), }); } } finally { } } async getOrSet(key, createValueFunc, ttl, cacheNullable = true) { const cachedData = await this.get(key); if (cachedData !== undefined) { return cachedData; } const internalCreateValueFunc = this.buildInternalCreateValueFunc(key, createValueFunc); const value = await internalCreateValueFunc(); await this.set(key, value, ttl, cacheNullable); return value; } async setOrUpdate(key, createValueFunc, ttl, cacheNullable = true) { const internalCreateValueFunc = this.buildInternalCreateValueFunc(key, createValueFunc); const value = await internalCreateValueFunc(); await this.set(key, value, ttl, cacheNullable); return value; } async scan(pattern) { const found = []; let cursor = '0'; do { const reply = await this.redis.scan(cursor, 'MATCH', pattern); cursor = reply[0]; found.push(...reply[1]); } while (cursor !== '0'); return found; } async increment(key, ttl = null) { try { const newValue = await this.redis.incr(key); if (ttl) { await this.expire(key, ttl); } return newValue; } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to increment redis key.', { cacheKey: key, error: error?.toString(), }); } throw error; } finally { } } async incrby(key, value) { try { return await this.redis.incrby(key, value); } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to incrby redis key.', { cacheKey: key, error: error?.toString(), }); } throw error; } finally { } } async decrement(key, ttl = null) { try { const newValue = await this.redis.decr(key); if (ttl) { await this.expire(key, ttl); } return newValue; } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to decrement redis key.', { cacheKey: key, error: error?.toString(), }); } throw error; } finally { } } async hget(hash, field) { try { const data = await this.redis.hget(hash, field); if (data) { return JSON.parse(data); } } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to hget from redis.', { hash, field, exception: error?.toString(), }); } } finally { } return null; } async hgetall(hash) { try { const data = await this.redis.hgetall(hash); if (!data) { return null; } const response = {}; for (const key of Object.keys(data)) { response[key] = JSON.parse(data[key]); } return response; } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to hgetall from redis.', { hash, exception: error?.toString(), }); } } finally { } return null; } async hset(hash, field, value, cacheNullable = true) { try { if (!cacheNullable && value == null) { return 0; } return await this.redis.hset(hash, field, JSON.stringify(value)); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to hset in redis.', { hash, field, value, exception: error?.toString(), }); } throw error; } finally { } } async hsetMany(hash, fieldsValues, cacheNullable = true) { try { const hashMap = new Map(); for (const [field, value] of fieldsValues) { if (!cacheNullable && value == null) { continue; } hashMap.set(field, JSON.stringify(value)); } if (hashMap.size === 0) { return 0; } return await this.redis.hset(hash, hashMap); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to hset many in redis.', { hash, fieldsValues, exception: error?.toString(), }); } throw error; } finally { } } async hincrby(hash, field, value) { try { return await this.redis.hincrby(hash, field, value); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to hincrby in redis.', { hash, field, value, exception: error?.toString(), }); } throw error; } finally { } } async hkeys(hash) { try { return await this.redis.hkeys(hash); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to hkeys in redis.', { hash, exception: error?.toString(), }); } throw error; } finally { } } async zadd(key, member, value, options = []) { try { return await this.redis.zadd(key, ...options, value, member); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to zadd in redis.', { exception: error?.toString(), key, member, value, }); } throw error; } finally { } } async zincrby(key, member, increment) { try { return await this.redis.zincrby(key, increment, member); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to zincrby in redis.', { exception: error?.toString(), key, member, increment, }); } throw error; } finally { } } async zrank(key, member) { try { return await this.redis.zrank(key, member); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to get zrank from redis.', { exception: error?.toString(), key, member, }); } throw error; } finally { } } async keys(key) { try { return await this.redis.keys(key); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to get keys from redis.', { exception: error?.toString(), key, }); } throw error; } finally { } } async zrevrank(key, member) { try { return await this.redis.zrevrank(key, member); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to get zrevrank from redis.', { exception: error?.toString(), key, member, }); } throw error; } finally { } } async sadd(key, ...values) { try { return await this.redis.sadd(key, ...values); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to sadd redis.', { exception: error?.toString(), key, ...values, }); } throw error; } finally { } } async sunionstore(destination, keys) { try { return await this.redis.sunionstore(destination, keys); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to sunionstore in redis.', { destination, keys, exception: error?.toString(), }); } throw error; } finally { } } async smembers(key) { try { return await this.redis.smembers(key); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to smembers in redis.', { exception: error?.toString(), key, }); } throw error; } finally { } } async zrevrange(setName, start, stop, withScores = false) { try { if (withScores) { return await this.redis.zrevrange(setName, start, stop, 'WITHSCORES'); } return await this.redis.zrevrange(setName, start, stop); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to zrevrange in redis.', { exception: error?.toString(), setName, start, stop, withScores, }); } throw error; } finally { } } async zrangebyscore(setName, start, stop, options) { try { if (options?.withScores) { return await this.redis.zrangebyscore(setName, start, stop, 'WITHSCORES'); } return await this.redis.zrangebyscore(setName, start, stop); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to get zrangebyscore in redis.', { exception: error?.toString(), setName, start, stop, options, }); } throw error; } finally { } } async zrange(setName, start, stop, options) { try { if (options?.order === 'REV') { if (options?.withScores) { return await this.redis.zrange(setName, start, stop, 'REV', 'WITHSCORES'); } return await this.redis.zrange(setName, start, stop, 'REV'); } if (options?.withScores) { return await this.redis.zrange(setName, start, stop, 'WITHSCORES'); } return await this.redis.zrange(setName, start, stop); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to get zrange in redis.', { exception: error?.toString(), setName, start, stop, options, }); } throw error; } finally { } } async zmscore(setName, ...args) { try { return await this.redis.zmscore(setName, args); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to zmscore in redis.', { exception: error?.toString(), setName, args, }); } throw error; } finally { } } async scard(key) { try { return await this.redis.scard(key); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to scard in redis.', { exception: error?.toString(), key, }); } throw error; } finally { } } async zcount(key, min, max) { try { return await this.redis.zcount(key, min, max); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to get zcount in redis.', { exception: error?.toString(), key, min, max, }); } throw error; } finally { } } defineCommand(name, definition) { try { return this.redis.defineCommand(name, definition); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to define command in redis.', { exception: error?.toString(), name, definition, }); } throw error; } finally { } } async executeCommand(name, ...args) { try { return await this.redis[name](args); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to execute custom command in redis.', { exception: error?.toString(), name, args, }); } throw error; } finally { } } async rpush(key, items) { try { if (items?.length > 0) { await this.redis.rpush(key, items); } } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to rpush to redis.', { exception: error?.toString(), key, }); } } finally { } } async lrange(key, start = 0, stop = -1) { try { return await this.redis.lrange(key, start, stop); } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to execute lrange into redis.', { exception: error?.toString(), key, }); } throw error; } finally { } } async lpop(key) { const items = []; try { let item; while (item = await this.redis.lpop(key)) { items.push(item); } } catch (error) { if (error instanceof Error) { this.logger.error('An error occurred while trying to lpop to redis.', { exception: error?.toString(), key, }); } } finally { } return items; } buildInternalCreateValueFunc(key, createValueFunc) { return async () => { try { return await createValueFunc(); } catch (error) { if (error instanceof Error) { this.logger.error('RedisCache - An error occurred while trying to load value.', { error: error?.toString(), key, }); } throw error; } }; } } exports.RedisCacheService = RedisCacheService; //# sourceMappingURL=redis-cache.service.js.map