UNPKG

@ticatec/redis-client

Version:

A lightweight TypeScript wrapper around ioredis with singleton pattern support, mock Redis for testing, and abstract caching framework.

260 lines 8.64 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const ioredis_1 = __importDefault(require("ioredis")); const log4js_1 = __importDefault(require("log4js")); /** * Redis客户端工具 - 基于ioredis的轻量级封装 * 提供单例模式的Redis客户端,支持真实Redis和Mock Redis切换 * @class RedisClient */ class RedisClient { constructor(conf) { this.logger = log4js_1.default.getLogger('RedisClient'); if (conf != null) { this.logger.debug('redis 服务器参数:', conf); this._client = new ioredis_1.default(conf); this._client.on('error', (err) => this.logger.log('Redis Client Error', err)); this._client.on('connect', () => this.logger.log('Connecting the redis server...')); this._client.on('ready', () => this.logger.log('Connected the redis server.')); this._client.on('end', () => this.logger.log('Connection is broken from redis server')); this._client.on('reconnecting', (err) => this.logger.log('Try to reconnect the redis server...')); } else { this.logger.debug('使用模拟redis'); const MockRedis = require('ioredis-mock'); this._client = new MockRedis(); } } /** * 初始化Redis连接 * @static * @param {any} conf - Redis配置参数,传入null时使用Mock Redis * @returns {Promise<void>} */ static async init(conf) { if (RedisClient.instance == null) { RedisClient.instance = new RedisClient(conf); } } /** * 获取Redis客户端实例 * @readonly * @type {Redis} * @returns {Redis} ioredis客户端实例 */ get client() { return this._client; } /** * 获取RedisClient单例实例 * @static * @returns {RedisClient} RedisClient实例 * @throws {Error} 如果未先调用init方法初始化 */ static getInstance() { return RedisClient.instance; } /** * 设置一个键值对 * @param {string} key - Redis键名 * @param {any} value - 要存储的值,对象类型会自动JSON序列化 * @param {number} [seconds=0] - 过期时间(秒),0表示永不过期 * @returns {Promise<void>} */ async set(key, value, seconds = 0) { if (typeof value == "object") { value = JSON.stringify(value); } if (seconds == null || seconds == 0) { await this._client.set(key, value); } else { await this._client.set(key, value, 'EX', seconds); } } /** * 获取指定键的值 * @param {string} key - Redis键名 * @returns {Promise<string | Buffer | number | null>} 键对应的值,不存在时返回null */ get(key) { return this._client.get(key); } /** * 获取指定键的值并解析为JSON对象 * @param {string} key - Redis键名 * @returns {Promise<any>} 解析后的对象,解析失败或不存在时返回null */ async getObject(key) { let text = await this.get(key); let result = null; if (text != null && typeof text == "string") { try { result = JSON.parse(text); } catch (ex) { this.logger.debug(`${text} is not a json string.`); } } return result; } /** * 删除指定的键 * @param {string} key - 要删除的Redis键名 * @returns {Promise<void>} */ async del(key) { await this._client.del(key); } /** * 设置键的过期时间 * @param {string} key - Redis键名 * @param {number} seconds - 过期时间(秒) * @returns {Promise<void>} */ async expiry(key, seconds) { await this._client.expire(key, seconds); } /** * 设置哈希表字段 * @param {string} key - Redis键名 * @param {any} data - 哈希表数据对象 * @param {number} [seconds=0] - 过期时间(秒),0表示永不过期 * @returns {Promise<void>} */ async hset(key, data, seconds = 0) { await this._client.hset(key, data); if (seconds != null && seconds > 0) { await this.expiry(key, seconds); } } /** * 获取哈希表中指定字段的值 * @param {string} key - Redis键名 * @param {string} name - 哈希表字段名 * @returns {Promise<string | null>} 字段值,不存在时返回null */ async hget(key, name) { return this._client.hget(key, name); } /** * 获取哈希表中所有字段和值 * @param {string} key - Redis键名 * @returns {Promise<Record<string, string>>} 包含所有字段和值的对象 */ async hgetall(key) { return this._client.hgetall(key); } /** * 仅在字段不存在时设置哈希表字段值 * @param {string} key - Redis键名 * @param {string} name - 哈希表字段名 * @param {string | Buffer | number} value - 字段值 * @returns {Promise<void>} */ async hsetnx(key, name, value) { await this._client.hsetnx(key, name, value); } /** * 向集合添加成员 * @param {string} key - Redis键名 * @param {Array<string | Buffer | number>} arr - 要添加的成员数组 * @param {number} seconds - 过期时间(秒),大于0时设置过期时间 * @returns {Promise<void>} */ async sadd(key, arr, seconds) { await this._client.sadd(key, arr); if (seconds > 0) { await this.expiry(key, seconds); } } /** * 获取集合中成员的数量 * @param {string} key - Redis键名 * @returns {Promise<number>} 集合成员数量 */ async scard(key) { return this._client.scard(key); } /** * 检查值是否为集合成员 * @param {string} key - Redis键名 * @param {any} value - 要检查的值 * @returns {Promise<boolean>} 是否为集合成员 */ async isSetMember(key, value) { return await this._client.sismember(key, value) == 1; } /** * 向列表尾部添加元素 * @param {string} key - Redis键名 * @param {any} data - 要添加的数据,对象类型会自动JSON序列化 * @param {number} [seconds=0] - 过期时间(秒),0表示永不过期 * @returns {Promise<void>} */ async rpush(key, data, seconds = 0) { if (typeof data == "object") { data = JSON.stringify(data); } await this._client.rpush(key, data); if (seconds > 0) { await this.expiry(key, seconds); } } /** * 获取列表指定范围的元素 * @param {string} key - Redis键名 * @param {number} start - 开始索引 * @param {number} end - 结束索引(-1表示最后一个元素) * @returns {Promise<string[]>} 指定范围的元素数组 */ async lrange(key, start, end) { return this._client.lrange(key, start, end); } /** * 获取列表指定范围的元素并解析为JSON对象 * @param {string} key - Redis键名 * @param {number} start - 开始索引 * @param {number} end - 结束索引(-1表示最后一个元素) * @returns {Promise<Array<any>>} 解析后的对象数组 */ async lrangeObject(key, start, end) { let arr = await this._client.lrange(key, start, end); let list = []; for (let item of arr) { if (typeof item == "string") { try { list.push(JSON.parse(item)); } catch (ex) { this.logger.warn(`${item} is not a json string`); } } else { list.push(item); } } return list; } /** * 获取列表长度 * @param {string} key - Redis键名 * @returns {Promise<number>} 列表长度 */ async llen(key) { return this._client.llen(key); } /** * 移除并返回列表的第一个元素 * @param {string} key - Redis键名 * @returns {Promise<string | null>} 被移除的元素,列表为空时返回null */ async lpop(key) { return this._client.lpop(key); } } exports.default = RedisClient; //# sourceMappingURL=RedisClient.js.map