index.js 7.1 KB

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