@silverwind/ioredis-mock
Version:
This library emulates ioredis by performing all operations in-memory.
164 lines (125 loc) • 6.27 kB
JavaScript
"use strict";
var _events = require("events");
var _redisCommands = _interopRequireDefault(require("redis-commands"));
var commands = _interopRequireWildcard(require("./commands"));
var commandsStream = _interopRequireWildcard(require("./commands-stream"));
var _command = _interopRequireWildcard(require("./command"));
var _data = _interopRequireDefault(require("./data"));
var _expires = _interopRequireDefault(require("./expires"));
var _emitConnectEvent = _interopRequireDefault(require("./commands-utils/emitConnectEvent"));
var _pipeline = _interopRequireDefault(require("./pipeline"));
var _promiseContainer = _interopRequireDefault(require("./promise-container"));
var _keyspaceNotifications = _interopRequireDefault(require("./keyspace-notifications"));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/* eslint-disable max-classes-per-file */
const defaultOptions = {
data: {},
keyPrefix: '',
lazyConnect: false,
notifyKeyspaceEvents: '' // string pattern as specified in https://redis.io/topics/notifications#configuration e.g. 'gxK'
};
class RedisMock extends _events.EventEmitter {
static get Promise() {
return _promiseContainer.default.get();
}
static set Promise(lib) {
return _promiseContainer.default.set(lib);
}
constructor(options = {}) {
super();
this.channels = new _events.EventEmitter();
this.patternChannels = new _events.EventEmitter();
this.batch = undefined;
this.connected = false;
this.subscriberMode = false;
this.customCommands = {}; // a mapping of sha1<string>:script<string>, used by evalsha command
this.shaScripts = {}; // eslint-disable-next-line prefer-object-spread
const optionsWithDefault = Object.assign({}, defaultOptions, options);
this.expires = (0, _expires.default)(optionsWithDefault.keyPrefix);
this.data = (0, _data.default)(this.expires, optionsWithDefault.data, optionsWithDefault.keyPrefix);
this._initCommands();
this.keyspaceEvents = (0, _keyspaceNotifications.default)(optionsWithDefault.notifyKeyspaceEvents);
if (optionsWithDefault.lazyConnect === false) {
this.connected = true;
(0, _emitConnectEvent.default)(this);
}
}
multi(batch = []) {
this.batch = new _pipeline.default(this); // eslint-disable-next-line no-underscore-dangle
this.batch._transactions += 1;
batch.forEach(([command, ...options]) => this.batch[command](...options));
return this.batch;
}
pipeline(batch = []) {
this.batch = new _pipeline.default(this);
batch.forEach(([command, ...options]) => this.batch[command](...options));
return this.batch;
}
exec(callback) {
const Promise = _promiseContainer.default.get();
if (!this.batch) {
return Promise.reject(new Error('ERR EXEC without MULTI'));
}
const pipeline = this.batch;
this.batch = undefined;
return pipeline.exec(callback);
}
createConnectedClient(options = {}) {
const mock = new RedisMock(options);
mock.expires = typeof options.keyPrefix === 'string' ? this.expires.withKeyPrefix(options.keyPrefix) : this.expires;
mock.data = typeof options.keyPrefix === 'string' ? this.data.withKeyPrefix(options.keyPrefix) : this.data;
mock.channels = this.channels;
mock.patternChannels = this.patternChannels;
return mock;
} // eslint-disable-next-line class-methods-use-this
disconnect() {
const removeFrom = ({
instanceListeners
}) => {
if (!instanceListeners) {
return;
}
instanceListeners.forEach(mapOfInstanceToListener => {
mapOfInstanceToListener.forEach((listener, instance) => {
if (instance === this) {
mapOfInstanceToListener.delete(instance);
}
});
});
};
removeFrom(this.channels);
removeFrom(this.patternChannels); // no-op
}
_initCommands() {
Object.keys(commands).forEach(command => {
const commandName = command === 'evaluate' ? 'eval' : command;
this[commandName] = (0, _command.default)(commands[command].bind(this), commandName, this);
});
Object.keys(commandsStream).forEach(command => {
this[command] = commandsStream[command].bind(this);
});
const supportedCommands = [..._redisCommands.default.list, ..._redisCommands.default.list.map(command => `${command}Buffer`)];
const docsLink = 'https://github.com/stipsan/ioredis-mock/blob/master/compat.md#supported-commands-';
supportedCommands.forEach(command => {
if (!(command in this)) {
Object.defineProperty(this, command, {
value: () => {
throw new TypeError(`Unsupported command: ${JSON.stringify(command)}, please check the full list over mocked commands: ${docsLink}`);
},
writable: false
});
}
});
}
}
RedisMock.Command = _command.Command;
RedisMock.Cluster = class RedisClusterMock extends RedisMock {
constructor(nodesOptions) {
super();
this.nodes = [];
nodesOptions.forEach(options => this.nodes.push(new RedisMock(options)));
}
};
module.exports = RedisMock;