index.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.getKeyIndexes = exports.hasFlag = exports.exists = exports.list = void 0;
  7. const commands_json_1 = __importDefault(require("./commands.json"));
  8. /**
  9. * Redis command list
  10. *
  11. * All commands are lowercased.
  12. */
  13. exports.list = Object.keys(commands_json_1.default);
  14. const flags = {};
  15. exports.list.forEach((commandName) => {
  16. flags[commandName] = commands_json_1.default[commandName].flags.reduce(function (flags, flag) {
  17. flags[flag] = true;
  18. return flags;
  19. }, {});
  20. });
  21. /**
  22. * Check if the command exists
  23. */
  24. function exists(commandName) {
  25. return Boolean(commands_json_1.default[commandName]);
  26. }
  27. exports.exists = exists;
  28. /**
  29. * Check if the command has the flag
  30. *
  31. * Some of possible flags: readonly, noscript, loading
  32. */
  33. function hasFlag(commandName, flag) {
  34. if (!flags[commandName]) {
  35. throw new Error("Unknown command " + commandName);
  36. }
  37. return Boolean(flags[commandName][flag]);
  38. }
  39. exports.hasFlag = hasFlag;
  40. /**
  41. * Get indexes of keys in the command arguments
  42. *
  43. * @example
  44. * ```javascript
  45. * getKeyIndexes('set', ['key', 'value']) // [0]
  46. * getKeyIndexes('mget', ['key1', 'key2']) // [0, 1]
  47. * ```
  48. */
  49. function getKeyIndexes(commandName, args, options) {
  50. const command = commands_json_1.default[commandName];
  51. if (!command) {
  52. throw new Error("Unknown command " + commandName);
  53. }
  54. if (!Array.isArray(args)) {
  55. throw new Error("Expect args to be an array");
  56. }
  57. const keys = [];
  58. const parseExternalKey = Boolean(options && options.parseExternalKey);
  59. const takeDynamicKeys = (args, startIndex) => {
  60. const keys = [];
  61. const keyStop = Number(args[startIndex]);
  62. for (let i = 0; i < keyStop; i++) {
  63. keys.push(i + startIndex + 1);
  64. }
  65. return keys;
  66. };
  67. const takeKeyAfterToken = (args, startIndex, token) => {
  68. for (let i = startIndex; i < args.length - 1; i += 1) {
  69. if (String(args[i]).toLowerCase() === token.toLowerCase()) {
  70. return i + 1;
  71. }
  72. }
  73. return null;
  74. };
  75. switch (commandName) {
  76. case "zunionstore":
  77. case "zinterstore":
  78. case "zdiffstore":
  79. keys.push(0, ...takeDynamicKeys(args, 1));
  80. break;
  81. case "eval":
  82. case "evalsha":
  83. case "eval_ro":
  84. case "evalsha_ro":
  85. case "fcall":
  86. case "fcall_ro":
  87. case "blmpop":
  88. case "bzmpop":
  89. keys.push(...takeDynamicKeys(args, 1));
  90. break;
  91. case "sintercard":
  92. case "lmpop":
  93. case "zunion":
  94. case "zinter":
  95. case "zmpop":
  96. case "zintercard":
  97. case "zdiff": {
  98. keys.push(...takeDynamicKeys(args, 0));
  99. break;
  100. }
  101. case "georadius": {
  102. keys.push(0);
  103. const storeKey = takeKeyAfterToken(args, 5, "STORE");
  104. if (storeKey)
  105. keys.push(storeKey);
  106. const distKey = takeKeyAfterToken(args, 5, "STOREDIST");
  107. if (distKey)
  108. keys.push(distKey);
  109. break;
  110. }
  111. case "georadiusbymember": {
  112. keys.push(0);
  113. const storeKey = takeKeyAfterToken(args, 4, "STORE");
  114. if (storeKey)
  115. keys.push(storeKey);
  116. const distKey = takeKeyAfterToken(args, 4, "STOREDIST");
  117. if (distKey)
  118. keys.push(distKey);
  119. break;
  120. }
  121. case "sort":
  122. case "sort_ro":
  123. keys.push(0);
  124. for (let i = 1; i < args.length - 1; i++) {
  125. let arg = args[i];
  126. if (typeof arg !== "string") {
  127. continue;
  128. }
  129. const directive = arg.toUpperCase();
  130. if (directive === "GET") {
  131. i += 1;
  132. arg = args[i];
  133. if (arg !== "#") {
  134. if (parseExternalKey) {
  135. keys.push([i, getExternalKeyNameLength(arg)]);
  136. }
  137. else {
  138. keys.push(i);
  139. }
  140. }
  141. }
  142. else if (directive === "BY") {
  143. i += 1;
  144. if (parseExternalKey) {
  145. keys.push([i, getExternalKeyNameLength(args[i])]);
  146. }
  147. else {
  148. keys.push(i);
  149. }
  150. }
  151. else if (directive === "STORE") {
  152. i += 1;
  153. keys.push(i);
  154. }
  155. }
  156. break;
  157. case "migrate":
  158. if (args[2] === "") {
  159. for (let i = 5; i < args.length - 1; i++) {
  160. const arg = args[i];
  161. if (typeof arg === "string" && arg.toUpperCase() === "KEYS") {
  162. for (let j = i + 1; j < args.length; j++) {
  163. keys.push(j);
  164. }
  165. break;
  166. }
  167. }
  168. }
  169. else {
  170. keys.push(2);
  171. }
  172. break;
  173. case "xreadgroup":
  174. case "xread":
  175. // Keys are 1st half of the args after STREAMS argument.
  176. for (let i = commandName === "xread" ? 0 : 3; i < args.length - 1; i++) {
  177. if (String(args[i]).toUpperCase() === "STREAMS") {
  178. for (let j = i + 1; j <= i + (args.length - 1 - i) / 2; j++) {
  179. keys.push(j);
  180. }
  181. break;
  182. }
  183. }
  184. break;
  185. default:
  186. // Step has to be at least one in this case, otherwise the command does
  187. // not contain a key.
  188. if (command.step > 0) {
  189. const keyStart = command.keyStart - 1;
  190. const keyStop = command.keyStop > 0
  191. ? command.keyStop
  192. : args.length + command.keyStop + 1;
  193. for (let i = keyStart; i < keyStop; i += command.step) {
  194. keys.push(i);
  195. }
  196. }
  197. break;
  198. }
  199. return keys;
  200. }
  201. exports.getKeyIndexes = getKeyIndexes;
  202. function getExternalKeyNameLength(key) {
  203. if (typeof key !== "string") {
  204. key = String(key);
  205. }
  206. const hashPos = key.indexOf("->");
  207. return hashPos === -1 ? key.length : hashPos;
  208. }