UNPKG

@onesy/redis

Version:
180 lines (177 loc) 5.9 kB
import _defineProperty from "@babel/runtime/helpers/defineProperty"; import { createClient } from 'redis'; import merge from '@onesy/utils/merge'; import stringify from '@onesy/utils/stringify'; import parse from '@onesy/utils/parse'; import { ConnectionError } from '@onesy/errors'; import OnesyLog from '@onesy/log'; import OnesySubscription from '@onesy/subscription'; export const optionsDefault = {}; class OnesyRedis { get options() { return this.options_; } set options(options) { this.options_ = merge(options, optionsDefault); this.namespace = this.options.namespace ?? this.namespace; } constructor() { let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : optionsDefault; _defineProperty(this, "client_", void 0); _defineProperty(this, "clientSubscriber", void 0); _defineProperty(this, "connected", false); _defineProperty(this, "namespace", ''); _defineProperty(this, "amalog", void 0); _defineProperty(this, "options_", optionsDefault); // For listening on redis events _defineProperty(this, "subscription", new OnesySubscription()); // alias _defineProperty(this, "set", this.add); // alias _defineProperty(this, "delete", this.remove); // alias _defineProperty(this, "deleteMany", this.removeMany); this.options = options; this.amalog = new OnesyLog({ arguments: { pre: ['Redis'] } }); } async query() { let queryProps = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '*'; const client = await this.client; const query = this.namespace ? `${this.namespace}:${queryProps}` : queryProps; const value = await client.keys(query); return value; } async get(keyProps) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { parse: true }; const client = await this.client; const key = this.namespace ? `${this.namespace}:${keyProps}` : keyProps; const value = await client.get(key); return options.parse ? parse(value) : value; } async add(keyProps, value) { const client = await this.client; const key = this.namespace ? `${this.namespace}:${keyProps}` : keyProps; return client.set(key, value); } async remove(keyProps) { const client = await this.client; const key = this.namespace ? `${this.namespace}:${keyProps}` : keyProps; return client.del(key); } async removeMany(query) { const keys = await this.query(query); return Promise.allSettled((keys || []).map(key => { const keyProp = this.namespace ? key.replace(`${this.namespace}:`, '') : key; return this.remove(keyProp); })); } async subscribe(channels, method, bufferMode) { await this.connection; // we have to separate subscribe, publish client context const client = this.clientSubscriber; return client.subscribe(channels, method, bufferMode); } async unsubscribe(channels, method, bufferMode) { const client = await this.client; return client.unsubscribe(channels, method, bufferMode); } messageData(message) { let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { parse: true }; if (message) { const data = message; return options.parse ? parse(data) : data; } } async publish(channel, data) { let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : { serialize: true }; const client = await this.client; const message = options.serialize ? stringify(data) : data; return client.publish(channel, message); } get client() { return new Promise(async (resolve, reject) => { if (this.connected && this.client_) return resolve(this.client_); try { return resolve(await this.connect()); } catch (error) { throw error; } }); } // alias for the client get connection() { return new Promise(async (resolve, reject) => { if (this.connected && this.client_) return resolve(this.client_); try { return resolve(await this.connect()); } catch (error) { throw error; } }); } get disconnect() { return new Promise(async resolve => { if (this.connected) { try { await this.client_.disconnect(); this.amalog.important(`Disconnected`); this.connected = false; this.client_ = undefined; this.clientSubscriber = undefined; this.subscription.emit('disconnected'); return resolve(); } catch (error) { this.amalog.warn(`Connection close error`, error); this.subscription.emit('disconnect:error', error); throw new ConnectionError(error); } } return resolve(); }); } async connect() { const { uri } = this.options; try { this.client_ = createClient({ url: uri }); await this.client_.connect(); this.clientSubscriber = this.client_.duplicate(); await this.clientSubscriber.connect(); this.amalog.info(`Connected`); this.connected = true; this.subscription.emit('connected'); this.client_.on('end', () => this.amalog.important('Client closed')); return this.client_; } catch (error) { this.amalog.warn(`Connection error`, error); this.connected = false; this.subscription.emit('connect:error', error); throw new ConnectionError(error); } } // Be very careful with this one, // it removes all data in the redis, // usually used for testing only async reset() { if (this.connected) { const client = await this.client; if (client) return client.flushDb(); } this.amalog.important(`All cleaned`); this.subscription.emit('reset'); } } export default OnesyRedis;