utils.js 4.2 KB

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