UNPKG

@silverwind/ioredis-mock

Version:

This library emulates ioredis by performing all operations in-memory.

164 lines (125 loc) 6.27 kB
"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;