@onesy/redis
Version:
180 lines (177 loc) • 5.9 kB
JavaScript
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;