From 72a7e2a2ecf704fb60927edb81fa5de7c8b5ac33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=90=E9=AA=85?= Date: Fri, 19 Oct 2018 23:05:55 +0800 Subject: [PATCH] refactor: migrate script to TypeScript (#735) --- lib/cluster/index.ts | 2 +- lib/command.js | 306 ---------------------------------- lib/command.ts | 331 +++++++++++++++++++++++++++++++++++++ lib/commander.js | 4 +- lib/index.js | 2 +- lib/pipeline.js | 2 +- lib/redis.js | 2 +- lib/redis/event_handler.js | 2 +- lib/redis/parser.js | 2 +- lib/script.js | 48 ------ lib/script.ts | 49 ++++++ test/functional/exports.js | 2 +- test/unit/command.js | 2 +- 13 files changed, 390 insertions(+), 364 deletions(-) delete mode 100644 lib/command.js create mode 100644 lib/command.ts delete mode 100644 lib/script.js create mode 100644 lib/script.ts diff --git a/lib/cluster/index.ts b/lib/cluster/index.ts index 234821ac..a5f16bbe 100644 --- a/lib/cluster/index.ts +++ b/lib/cluster/index.ts @@ -13,12 +13,12 @@ import {CallbackFunction} from '../types'; import {IClusterOptions, DEFAULT_CLUSTER_OPTIONS} from './ClusterOptions' import {sample, CONNECTION_CLOSED_ERROR_MSG, shuffle, timeout, zipMap} from '../utils' import * as commands from 'redis-commands' +import Command from '../command' const Deque = require('denque') const Redis = require('../redis') const debug = require('../utils/debug')('ioredis:cluster') const Commander = require('../commander') -const Command = require('../command') type ClusterStatus = 'end' | 'close' | 'wait' | 'connecting' | 'connect' | 'ready' | 'reconnecting' | 'disconnecting' diff --git a/lib/command.js b/lib/command.js deleted file mode 100644 index a92b9d4e..00000000 --- a/lib/command.js +++ /dev/null @@ -1,306 +0,0 @@ -'use strict'; - -var _ = require('./utils/lodash'); -var fbuffer = require('flexbuffer'); -var utils = require('./utils'); -var commands = require('redis-commands'); -var calculateSlot = require('cluster-key-slot'); -var PromiseContainer = require('./promiseContainer'); -var asCallback = require('standard-as-callback'); - -/** - * Command instance - * - * It's rare that you need to create a Command instance yourself. - * - * @constructor - * @param {string} name - Command name - * @param {string[]} [args=null] - An array of command arguments - * @param {object} [options] - * @param {string} [options.replyEncoding=null] - Set the encoding of the reply, - * by default buffer will be returned. - * @param {function} [callback=null] - The callback that handles the response. - * If omit, the response will be handled via Promise. - * @example - * ```js - * var infoCommand = new Command('info', null, function (err, result) { - * console.log('result', result); - * }); - * - * redis.sendCommand(infoCommand); - * - * // When no callback provided, Command instance will have a `promise` property, - * // which will resolve/reject with the result of the command. - * var getCommand = new Command('get', ['foo']); - * getCommand.promise.then(function (result) { - * console.log('result', result); - * }); - * ``` - * - * @see {@link Redis#sendCommand} which can send a Command instance to Redis - * @public - */ -function Command(name, args, options, callback) { - if (typeof options === 'undefined') { - options = {}; - } - this.name = name; - this.replyEncoding = options.replyEncoding; - this.errorStack = options.errorStack; - this.args = args ? _.flatten(args) : []; - this.callback = callback; - this.initPromise(); - - var keyPrefix = options.keyPrefix; - if (keyPrefix) { - this._iterateKeys(function (key) { - return keyPrefix + key; - }); - } -} - -Command.prototype.initPromise = function () { - var _this = this; - var Promise = PromiseContainer.get(); - var promise = new Promise(function (resolve, reject) { - if (!_this.transformed) { - _this.transformed = true; - var transformer = Command._transformer.argument[_this.name]; - if (transformer) { - _this.args = transformer(_this.args); - } - _this.stringifyArguments(); - } - - _this.resolve = _this._convertValue(resolve); - if (_this.errorStack) { - _this.reject = function (err) { - reject(utils.optimizeErrorStack(err, _this.errorStack, __dirname)); - }; - } else { - _this.reject = reject; - } - }); - - this.promise = asCallback(promise, this.callback); -}; - -Command.prototype.getSlot = function () { - if (typeof this._slot === 'undefined') { - var key = this.getKeys()[0]; - if (key == null) { - this.slot = null; - } else { - this.slot = calculateSlot(key); - } - } - return this.slot; -}; - -Command.prototype.getKeys = function () { - return this._iterateKeys(); -}; - -/** - * Iterate through the command arguments that are considered keys. - * - * @param {function} [transform] - The transformation that should be applied to - * each key. The transformations will persist. - * @return {string[]} The keys of the command. - * @private - */ -Command.prototype._iterateKeys = function (transform) { - if (typeof this._keys === 'undefined') { - if (typeof transform !== 'function') { - transform = function (key) { - return key; - }; - } - this._keys = []; - if (commands.exists(this.name)) { - var keyIndexes = commands.getKeyIndexes(this.name, this.args); - for (var i = 0; i < keyIndexes.length; i++) { - var index = keyIndexes[i]; - this.args[index] = transform(this.args[index]); - this._keys.push(this.args[index]); - } - } - } - return this._keys; -}; - -/** - * Convert command to writable buffer or string - * - * @return {string|Buffer} - * @see {@link Redis#sendCommand} - * @public - */ -Command.prototype.toWritable = function () { - var bufferMode = false; - var i; - for (i = 0; i < this.args.length; ++i) { - if (this.args[i] instanceof Buffer) { - bufferMode = true; - break; - } - } - - var result, arg; - var commandStr = '*' + (this.args.length + 1) + '\r\n$' + this.name.length + '\r\n' + this.name + '\r\n'; - if (bufferMode) { - var resultBuffer = new fbuffer.FlexBuffer(0); - resultBuffer.write(commandStr); - for (i = 0; i < this.args.length; ++i) { - arg = this.args[i]; - if (arg instanceof Buffer) { - if (arg.length === 0) { - resultBuffer.write('$0\r\n\r\n'); - } else { - resultBuffer.write('$' + arg.length + '\r\n'); - resultBuffer.write(arg); - resultBuffer.write('\r\n'); - } - } else { - resultBuffer.write('$' + Buffer.byteLength(arg) + '\r\n' + arg + '\r\n'); - } - } - result = resultBuffer.getBuffer(); - } else { - result = commandStr; - for (i = 0; i < this.args.length; ++i) { - result += '$' + Buffer.byteLength(this.args[i]) + '\r\n' + this.args[i] + '\r\n'; - } - } - return result; -}; - -Command.prototype.stringifyArguments = function () { - for (var i = 0; i < this.args.length; ++i) { - if (!(this.args[i] instanceof Buffer) && typeof this.args[i] !== 'string') { - this.args[i] = utils.toArg(this.args[i]); - } - } -}; - -/** - * Convert the value from buffer to the target encoding. - * - * @param {function} resolve - The resolve function of the Promise - * @return {function} A funtion to transform and resolve a value - * @private - */ -Command.prototype._convertValue = function (resolve) { - var _this = this; - return function (value) { - try { - resolve(_this.transformReply(value)); - } catch (err) { - _this.reject(err); - } - return _this.promise; - }; -}; - -/** - * Convert buffer/buffer[] to string/string[], - * and apply reply transformer. - * - * @public - */ -Command.prototype.transformReply = function (result) { - if (this.replyEncoding) { - result = utils.convertBufferToString(result, this.replyEncoding); - } - var transformer = Command._transformer.reply[this.name]; - if (transformer) { - result = transformer(result); - } - - return result; -}; - -Command.FLAGS = { - // Commands that can be processed when client is in the subscriber mode - VALID_IN_SUBSCRIBER_MODE: ['subscribe', 'psubscribe', 'unsubscribe', 'punsubscribe', 'ping', 'quit'], - // Commands that are valid in monitor mode - VALID_IN_MONITOR_MODE: ['monitor', 'auth'], - // Commands that will turn current connection into subscriber mode - ENTER_SUBSCRIBER_MODE: ['subscribe', 'psubscribe'], - // Commands that may make current connection quit subscriber mode - EXIT_SUBSCRIBER_MODE: ['unsubscribe', 'punsubscribe'], - // Commands that will make client disconnect from server TODO shutdown? - WILL_DISCONNECT: ['quit'] -}; - -var flagMap = Object.keys(Command.FLAGS).reduce(function (map, flagName) { - map[flagName] = {}; - Command.FLAGS[flagName].forEach(function (commandName) { - map[flagName][commandName] = true; - }); - return map; -}, {}); - -/** - * Check whether the command has the flag - * - * @param {string} flagName - * @param {string} commandName - * @return {boolean} - */ -Command.checkFlag = function (flagName, commandName) { - return !!flagMap[flagName][commandName]; -}; - -Command._transformer = { - argument: {}, - reply: {} -}; - -Command.setArgumentTransformer = function (name, func) { - Command._transformer.argument[name] = func; -}; - -Command.setReplyTransformer = function (name, func) { - Command._transformer.reply[name] = func; -}; - -var msetArgumentTransformer = function (args) { - if (args.length === 1) { - if (typeof Map !== 'undefined' && args[0] instanceof Map) { - return utils.convertMapToArray(args[0]); - } - if (typeof args[0] === 'object' && args[0] !== null) { - return utils.convertObjectToArray(args[0]); - } - } - return args; -}; - -Command.setArgumentTransformer('mset', msetArgumentTransformer); -Command.setArgumentTransformer('msetnx', msetArgumentTransformer); - -Command.setArgumentTransformer('hmset', function (args) { - if (args.length === 2) { - if (typeof Map !== 'undefined' && args[1] instanceof Map) { - return [args[0]].concat(utils.convertMapToArray(args[1])); - } - if (typeof args[1] === 'object' && args[1] !== null) { - return [args[0]].concat(utils.convertObjectToArray(args[1])); - } - } - return args; -}); - -Command.setReplyTransformer('hgetall', function (result) { - if (Array.isArray(result)) { - var obj = {}; - for (var i = 0; i < result.length; i += 2) { - obj[result[i]] = result[i + 1]; - } - return obj; - } - return result; -}); - -module.exports = Command; diff --git a/lib/command.ts b/lib/command.ts new file mode 100644 index 00000000..b21612e2 --- /dev/null +++ b/lib/command.ts @@ -0,0 +1,331 @@ +import * as fbuffer from 'flexbuffer' +import * as commands from 'redis-commands' +import * as calculateSlot from 'cluster-key-slot' +import * as asCallback from 'standard-as-callback' +import {convertBufferToString, optimizeErrorStack, toArg, convertMapToArray, convertObjectToArray} from './utils' +import {flatten} from './utils/lodash' +import {get as getPromise} from './promiseContainer' + +interface ICommandOptions { + /** + * Set the encoding of the reply, by default buffer will be returned. + * + * @type {(string | null)} + * @memberof ICommandOptions + */ + replyEncoding?: string | null, + errorStack?: string, + keyPrefix?: string +} + +type ArgumentTransformer = (args: any[]) => any[] +type ReplyTransformer = (reply: any) => any +type FlagMap = {[flag: string]: {[command: string]: true}} + +/** + * Command instance + * + * It's rare that you need to create a Command instance yourself. + * + * @export + * @class Command + * + * @example + * ```js + * var infoCommand = new Command('info', null, function (err, result) { + * console.log('result', result); + * }); + * + * redis.sendCommand(infoCommand); + * + * // When no callback provided, Command instance will have a `promise` property, + * // which will resolve/reject with the result of the command. + * var getCommand = new Command('get', ['foo']); + * getCommand.promise.then(function (result) { + * console.log('result', result); + * }); + * ``` + * @see {@link Redis#sendCommand} which can send a Command instance to Redis + */ +export default class Command { + public static FLAGS = { + // Commands that can be processed when client is in the subscriber mode + VALID_IN_SUBSCRIBER_MODE: ['subscribe', 'psubscribe', 'unsubscribe', 'punsubscribe', 'ping', 'quit'], + // Commands that are valid in monitor mode + VALID_IN_MONITOR_MODE: ['monitor', 'auth'], + // Commands that will turn current connection into subscriber mode + ENTER_SUBSCRIBER_MODE: ['subscribe', 'psubscribe'], + // Commands that may make current connection quit subscriber mode + EXIT_SUBSCRIBER_MODE: ['unsubscribe', 'punsubscribe'], + // Commands that will make client disconnect from server TODO shutdown? + WILL_DISCONNECT: ['quit'] + } + + private static flagMap?: FlagMap + + private static getFlagMap (): FlagMap { + if (!this.flagMap) { + this.flagMap = Object.keys(Command.FLAGS).reduce((map, flagName) => { + map[flagName] = {} + Command.FLAGS[flagName].forEach((commandName) => { + map[flagName][commandName] = true + }) + return map + }, {}) + } + return this.flagMap + } + + /** + * Check whether the command has the flag + * + * @param {string} flagName + * @param {string} commandName + * @return {boolean} + */ + public static checkFlag (flagName: string, commandName: string): boolean { + return !!this.getFlagMap()[flagName][commandName] + } + + private static _transformer: { + argument: {[command: string]: ArgumentTransformer}, + reply: {[command: string]: ReplyTransformer} + } = { + argument: {}, + reply: {} + }; + + public static setArgumentTransformer (name: string, func: ArgumentTransformer) { + this._transformer.argument[name] = func + } + + public static setReplyTransformer (name: string, func: ReplyTransformer) { + this._transformer.reply[name] = func + } + + private replyEncoding: string | null + private errorStack: string + private args: Array + private callback: Function + private transformed: boolean = false + public isCustomCommand: boolean = false + + private slot?: number | null + private keys?: Array + + public reject: (err: Error) => void + public resolve: (result: any) => void + public promise: Promise + + /** + * Creates an instance of Command. + * @param {string} name Command name + * @param {(Array)} [args=[]] An array of command arguments + * @param {ICommandOptions} [options={}] + * @param {Function} [callback] The callback that handles the response. + * If omit, the response will be handled via Promise + * @memberof Command + */ + constructor (public name: string, args: Array = [], options: ICommandOptions = {}, callback?: Function) { + this.replyEncoding = options.replyEncoding + this.errorStack = options.errorStack + + this.args = flatten(args) + this.callback = callback + + this.initPromise() + + if (options.keyPrefix) { + this._iterateKeys((key) => ( + options.keyPrefix + key + )) + } + } + + private initPromise () { + const Promise = getPromise() + const promise = new Promise((resolve, reject) => { + if (!this.transformed) { + this.transformed = true + const transformer = Command._transformer.argument[this.name] + if (transformer) { + this.args = transformer(this.args) + } + this.stringifyArguments() + } + + this.resolve = this._convertValue(resolve) + if (this.errorStack) { + this.reject = (err) => { + reject(optimizeErrorStack(err, this.errorStack, __dirname)) + } + } else { + this.reject = reject + } + }) + + this.promise = asCallback(promise, this.callback) + } + + public getSlot () { + if (typeof this.slot === 'undefined') { + const key = this.getKeys()[0] + this.slot = key == null ? null : calculateSlot(key) + } + return this.slot + } + + public getKeys (): Array { + return this._iterateKeys() + } + + /** + * Iterate through the command arguments that are considered keys. + * + * @param {Function} [transform=(key) => key] The transformation that should be applied to + * each key. The transformations will persist. + * @returns {string[]} The keys of the command. + * @memberof Command + */ + private _iterateKeys (transform: Function = (key) => key): Array { + if (typeof this.keys === 'undefined') { + this.keys = [] + if (commands.exists(this.name)) { + const keyIndexes = commands.getKeyIndexes(this.name, this.args) + for (const index of keyIndexes) { + this.args[index] = transform(this.args[index]) + this.keys.push(this.args[index] as string | Buffer) + } + } + } + return this.keys + } + + /** + * Convert command to writable buffer or string + * + * @return {string|Buffer} + * @see {@link Redis#sendCommand} + * @public + */ + public toWritable (): string | Buffer { + let bufferMode = false; + for (const arg of this.args) { + if (arg instanceof Buffer) { + bufferMode = true; + break; + } + } + + let result + let commandStr = '*' + (this.args.length + 1) + '\r\n$' + this.name.length + '\r\n' + this.name + '\r\n' + if (bufferMode) { + const resultBuffer = new fbuffer.FlexBuffer(0) + resultBuffer.write(commandStr) + for (const arg of this.args) { + if (arg instanceof Buffer) { + if (arg.length === 0) { + resultBuffer.write('$0\r\n\r\n') + } else { + resultBuffer.write('$' + arg.length + '\r\n') + resultBuffer.write(arg) + resultBuffer.write('\r\n') + } + } else { + resultBuffer.write('$' + Buffer.byteLength(arg as string | Buffer) + '\r\n' + arg + '\r\n') + } + } + result = resultBuffer.getBuffer() + } else { + result = commandStr + for (const arg of this.args) { + result += '$' + Buffer.byteLength(arg as string | Buffer) + '\r\n' + arg + '\r\n' + } + } + return result + } + + stringifyArguments (): void { + for (let i = 0; i < this.args.length; ++i) { + const arg = this.args[i] + if (!(arg instanceof Buffer) && typeof arg !== 'string') { + this.args[i] = toArg(arg) + } + } + } + + /** + * Convert the value from buffer to the target encoding. + * + * @private + * @param {Function} resolve The resolve function of the Promise + * @returns {Function} A funtion to transform and resolve a value + * @memberof Command + */ + private _convertValue (resolve: Function): (result: any) => void { + return (value) => { + try { + resolve(this.transformReply(value)) + } catch (err) { + this.reject(err) + } + return this.promise + } + } + + /** + * Convert buffer/buffer[] to string/string[], + * and apply reply transformer. + * + * @memberof Command + */ + public transformReply (result: Buffer | Buffer[]): string | string[] | Buffer | Buffer[] { + if (this.replyEncoding) { + result = convertBufferToString(result, this.replyEncoding) + } + const transformer = Command._transformer.reply[this.name] + if (transformer) { + result = transformer(result) + } + + return result + } +} + +const msetArgumentTransformer = function (args) { + if (args.length === 1) { + if (typeof Map !== 'undefined' && args[0] instanceof Map) { + return convertMapToArray(args[0]); + } + if (typeof args[0] === 'object' && args[0] !== null) { + return convertObjectToArray(args[0]); + } + } + return args; +}; + +Command.setArgumentTransformer('mset', msetArgumentTransformer) +Command.setArgumentTransformer('msetnx', msetArgumentTransformer) + +Command.setArgumentTransformer('hmset', function (args) { + if (args.length === 2) { + if (typeof Map !== 'undefined' && args[1] instanceof Map) { + return [args[0]].concat(convertMapToArray(args[1])) + } + if (typeof args[1] === 'object' && args[1] !== null) { + return [args[0]].concat(convertObjectToArray(args[1])) + } + } + return args +}) + +Command.setReplyTransformer('hgetall', function (result) { + if (Array.isArray(result)) { + var obj = {} + for (var i = 0; i < result.length; i += 2) { + obj[result[i]] = result[i + 1] + } + return obj + } + return result +}) diff --git a/lib/commander.js b/lib/commander.js index 69a9a520..8fad08d0 100644 --- a/lib/commander.js +++ b/lib/commander.js @@ -1,8 +1,8 @@ 'use strict'; var _ = require('./utils/lodash'); -var Command = require('./command'); -var Script = require('./script'); +var Command = require('./command').default; +var Script = require('./script').default; var PromiseContainer = require('./promiseContainer'); var asCallback = require('standard-as-callback'); diff --git a/lib/index.js b/lib/index.js index 48aa3dde..e6ff1f9c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -4,7 +4,7 @@ exports = module.exports = require('./redis'); exports.ReplyError = require('redis-errors').ReplyError; exports.Cluster = require('./cluster').default; -exports.Command = require('./command'); +exports.Command = require('./command').default; exports.ScanStream = require('./ScanStream').default; exports.Pipeline = require('./pipeline'); diff --git a/lib/pipeline.js b/lib/pipeline.js index 5068eba8..29a14779 100644 --- a/lib/pipeline.js +++ b/lib/pipeline.js @@ -1,7 +1,7 @@ 'use strict'; var _ = require('./utils/lodash'); var Commander = require('./commander'); -var Command = require('./command'); +var Command = require('./command').default; var fbuffer = require('flexbuffer'); var util = require('util'); var asCallback = require('standard-as-callback'); diff --git a/lib/redis.js b/lib/redis.js index 0a03ab76..7b4d11c0 100644 --- a/lib/redis.js +++ b/lib/redis.js @@ -4,7 +4,7 @@ var _ = require('./utils/lodash'); var util = require('util'); var EventEmitter = require('events').EventEmitter; var Deque = require('denque'); -var Command = require('./command'); +var Command = require('./command').default; var Commander = require('./commander'); var utils = require('./utils'); var asCallback = require('standard-as-callback'); diff --git a/lib/redis/event_handler.js b/lib/redis/event_handler.js index e7e2140e..3235764e 100644 --- a/lib/redis/event_handler.js +++ b/lib/redis/event_handler.js @@ -1,7 +1,7 @@ 'use strict'; var debug = require('../utils/debug')('ioredis:connection'); -var Command = require('../command'); +var Command = require('../command').default; var utils = require('../utils'); var _ = require('../utils/lodash'); var {MaxRetriesPerRequestError} = require('../errors') diff --git a/lib/redis/parser.js b/lib/redis/parser.js index 9f533fb2..5948b040 100644 --- a/lib/redis/parser.js +++ b/lib/redis/parser.js @@ -1,7 +1,7 @@ 'use strict'; var _ = require('../utils/lodash'); -var Command = require('../command'); +var Command = require('../command').default; var SubscriptionSet = require('../SubscriptionSet').default; var debug = require('../utils/debug')('ioredis:reply'); var Parser = require('redis-parser'); diff --git a/lib/script.js b/lib/script.js deleted file mode 100644 index b026ce05..00000000 --- a/lib/script.js +++ /dev/null @@ -1,48 +0,0 @@ -'use strict'; - -var Command = require('./command'); -var crypto = require('crypto'); -var PromiseContainer = require('./promiseContainer') -var asCallback = require('standard-as-callback'); - -function Script(lua, numberOfKeys, keyPrefix) { - this.lua = lua; - this.sha = crypto.createHash('sha1').update(this.lua).digest('hex'); - this.numberOfKeys = typeof numberOfKeys === 'number' ? numberOfKeys : null; - this.keyPrefix = keyPrefix ? keyPrefix : ''; -} - -Script.prototype.execute = function (container, args, options, callback) { - if (typeof this.numberOfKeys === 'number') { - args.unshift(this.numberOfKeys); - } - if (this.keyPrefix) { - options.keyPrefix = this.keyPrefix; - } - - var evalsha = new Command('evalsha', [this.sha].concat(args), options); - evalsha.isCustomCommand = true; - var result = container.sendCommand(evalsha); - if (PromiseContainer.isPromise(result)) { - var _this = this; - return asCallback( - result.catch(function (err) { - if (err.toString().indexOf('NOSCRIPT') === -1) { - throw err; - } - return container.sendCommand( - new Command('eval', [_this.lua].concat(args), options) - ); - }), - callback - ) - } - - // result is not a Promise--probably returned from a pipeline chain; however, - // we still need the callback to fire when the script is evaluated - asCallback(evalsha.promise, callback) - - return result; -}; - -module.exports = Script; diff --git a/lib/script.ts b/lib/script.ts new file mode 100644 index 00000000..26d1b5b8 --- /dev/null +++ b/lib/script.ts @@ -0,0 +1,49 @@ +import {createHash} from 'crypto' +import {isPromise} from './promiseContainer' +import Command from './command' +import * as asCallback from 'standard-as-callback' + +export default class Script { + private sha: string + + constructor ( + private lua: string, + private numberOfKeys: number = null, + private keyPrefix: string = '' + ) { + this.sha = createHash('sha1').update(lua).digest('hex') + } + + execute (container: any, args: any[], options: any, callback?: Function) { + if (typeof this.numberOfKeys === 'number') { + args.unshift(this.numberOfKeys) + } + if (this.keyPrefix) { + options.keyPrefix = this.keyPrefix + } + + const evalsha = new Command('evalsha', [this.sha].concat(args), options) + evalsha.isCustomCommand = true + + const result = container.sendCommand(evalsha) + if (isPromise(result)) { + return asCallback( + result.catch((err) => { + if (err.toString().indexOf('NOSCRIPT') === -1) { + throw err + } + return container.sendCommand( + new Command('eval', [this.lua].concat(args), options) + ) + }), + callback + ) + } + + // result is not a Promise--probably returned from a pipeline chain; however, + // we still need the callback to fire when the script is evaluated + asCallback(evalsha.promise, callback) + + return result + } +} diff --git a/test/functional/exports.js b/test/functional/exports.js index fcccd8d1..f83571e7 100644 --- a/test/functional/exports.js +++ b/test/functional/exports.js @@ -1,7 +1,7 @@ describe('exports', function () { describe('.Command', function () { it('should be `Command`', function () { - var Command = require('../../lib/command'); + var Command = require('../../lib/command').default; expect(Redis.Command).to.eql(Command); }); }); diff --git a/test/unit/command.js b/test/unit/command.js index c0af7f52..ef1b9e16 100644 --- a/test/unit/command.js +++ b/test/unit/command.js @@ -1,6 +1,6 @@ 'use strict'; -var Command = require('../../lib/command'); +var Command = require('../../lib/command').default; describe('Command', function () { describe('constructor()', function () {