UNPKG

4.32 kBJavaScriptView Raw
1'use strict';
2
3// hgetall converts its replies to an Object. If the reply is empty, null is returned.
4// These function are only called with internal data and have therefore always the same instanceof X
5function replyToObject (reply) {
6 // The reply might be a string or a buffer if this is called in a transaction (multi)
7 if (reply.length === 0 || !(reply instanceof Array)) {
8 return null;
9 }
10 var obj = {};
11 for (var i = 0; i < reply.length; i += 2) {
12 obj[reply[i].toString('binary')] = reply[i + 1];
13 }
14 return obj;
15}
16
17function replyToStrings (reply) {
18 if (reply instanceof Buffer) {
19 return reply.toString();
20 }
21 if (reply instanceof Array) {
22 var res = new Array(reply.length);
23 for (var i = 0; i < reply.length; i++) {
24 // Recusivly call the function as slowlog returns deep nested replies
25 res[i] = replyToStrings(reply[i]);
26 }
27 return res;
28 }
29
30 return reply;
31}
32
33function print (err, reply) {
34 if (err) {
35 // A error always begins with Error:
36 console.log(err.toString());
37 } else {
38 console.log('Reply: ' + reply);
39 }
40}
41
42var camelCase;
43// Deep clone arbitrary objects with arrays. Can't handle cyclic structures (results in a range error)
44// Any attribute with a non primitive value besides object and array will be passed by reference (e.g. Buffers, Maps, Functions)
45// All capital letters are going to be replaced with a lower case letter and a underscore infront of it
46function clone (obj) {
47 var copy;
48 if (Array.isArray(obj)) {
49 copy = new Array(obj.length);
50 for (var i = 0; i < obj.length; i++) {
51 copy[i] = clone(obj[i]);
52 }
53 return copy;
54 }
55 if (Object.prototype.toString.call(obj) === '[object Object]') {
56 copy = {};
57 var elems = Object.keys(obj);
58 var elem;
59 while (elem = elems.pop()) {
60 if (elem === 'tls') { // special handle tls
61 copy[elem] = obj[elem];
62 continue;
63 }
64 // Accept camelCase options and convert them to snake_case
65 var snake_case = elem.replace(/[A-Z][^A-Z]/g, '_$&').toLowerCase();
66 // If camelCase is detected, pass it to the client, so all variables are going to be camelCased
67 // There are no deep nested options objects yet, but let's handle this future proof
68 if (snake_case !== elem.toLowerCase()) {
69 camelCase = true;
70 }
71 copy[snake_case] = clone(obj[elem]);
72 }
73 return copy;
74 }
75 return obj;
76}
77
78function convenienceClone (obj) {
79 camelCase = false;
80 obj = clone(obj) || {};
81 if (camelCase) {
82 obj.camel_case = true;
83 }
84 return obj;
85}
86
87function callbackOrEmit (self, callback, err, res) {
88 if (callback) {
89 callback(err, res);
90 } else if (err) {
91 self.emit('error', err);
92 }
93}
94
95function replyInOrder (self, callback, err, res, queue) {
96 // If the queue is explicitly passed, use that, otherwise fall back to the offline queue first,
97 // as there might be commands in both queues at the same time
98 var command_obj;
99 /* istanbul ignore if: TODO: Remove this as soon as we test Redis 3.2 on travis */
100 if (queue) {
101 command_obj = queue.peekBack();
102 } else {
103 command_obj = self.offline_queue.peekBack() || self.command_queue.peekBack();
104 }
105 if (!command_obj) {
106 process.nextTick(function () {
107 callbackOrEmit(self, callback, err, res);
108 });
109 } else {
110 var tmp = command_obj.callback;
111 command_obj.callback = tmp ?
112 function (e, r) {
113 tmp(e, r);
114 callbackOrEmit(self, callback, err, res);
115 } :
116 function (e, r) {
117 if (e) {
118 self.emit('error', e);
119 }
120 callbackOrEmit(self, callback, err, res);
121 };
122 }
123}
124
125module.exports = {
126 reply_to_strings: replyToStrings,
127 reply_to_object: replyToObject,
128 print: print,
129 err_code: /^([A-Z]+)\s+(.+)$/,
130 monitor_regex: /^[0-9]{10,11}\.[0-9]+ \[[0-9]{1,3} (.(?!\]))+.\]( ".+?")+$/,
131 clone: convenienceClone,
132 callback_or_emit: callbackOrEmit,
133 reply_in_order: replyInOrder
134};