diff --git a/index.js b/index.js index 811312d9b5..f0c220bf00 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,6 @@ var default_port = 6379; var default_host = '127.0.0.1'; function noop () {} -function clone (obj) { return JSON.parse(JSON.stringify(obj || {})); } function debug (msg) { if (exports.debug_mode) { console.error(msg); } } function handle_detect_buffers_reply (reply, command, buffer_args) { @@ -35,7 +34,7 @@ exports.debug_mode = /\bredis\b/i.test(process.env.NODE_DEBUG); function RedisClient (options) { // Copy the options so they are not mutated - options = clone(options); + options = utils.clone(options); events.EventEmitter.call(this); var cnx_options = {}; var self = this; @@ -205,8 +204,8 @@ RedisClient.prototype.cork = noop; RedisClient.prototype.uncork = noop; RedisClient.prototype.duplicate = function (options) { - var existing_options = clone(this.options); - options = clone(options); + var existing_options = utils.clone(this.options); + options = utils.clone(options); for (var elem in options) { // jshint ignore: line existing_options[elem] = options[elem]; } @@ -1293,11 +1292,11 @@ Multi.prototype.exec = Multi.prototype.EXEC = Multi.prototype.exec_batch = funct var createClient = function (port_arg, host_arg, options) { if (typeof port_arg === 'number' || typeof port_arg === 'string' && /^\d+$/.test(port_arg)) { - options = clone(options); + options = utils.clone(options); options.host = host_arg; options.port = port_arg; } else if (typeof port_arg === 'string' || port_arg && port_arg.url) { - options = clone(port_arg.url ? port_arg : host_arg || options); + options = utils.clone(port_arg.url ? port_arg : host_arg || options); var parsed = URL.parse(port_arg.url || port_arg, true, true); // [redis:]//[[user][:password]@][host][:port][/db-number][?db=db-number[&password=bar[&option=value]]] if (parsed.hostname || parsed.slashes) { // The host might be an empty string @@ -1326,7 +1325,7 @@ var createClient = function (port_arg, host_arg, options) { options.path = port_arg; } } else if (typeof port_arg === 'object' || port_arg === undefined) { - options = clone(port_arg || options); + options = utils.clone(port_arg || options); options.host = options.host || host_arg; } if (!options) { diff --git a/lib/utils.js b/lib/utils.js index 9fbb22cb60..8cdfb1f2b5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -38,9 +38,36 @@ function print (err, reply) { var redisErrCode = /^([A-Z]+)\s+(.+)$/; +// Deep clone arbitrary objects with arrays. Can't handle cyclic structures (results in a range error) +function clone (obj) { + if (obj) { + var copy; + if (obj.constructor === Array) { + copy = new Array(obj.length); + for (var i = 0; i < obj.length; i++) { + copy[i] = clone(obj[i]); + } + return copy; + } + if (obj.constructor === Object) { + copy = {}; + for (var elem in obj) { + if (!obj.hasOwnProperty(elem)) { + // Do not add non own properties to the cloned object + continue; + } + copy[elem] = clone(obj[elem]); + } + return copy; + } + } + return obj; +} + module.exports = { reply_to_strings: replyToStrings, reply_to_object: replyToObject, print: print, - err_code: redisErrCode + err_code: redisErrCode, + clone: clone };