UNPKG

nestjs-redis-plus

Version:
314 lines (313 loc) 10.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; var __param = (this && this.__param) || function (paramIndex, decorator) { return function (target, key) { decorator(target, key, paramIndex); } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.RedisService = void 0; const core_1 = require("@nestjs/core"); const common_1 = require("@nestjs/common"); const redis_constants_1 = require("./redis.constants"); let RedisService = class RedisService { clientName; moduleRef; redis; constructor(clientName, moduleRef) { this.clientName = clientName; this.moduleRef = moduleRef; } onModuleInit() { this.redis = this.moduleRef.get(this.clientName); } get client() { return this.redis; } get keyPrefix() { return this.redis.options.keyPrefix; } // Keys toInt(value, radix = 10) { if (!value) return 0; const int = parseInt(value, radix); if (isNaN(int)) return null; return int; } toFloat(value) { if (!value) return 0; const float = parseFloat(value); if (isNaN(float)) return null; return float; } setKey(key, value) { return this.redis.set(key, value); } setKeys(map) { return this.redis.mset(map); } getKey(key) { return this.redis.get(key); } getAndSetKey(key, value) { return this.redis.getset(key, value); } getAndDeleteKey(key) { return this.redis.getdel(key); } getAndExpireKey(key, ttl) { return this.redis.getex(key, "EX", ttl); } async getKeys(keys) { const values = await this.redis.mget(keys); return new Map(keys.map((key, index) => [key, values[index]])); } delKey(key) { return this.redis.del(key); } delKeys(keys) { return this.redis.del(keys); } keyExists(key) { return this.redis.exists(key); } setJSONKey(key, value) { return this.redis.set(key, JSON.stringify(value)); } async getJSONKey(key) { const value = await this.redis.get(key); return value ? JSON.parse(value) : null; } async getIntKey(key, radix, isStrict) { const value = await this.redis.get(key); const int = this.toInt(value, radix); if (isStrict && int === null) throw new Error(`"${key}" is not an int: ${value}`); return int; } async getFloatKey(key, isStrict) { const value = await this.redis.get(key); const float = this.toFloat(value); if (isStrict && float === null) throw new Error(`"${key}" is not a float: ${value}`); return float; } async scanKeys(pattern, count = 100, includeKeyPrefix = true) { const keys = []; const match = includeKeyPrefix ? `${this.keyPrefix}${pattern}` : pattern; const cursor = this.redis.scanStream({ match, count }); for await (const matches of cursor) keys.push(...matches); return keys; } async expireKey(key, ttl) { const isExpired = await this.redis.expire(key, ttl); return isExpired === 1; } async setAndExpireKey(key, value, ttl) { const isSet = await this.redis.set(key, value, "EX", ttl); return isSet === "OK"; } async lockKey(key) { const isLocked = await this.redis.set(key, "locked", "NX"); return isLocked === "OK"; } async isKeyLocked(key, ensure) { if (!ensure) return this.keyExists(key); const value = await this.getKey(key); return value === "locked"; } unlockKey(key) { return this.delKey(key); } async lockAndExpireKey(key, ttl) { const isLocked = await this.redis.set(key, "locked", "EX", ttl, "NX"); return isLocked === "OK"; } async refreshKeyLock(key, ttl) { const isRefreshed = await this.redis.set(key, "locked", "EX", ttl, "XX"); return isRefreshed === "OK"; } incrKey(key) { return this.redis.incr(key); } incrKeyBy(key, increment) { return this.redis.incrby(key, increment); } async incrKeyByFloat(key, increment) { const result = await this.redis.incrbyfloat(key, increment); return parseFloat(result); } decrKey(key) { return this.redis.decr(key); } decrKeyBy(key, decrement) { return this.redis.decrby(key, decrement); } // Maps setMap(key, map) { return this.redis.hmset(key, map); } async getMap(key) { const records = await this.getMapAsObject(key); return new Map(Object.entries(records)); } async getMapAsObject(key) { const records = await this.redis.hgetall(key); return records; } getMapKeys(key) { return this.redis.hkeys(key); } getMapValues(key) { return this.redis.hvals(key); } setField(key, field, value) { return this.redis.hset(key, field, value); } setFields(key, fields) { return this.redis.hmset(key, fields); } getField(key, field) { return this.redis.hget(key, field); } getFields(key, fields) { return this.redis.hmget(key, ...fields); } delField(key, field) { return this.redis.hdel(key, field); } delFields(key, fields) { return this.redis.hdel(key, ...fields); } fieldExists(key, field) { return this.redis.hexists(key, field); } async getIntField(key, field, radix, isStrict) { const value = await this.getField(key, field); const int = this.toInt(value, radix); if (isStrict && int === null) throw new Error(`"${key}.${field}" is not an int: ${value}`); return int; } async getFloatField(key, field, isStrict) { const value = await this.getField(key, field); const float = this.toFloat(value); if (isStrict && float === null) throw new Error(`"${key}.${field}" is not a float: ${value}`); return float; } async scanMap(key, pattern, count = 100, includeKeyPrefix = true) { const fields = []; const match = includeKeyPrefix ? `${this.keyPrefix}${pattern}` : pattern; const cursor = this.redis.hscanStream(key, { match, count }); for await (const matches of cursor) fields.push(...matches); return fields; } async lockField(key, field) { const isLocked = await this.redis.hsetnx(key, field, "locked"); return isLocked === 1; } async isFieldLocked(key, field, ensure) { if (!ensure) return this.fieldExists(key, field); const value = await this.getField(key, field); return value === "locked"; } unlockField(key, field) { return this.delField(key, field); } incrFieldBy(key, field, increment) { return this.redis.hincrby(key, field, increment); } async incrFieldByFloat(key, field, increment) { const result = await this.redis.hincrbyfloat(key, field, increment); return parseFloat(result); } // Sets async getSet(key) { const members = await this.redis.smembers(key); return new Set(members); } async getIntSet(key, radix, isStrict) { const members = await this.redis.smembers(key); const ints = members.flatMap((member, idx) => { const int = this.toInt(member, radix); if (isStrict && int === null) throw new Error(`"${key}[${idx}]" is not an int: ${member}`); return int; }); return new Set(ints); } async getFloatSet(key, isStrict) { const members = await this.redis.smembers(key); const floats = members .flatMap((member, idx) => { const float = parseFloat(member); if (isStrict && float === null) throw new Error(`"${key}[${idx}]" is not a float: ${member}`); return float; }) .sort((a, b) => a - b); return new Set(floats); } async scanSet(key, pattern, count = 100, includeKeyPrefix = true) { const members = []; const match = includeKeyPrefix ? `${this.keyPrefix}${pattern}` : pattern; const cursor = this.redis.sscanStream(key, { match, count, }); for await (const matches of cursor) members.push(...matches); return members; } async addToSet(key, values, isStrict) { const added = await this.redis.sadd(key, values); if (isStrict && added !== values.length) throw new Error(`Only ${added} of ${values.length} were added to "${key}"`); return added; } async removeFromSet(key, values, isStrict) { const removed = await this.redis.srem(key, values); if (isStrict && removed !== values.length) throw new Error(`Only ${removed} of ${values.length} were removed from "${key}"`); return removed; } countSet(key) { return this.redis.scard(key); } async isMemberOfSet(key, member) { const isMember = await this.redis.sismember(key, member); return isMember === 1; } async areMembersOfSet(key, members, returnType) { const replies = await this.redis.smismember(key, members); if (returnType) return replies.flatMap((reply, idx) => { if ((returnType === "included" && reply === 0) || (returnType === "excluded" && reply === 1)) return []; return [members[idx]]; }); return replies.every((reply) => reply === 1); } }; RedisService = __decorate([ (0, common_1.Injectable)(), __param(0, (0, common_1.Inject)(redis_constants_1.REDIS_NAME_TOKEN)), __metadata("design:paramtypes", [String, core_1.ModuleRef]) ], RedisService); exports.RedisService = RedisService;