You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.2 KiB

4 years ago
  1. 'use strict'
  2. var commands = require('./commands.json')
  3. /**
  4. * Redis command list
  5. *
  6. * All commands are lowercased.
  7. *
  8. * @var {string[]}
  9. * @public
  10. */
  11. exports.list = Object.keys(commands)
  12. var flags = {}
  13. exports.list.forEach(function (commandName) {
  14. flags[commandName] = commands[commandName].flags.reduce(function (flags, flag) {
  15. flags[flag] = true
  16. return flags
  17. }, {})
  18. })
  19. /**
  20. * Check if the command exists
  21. *
  22. * @param {string} commandName - the command name
  23. * @return {boolean} result
  24. * @public
  25. */
  26. exports.exists = function (commandName) {
  27. return Boolean(commands[commandName])
  28. }
  29. /**
  30. * Check if the command has the flag
  31. *
  32. * Some of possible flags: readonly, noscript, loading
  33. * @param {string} commandName - the command name
  34. * @param {string} flag - the flag to check
  35. * @return {boolean} result
  36. * @public
  37. */
  38. exports.hasFlag = function (commandName, flag) {
  39. if (!flags[commandName]) {
  40. throw new Error('Unknown command ' + commandName)
  41. }
  42. return Boolean(flags[commandName][flag])
  43. }
  44. /**
  45. * Get indexes of keys in the command arguments
  46. *
  47. * @param {string} commandName - the command name
  48. * @param {string[]} args - the arguments of the command
  49. * @param {object} [options] - options
  50. * @param {boolean} [options.parseExternalKey] - parse external keys
  51. * @return {number[]} - the list of the index
  52. * @public
  53. *
  54. * @example
  55. * ```javascript
  56. * getKeyIndexes('set', ['key', 'value']) // [0]
  57. * getKeyIndexes('mget', ['key1', 'key2']) // [0, 1]
  58. * ```
  59. */
  60. exports.getKeyIndexes = function (commandName, args, options) {
  61. var command = commands[commandName]
  62. if (!command) {
  63. throw new Error('Unknown command ' + commandName)
  64. }
  65. if (!Array.isArray(args)) {
  66. throw new Error('Expect args to be an array')
  67. }
  68. var keys = []
  69. var i, keyStart, keyStop, parseExternalKey
  70. switch (commandName) {
  71. case 'zunionstore':
  72. case 'zinterstore':
  73. keys.push(0)
  74. // fall through
  75. case 'eval':
  76. case 'evalsha':
  77. keyStop = Number(args[1]) + 2
  78. for (i = 2; i < keyStop; i++) {
  79. keys.push(i)
  80. }
  81. break
  82. case 'sort':
  83. parseExternalKey = options && options.parseExternalKey
  84. keys.push(0)
  85. for (i = 1; i < args.length - 1; i++) {
  86. if (typeof args[i] !== 'string') {
  87. continue
  88. }
  89. var directive = args[i].toUpperCase()
  90. if (directive === 'GET') {
  91. i += 1
  92. if (args[i] !== '#') {
  93. if (parseExternalKey) {
  94. keys.push([i, getExternalKeyNameLength(args[i])])
  95. } else {
  96. keys.push(i)
  97. }
  98. }
  99. } else if (directive === 'BY') {
  100. i += 1
  101. if (parseExternalKey) {
  102. keys.push([i, getExternalKeyNameLength(args[i])])
  103. } else {
  104. keys.push(i)
  105. }
  106. } else if (directive === 'STORE') {
  107. i += 1
  108. keys.push(i)
  109. }
  110. }
  111. break
  112. case 'migrate':
  113. if (args[2] === '') {
  114. for (i = 5; i < args.length - 1; i++) {
  115. if (args[i].toUpperCase() === 'KEYS') {
  116. for (var j = i + 1; j < args.length; j++) {
  117. keys.push(j)
  118. }
  119. break
  120. }
  121. }
  122. } else {
  123. keys.push(2)
  124. }
  125. break
  126. case 'xreadgroup':
  127. case 'xread':
  128. // Keys are 1st half of the args after STREAMS argument.
  129. for (i = commandName === 'xread' ? 0 : 3; i < args.length - 1; i++) {
  130. if (String(args[i]).toUpperCase() === 'STREAMS') {
  131. for (j = i + 1; j <= i + ((args.length - 1 - i) / 2); j++) {
  132. keys.push(j)
  133. }
  134. break
  135. }
  136. }
  137. break
  138. default:
  139. // Step has to be at least one in this case, otherwise the command does
  140. // not contain a key.
  141. if (command.step > 0) {
  142. keyStart = command.keyStart - 1
  143. keyStop = command.keyStop > 0 ? command.keyStop : args.length + command.keyStop + 1
  144. for (i = keyStart; i < keyStop; i += command.step) {
  145. keys.push(i)
  146. }
  147. }
  148. break
  149. }
  150. return keys
  151. }
  152. function getExternalKeyNameLength (key) {
  153. if (typeof key !== 'string') {
  154. key = String(key)
  155. }
  156. var hashPos = key.indexOf('->')
  157. return hashPos === -1 ? key.length : hashPos
  158. }