ioredis-om 5.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1571 -0
  3. package/built/Command.d.ts +166 -0
  4. package/built/Command.js +450 -0
  5. package/built/DataHandler.d.ts +37 -0
  6. package/built/DataHandler.js +224 -0
  7. package/built/Pipeline.d.ts +31 -0
  8. package/built/Pipeline.js +342 -0
  9. package/built/Redis.d.ts +243 -0
  10. package/built/Redis.js +800 -0
  11. package/built/ScanStream.d.ts +23 -0
  12. package/built/ScanStream.js +51 -0
  13. package/built/Script.d.ts +11 -0
  14. package/built/Script.js +62 -0
  15. package/built/SubscriptionSet.d.ts +14 -0
  16. package/built/SubscriptionSet.js +41 -0
  17. package/built/autoPipelining.d.ts +8 -0
  18. package/built/autoPipelining.js +167 -0
  19. package/built/cluster/ClusterOptions.d.ts +172 -0
  20. package/built/cluster/ClusterOptions.js +22 -0
  21. package/built/cluster/ClusterSubscriber.d.ts +29 -0
  22. package/built/cluster/ClusterSubscriber.js +223 -0
  23. package/built/cluster/ClusterSubscriberGroup.d.ts +108 -0
  24. package/built/cluster/ClusterSubscriberGroup.js +373 -0
  25. package/built/cluster/ConnectionPool.d.ts +37 -0
  26. package/built/cluster/ConnectionPool.js +154 -0
  27. package/built/cluster/DelayQueue.d.ts +20 -0
  28. package/built/cluster/DelayQueue.js +53 -0
  29. package/built/cluster/ShardedSubscriber.d.ts +36 -0
  30. package/built/cluster/ShardedSubscriber.js +147 -0
  31. package/built/cluster/index.d.ts +163 -0
  32. package/built/cluster/index.js +937 -0
  33. package/built/cluster/util.d.ts +25 -0
  34. package/built/cluster/util.js +100 -0
  35. package/built/connectors/AbstractConnector.d.ts +12 -0
  36. package/built/connectors/AbstractConnector.js +26 -0
  37. package/built/connectors/ConnectorConstructor.d.ts +5 -0
  38. package/built/connectors/ConnectorConstructor.js +2 -0
  39. package/built/connectors/SentinelConnector/FailoverDetector.d.ts +11 -0
  40. package/built/connectors/SentinelConnector/FailoverDetector.js +45 -0
  41. package/built/connectors/SentinelConnector/SentinelIterator.d.ts +13 -0
  42. package/built/connectors/SentinelConnector/SentinelIterator.js +37 -0
  43. package/built/connectors/SentinelConnector/index.d.ts +72 -0
  44. package/built/connectors/SentinelConnector/index.js +305 -0
  45. package/built/connectors/SentinelConnector/types.d.ts +21 -0
  46. package/built/connectors/SentinelConnector/types.js +2 -0
  47. package/built/connectors/StandaloneConnector.d.ts +17 -0
  48. package/built/connectors/StandaloneConnector.js +69 -0
  49. package/built/connectors/index.d.ts +3 -0
  50. package/built/connectors/index.js +7 -0
  51. package/built/constants/TLSProfiles.d.ts +9 -0
  52. package/built/constants/TLSProfiles.js +149 -0
  53. package/built/errors/ClusterAllFailedError.d.ts +7 -0
  54. package/built/errors/ClusterAllFailedError.js +15 -0
  55. package/built/errors/MaxRetriesPerRequestError.d.ts +5 -0
  56. package/built/errors/MaxRetriesPerRequestError.js +14 -0
  57. package/built/errors/index.d.ts +2 -0
  58. package/built/errors/index.js +5 -0
  59. package/built/index.d.ts +44 -0
  60. package/built/index.js +62 -0
  61. package/built/redis/RedisOptions.d.ts +197 -0
  62. package/built/redis/RedisOptions.js +58 -0
  63. package/built/redis/event_handler.d.ts +4 -0
  64. package/built/redis/event_handler.js +315 -0
  65. package/built/tracing.d.ts +26 -0
  66. package/built/tracing.js +96 -0
  67. package/built/transaction.d.ts +13 -0
  68. package/built/transaction.js +100 -0
  69. package/built/types.d.ts +33 -0
  70. package/built/types.js +2 -0
  71. package/built/utils/Commander.d.ts +50 -0
  72. package/built/utils/Commander.js +117 -0
  73. package/built/utils/RedisCommander.d.ts +8950 -0
  74. package/built/utils/RedisCommander.js +7 -0
  75. package/built/utils/applyMixin.d.ts +3 -0
  76. package/built/utils/applyMixin.js +8 -0
  77. package/built/utils/argumentParsers.d.ts +14 -0
  78. package/built/utils/argumentParsers.js +74 -0
  79. package/built/utils/debug.d.ts +16 -0
  80. package/built/utils/debug.js +95 -0
  81. package/built/utils/index.d.ts +124 -0
  82. package/built/utils/index.js +332 -0
  83. package/built/utils/lodash.d.ts +4 -0
  84. package/built/utils/lodash.js +9 -0
  85. package/package.json +103 -0
@@ -0,0 +1,224 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Command_1 = require("./Command");
4
+ const utils_1 = require("./utils");
5
+ const RedisParser = require("redis-parser");
6
+ const SubscriptionSet_1 = require("./SubscriptionSet");
7
+ const debug = (0, utils_1.Debug)("dataHandler");
8
+ class DataHandler {
9
+ constructor(redis, parserOptions) {
10
+ this.redis = redis;
11
+ const parser = new RedisParser({
12
+ stringNumbers: parserOptions.stringNumbers,
13
+ returnBuffers: true,
14
+ returnError: (err) => {
15
+ this.returnError(err);
16
+ },
17
+ returnFatalError: (err) => {
18
+ this.returnFatalError(err);
19
+ },
20
+ returnReply: (reply) => {
21
+ this.returnReply(reply);
22
+ },
23
+ });
24
+ // prependListener ensures the parser receives and processes data before socket timeout checks are performed
25
+ redis.stream.prependListener("data", (data) => {
26
+ parser.execute(data);
27
+ });
28
+ // prependListener() doesn't enable flowing mode automatically - we need to resume the stream manually
29
+ redis.stream.resume();
30
+ }
31
+ returnFatalError(err) {
32
+ err.message += ". Please report this.";
33
+ this.redis.recoverFromFatalError(err, err, { offlineQueue: false });
34
+ }
35
+ returnError(err) {
36
+ const item = this.shiftCommand(err);
37
+ if (!item) {
38
+ return;
39
+ }
40
+ err.command = {
41
+ name: item.command.name,
42
+ args: item.command.args,
43
+ };
44
+ if (item.command.name == "ssubscribe" && err.message.includes("MOVED")) {
45
+ this.redis.emit("moved");
46
+ return;
47
+ }
48
+ this.redis.handleReconnection(err, item);
49
+ }
50
+ returnReply(reply) {
51
+ if (this.handleMonitorReply(reply)) {
52
+ return;
53
+ }
54
+ if (this.handleSubscriberReply(reply)) {
55
+ return;
56
+ }
57
+ const item = this.shiftCommand(reply);
58
+ if (!item) {
59
+ return;
60
+ }
61
+ if (Command_1.default.checkFlag("ENTER_SUBSCRIBER_MODE", item.command.name)) {
62
+ this.redis.condition.subscriber = new SubscriptionSet_1.default();
63
+ this.redis.condition.subscriber.add(item.command.name, reply[1].toString());
64
+ if (!fillSubCommand(item.command, reply[2])) {
65
+ this.redis.commandQueue.unshift(item);
66
+ }
67
+ }
68
+ else if (Command_1.default.checkFlag("EXIT_SUBSCRIBER_MODE", item.command.name)) {
69
+ if (!fillUnsubCommand(item.command, reply[2])) {
70
+ this.redis.commandQueue.unshift(item);
71
+ }
72
+ }
73
+ else {
74
+ item.command.resolve(reply);
75
+ }
76
+ }
77
+ handleSubscriberReply(reply) {
78
+ if (!this.redis.condition.subscriber) {
79
+ return false;
80
+ }
81
+ const replyType = Array.isArray(reply) ? reply[0].toString() : null;
82
+ debug('receive reply "%s" in subscriber mode', replyType);
83
+ switch (replyType) {
84
+ case "message":
85
+ if (this.redis.listeners("message").length > 0) {
86
+ // Check if there're listeners to avoid unnecessary `toString()`.
87
+ this.redis.emit("message", reply[1].toString(), reply[2] ? reply[2].toString() : "");
88
+ }
89
+ this.redis.emit("messageBuffer", reply[1], reply[2]);
90
+ break;
91
+ case "pmessage": {
92
+ const pattern = reply[1].toString();
93
+ if (this.redis.listeners("pmessage").length > 0) {
94
+ this.redis.emit("pmessage", pattern, reply[2].toString(), reply[3].toString());
95
+ }
96
+ this.redis.emit("pmessageBuffer", pattern, reply[2], reply[3]);
97
+ break;
98
+ }
99
+ case "smessage": {
100
+ if (this.redis.listeners("smessage").length > 0) {
101
+ this.redis.emit("smessage", reply[1].toString(), reply[2] ? reply[2].toString() : "");
102
+ }
103
+ this.redis.emit("smessageBuffer", reply[1], reply[2]);
104
+ break;
105
+ }
106
+ case "ssubscribe":
107
+ case "subscribe":
108
+ case "psubscribe": {
109
+ const channel = reply[1].toString();
110
+ this.redis.condition.subscriber.add(replyType, channel);
111
+ const item = this.shiftCommand(reply);
112
+ if (!item) {
113
+ return;
114
+ }
115
+ if (!fillSubCommand(item.command, reply[2])) {
116
+ this.redis.commandQueue.unshift(item);
117
+ }
118
+ break;
119
+ }
120
+ case "sunsubscribe":
121
+ case "unsubscribe":
122
+ case "punsubscribe": {
123
+ const channel = reply[1] ? reply[1].toString() : null;
124
+ if (channel) {
125
+ this.redis.condition.subscriber.del(replyType, channel);
126
+ }
127
+ const count = reply[2];
128
+ if (Number(count) === 0) {
129
+ this.redis.condition.subscriber = false;
130
+ }
131
+ const item = this.shiftCommand(reply);
132
+ if (!item) {
133
+ return;
134
+ }
135
+ if (!fillUnsubCommand(item.command, count)) {
136
+ this.redis.commandQueue.unshift(item);
137
+ }
138
+ break;
139
+ }
140
+ default: {
141
+ const item = this.shiftCommand(reply);
142
+ if (!item) {
143
+ return;
144
+ }
145
+ item.command.resolve(reply);
146
+ }
147
+ }
148
+ return true;
149
+ }
150
+ handleMonitorReply(reply) {
151
+ if (this.redis.status !== "monitoring") {
152
+ return false;
153
+ }
154
+ const replyStr = reply.toString();
155
+ if (replyStr === "OK") {
156
+ // Valid commands in the monitoring mode are AUTH and MONITOR,
157
+ // both of which always reply with 'OK'.
158
+ // So if we got an 'OK', we can make certain that
159
+ // the reply is made to AUTH & MONITOR.
160
+ return false;
161
+ }
162
+ // Since commands sent in the monitoring mode will trigger an exception,
163
+ // any replies we received in the monitoring mode should consider to be
164
+ // realtime monitor data instead of result of commands.
165
+ const len = replyStr.indexOf(" ");
166
+ const timestamp = replyStr.slice(0, len);
167
+ const argIndex = replyStr.indexOf('"');
168
+ const args = replyStr
169
+ .slice(argIndex + 1, -1)
170
+ .split('" "')
171
+ .map((elem) => elem.replace(/\\"/g, '"'));
172
+ const dbAndSource = replyStr.slice(len + 2, argIndex - 2).split(" ");
173
+ this.redis.emit("monitor", timestamp, args, dbAndSource[1], dbAndSource[0]);
174
+ return true;
175
+ }
176
+ shiftCommand(reply) {
177
+ const item = this.redis.commandQueue.shift();
178
+ if (!item) {
179
+ const message = "Command queue state error. If you can reproduce this, please report it.";
180
+ const error = new Error(message +
181
+ (reply instanceof Error
182
+ ? ` Last error: ${reply.message}`
183
+ : ` Last reply: ${reply.toString()}`));
184
+ this.redis.emit("error", error);
185
+ return null;
186
+ }
187
+ return item;
188
+ }
189
+ }
190
+ exports.default = DataHandler;
191
+ const remainingRepliesMap = new WeakMap();
192
+ function fillSubCommand(command, count) {
193
+ let remainingReplies = remainingRepliesMap.has(command)
194
+ ? remainingRepliesMap.get(command)
195
+ : command.args.length;
196
+ remainingReplies -= 1;
197
+ if (remainingReplies <= 0) {
198
+ command.resolve(count);
199
+ remainingRepliesMap.delete(command);
200
+ return true;
201
+ }
202
+ remainingRepliesMap.set(command, remainingReplies);
203
+ return false;
204
+ }
205
+ function fillUnsubCommand(command, count) {
206
+ let remainingReplies = remainingRepliesMap.has(command)
207
+ ? remainingRepliesMap.get(command)
208
+ : command.args.length;
209
+ if (remainingReplies === 0) {
210
+ if (Number(count) === 0) {
211
+ remainingRepliesMap.delete(command);
212
+ command.resolve(count);
213
+ return true;
214
+ }
215
+ return false;
216
+ }
217
+ remainingReplies -= 1;
218
+ if (remainingReplies <= 0) {
219
+ command.resolve(count);
220
+ return true;
221
+ }
222
+ remainingRepliesMap.set(command, remainingReplies);
223
+ return false;
224
+ }
@@ -0,0 +1,31 @@
1
+ import Redis from "./Redis";
2
+ import Cluster from "./cluster";
3
+ import Command from "./Command";
4
+ import Commander from "./utils/Commander";
5
+ declare class Pipeline extends Commander<{
6
+ type: "pipeline";
7
+ }> {
8
+ redis: Redis | Cluster;
9
+ isCluster: boolean;
10
+ isPipeline: boolean;
11
+ leftRedirections: {
12
+ value?: number;
13
+ };
14
+ promise: Promise<unknown>;
15
+ resolve: (result: unknown) => void;
16
+ reject: (error: Error) => void;
17
+ private replyPending;
18
+ private _queue;
19
+ private _result;
20
+ private _transactions;
21
+ private _shaToScript;
22
+ private preferKey;
23
+ constructor(redis: Redis | Cluster);
24
+ fillResult(value: unknown[], position: number): void;
25
+ sendCommand(command: Command): unknown;
26
+ addBatch(commands: any): this;
27
+ }
28
+ export default Pipeline;
29
+ interface Pipeline {
30
+ length: number;
31
+ }
@@ -0,0 +1,342 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const calculateSlot = require("cluster-key-slot");
4
+ const commands_1 = require("@ioredis/commands");
5
+ const standard_as_callback_1 = require("standard-as-callback");
6
+ const util_1 = require("util");
7
+ const Command_1 = require("./Command");
8
+ const utils_1 = require("./utils");
9
+ const Commander_1 = require("./utils/Commander");
10
+ /*
11
+ This function derives from the cluster-key-slot implementation.
12
+ Instead of checking that all keys have the same slot, it checks that all slots are served by the same set of nodes.
13
+ If this is satisfied, it returns the first key's slot.
14
+ */
15
+ function generateMultiWithNodes(redis, keys) {
16
+ const slot = calculateSlot(keys[0]);
17
+ const target = redis._groupsBySlot[slot];
18
+ for (let i = 1; i < keys.length; i++) {
19
+ if (redis._groupsBySlot[calculateSlot(keys[i])] !== target) {
20
+ return -1;
21
+ }
22
+ }
23
+ return slot;
24
+ }
25
+ class Pipeline extends Commander_1.default {
26
+ constructor(redis) {
27
+ super();
28
+ this.redis = redis;
29
+ this.isPipeline = true;
30
+ this.replyPending = 0;
31
+ this._queue = [];
32
+ this._result = [];
33
+ this._transactions = 0;
34
+ this._shaToScript = {};
35
+ this.isCluster =
36
+ this.redis.constructor.name === "Cluster" || this.redis.isCluster;
37
+ this.options = redis.options;
38
+ Object.keys(redis.scriptsSet).forEach((name) => {
39
+ const script = redis.scriptsSet[name];
40
+ this._shaToScript[script.sha] = script;
41
+ this[name] = redis[name];
42
+ this[name + "Buffer"] = redis[name + "Buffer"];
43
+ });
44
+ redis.addedBuiltinSet.forEach((name) => {
45
+ this[name] = redis[name];
46
+ this[name + "Buffer"] = redis[name + "Buffer"];
47
+ });
48
+ this.promise = new Promise((resolve, reject) => {
49
+ this.resolve = resolve;
50
+ this.reject = reject;
51
+ });
52
+ const _this = this;
53
+ Object.defineProperty(this, "length", {
54
+ get: function () {
55
+ return _this._queue.length;
56
+ },
57
+ });
58
+ }
59
+ fillResult(value, position) {
60
+ if (this._queue[position].name === "exec" && Array.isArray(value[1])) {
61
+ const execLength = value[1].length;
62
+ for (let i = 0; i < execLength; i++) {
63
+ if (value[1][i] instanceof Error) {
64
+ continue;
65
+ }
66
+ const cmd = this._queue[position - (execLength - i)];
67
+ try {
68
+ value[1][i] = cmd.transformReply(value[1][i]);
69
+ }
70
+ catch (err) {
71
+ value[1][i] = err;
72
+ }
73
+ }
74
+ }
75
+ this._result[position] = value;
76
+ if (--this.replyPending) {
77
+ return;
78
+ }
79
+ if (this.isCluster) {
80
+ let retriable = true;
81
+ let commonError;
82
+ for (let i = 0; i < this._result.length; ++i) {
83
+ const error = this._result[i][0];
84
+ const command = this._queue[i];
85
+ if (error) {
86
+ if (command.name === "exec" &&
87
+ error.message ===
88
+ "EXECABORT Transaction discarded because of previous errors.") {
89
+ continue;
90
+ }
91
+ if (!commonError) {
92
+ commonError = {
93
+ name: error.name,
94
+ message: error.message,
95
+ };
96
+ }
97
+ else if (commonError.name !== error.name ||
98
+ commonError.message !== error.message) {
99
+ retriable = false;
100
+ break;
101
+ }
102
+ }
103
+ else if (!command.inTransaction) {
104
+ const isReadOnly = (0, commands_1.exists)(command.name, { caseInsensitive: true }) &&
105
+ (0, commands_1.hasFlag)(command.name, "readonly", { nameCaseInsensitive: true });
106
+ if (!isReadOnly) {
107
+ retriable = false;
108
+ break;
109
+ }
110
+ }
111
+ }
112
+ if (commonError && retriable) {
113
+ const _this = this;
114
+ const errv = commonError.message.split(" ");
115
+ const queue = this._queue;
116
+ let inTransaction = false;
117
+ this._queue = [];
118
+ for (let i = 0; i < queue.length; ++i) {
119
+ if (errv[0] === "ASK" &&
120
+ !inTransaction &&
121
+ queue[i].name !== "asking" &&
122
+ (!queue[i - 1] || queue[i - 1].name !== "asking")) {
123
+ const asking = new Command_1.default("asking");
124
+ asking.ignore = true;
125
+ this.sendCommand(asking);
126
+ }
127
+ queue[i].initPromise();
128
+ this.sendCommand(queue[i]);
129
+ inTransaction = queue[i].inTransaction;
130
+ }
131
+ let matched = true;
132
+ if (typeof this.leftRedirections === "undefined") {
133
+ this.leftRedirections = {};
134
+ }
135
+ const exec = function () {
136
+ _this.exec();
137
+ };
138
+ const cluster = this.redis;
139
+ cluster.handleError(commonError, this.leftRedirections, {
140
+ moved: function (_slot, key) {
141
+ _this.preferKey = key;
142
+ if (cluster.slots[errv[1]]) {
143
+ if (cluster.slots[errv[1]][0] !== key) {
144
+ cluster.slots[errv[1]] = [key];
145
+ }
146
+ }
147
+ else {
148
+ cluster.slots[errv[1]] = [key];
149
+ }
150
+ cluster._groupsBySlot[errv[1]] =
151
+ cluster._groupsIds[cluster.slots[errv[1]].join(";")];
152
+ cluster.refreshSlotsCache();
153
+ _this.exec();
154
+ },
155
+ ask: function (_slot, key) {
156
+ _this.preferKey = key;
157
+ _this.exec();
158
+ },
159
+ tryagain: exec,
160
+ clusterDown: exec,
161
+ connectionClosed: exec,
162
+ maxRedirections: () => {
163
+ matched = false;
164
+ },
165
+ defaults: () => {
166
+ matched = false;
167
+ },
168
+ });
169
+ if (matched) {
170
+ return;
171
+ }
172
+ }
173
+ }
174
+ let ignoredCount = 0;
175
+ for (let i = 0; i < this._queue.length - ignoredCount; ++i) {
176
+ if (this._queue[i + ignoredCount].ignore) {
177
+ ignoredCount += 1;
178
+ }
179
+ this._result[i] = this._result[i + ignoredCount];
180
+ }
181
+ this.resolve(this._result.slice(0, this._result.length - ignoredCount));
182
+ }
183
+ sendCommand(command) {
184
+ if (this._transactions > 0) {
185
+ command.inTransaction = true;
186
+ }
187
+ const position = this._queue.length;
188
+ command.pipelineIndex = position;
189
+ command.promise
190
+ .then((result) => {
191
+ this.fillResult([null, result], position);
192
+ })
193
+ .catch((error) => {
194
+ this.fillResult([error], position);
195
+ });
196
+ this._queue.push(command);
197
+ return this;
198
+ }
199
+ addBatch(commands) {
200
+ let command, commandName, args;
201
+ for (let i = 0; i < commands.length; ++i) {
202
+ command = commands[i];
203
+ commandName = command[0];
204
+ args = command.slice(1);
205
+ this[commandName].apply(this, args);
206
+ }
207
+ return this;
208
+ }
209
+ }
210
+ exports.default = Pipeline;
211
+ // @ts-expect-error
212
+ const multi = Pipeline.prototype.multi;
213
+ // @ts-expect-error
214
+ Pipeline.prototype.multi = function () {
215
+ this._transactions += 1;
216
+ return multi.apply(this, arguments);
217
+ };
218
+ // @ts-expect-error
219
+ const execBuffer = Pipeline.prototype.execBuffer;
220
+ // @ts-expect-error
221
+ Pipeline.prototype.execBuffer = (0, util_1.deprecate)(function () {
222
+ if (this._transactions > 0) {
223
+ this._transactions -= 1;
224
+ }
225
+ return execBuffer.apply(this, arguments);
226
+ }, "Pipeline#execBuffer: Use Pipeline#exec instead");
227
+ // NOTE: To avoid an unhandled promise rejection, this will unconditionally always return this.promise,
228
+ // which always has the rejection handled by standard-as-callback
229
+ // adding the provided rejection callback.
230
+ //
231
+ // If a different promise instance were returned, that promise would cause its own unhandled promise rejection
232
+ // errors, even if that promise unconditionally resolved to **the resolved value of** this.promise.
233
+ Pipeline.prototype.exec = function (callback) {
234
+ // Wait for the cluster to be connected, since we need nodes information before continuing
235
+ if (this.isCluster && !this.redis.slots.length) {
236
+ if (this.redis.status === "wait")
237
+ this.redis.connect().catch(utils_1.noop);
238
+ if (callback && !this.nodeifiedPromise) {
239
+ this.nodeifiedPromise = true;
240
+ (0, standard_as_callback_1.default)(this.promise, callback);
241
+ }
242
+ this.redis.delayUntilReady((err) => {
243
+ if (err) {
244
+ this.reject(err);
245
+ return;
246
+ }
247
+ this.exec(callback);
248
+ });
249
+ return this.promise;
250
+ }
251
+ if (this._transactions > 0) {
252
+ this._transactions -= 1;
253
+ return execBuffer.apply(this, arguments);
254
+ }
255
+ if (!this.nodeifiedPromise) {
256
+ this.nodeifiedPromise = true;
257
+ (0, standard_as_callback_1.default)(this.promise, callback);
258
+ }
259
+ if (!this._queue.length) {
260
+ this.resolve([]);
261
+ }
262
+ let pipelineSlot;
263
+ if (this.isCluster) {
264
+ // List of the first key for each command
265
+ const sampleKeys = [];
266
+ for (let i = 0; i < this._queue.length; i++) {
267
+ const keys = this._queue[i].getKeys();
268
+ if (keys.length) {
269
+ sampleKeys.push(keys[0]);
270
+ }
271
+ // For each command, check that the keys belong to the same slot
272
+ if (keys.length && calculateSlot.generateMulti(keys) < 0) {
273
+ this.reject(new Error("All the keys in a pipeline command should belong to the same slot"));
274
+ return this.promise;
275
+ }
276
+ }
277
+ if (sampleKeys.length) {
278
+ pipelineSlot = generateMultiWithNodes(this.redis, sampleKeys);
279
+ if (pipelineSlot < 0) {
280
+ this.reject(new Error("All keys in the pipeline should belong to the same slots allocation group"));
281
+ return this.promise;
282
+ }
283
+ }
284
+ else {
285
+ // Send the pipeline to a random node
286
+ pipelineSlot = (Math.random() * 16384) | 0;
287
+ }
288
+ }
289
+ const _this = this;
290
+ execPipeline();
291
+ return this.promise;
292
+ function execPipeline() {
293
+ let writePending = (_this.replyPending = _this._queue.length);
294
+ let node;
295
+ if (_this.isCluster) {
296
+ node = {
297
+ slot: pipelineSlot,
298
+ redis: _this.redis.connectionPool.nodes.all[_this.preferKey],
299
+ };
300
+ }
301
+ let data = "";
302
+ let buffers;
303
+ const stream = {
304
+ isPipeline: true,
305
+ destination: _this.isCluster ? node : { redis: _this.redis },
306
+ write(writable) {
307
+ if (typeof writable !== "string") {
308
+ if (!buffers) {
309
+ buffers = [];
310
+ }
311
+ if (data) {
312
+ buffers.push(Buffer.from(data, "utf8"));
313
+ data = "";
314
+ }
315
+ buffers.push(writable);
316
+ }
317
+ else {
318
+ data += writable;
319
+ }
320
+ if (!--writePending) {
321
+ if (buffers) {
322
+ if (data) {
323
+ buffers.push(Buffer.from(data, "utf8"));
324
+ }
325
+ stream.destination.redis.stream.write(Buffer.concat(buffers));
326
+ }
327
+ else {
328
+ stream.destination.redis.stream.write(data);
329
+ }
330
+ // Reset writePending for resending
331
+ writePending = _this._queue.length;
332
+ data = "";
333
+ buffers = undefined;
334
+ }
335
+ },
336
+ };
337
+ for (let i = 0; i < _this._queue.length; ++i) {
338
+ _this.redis.sendCommand(_this._queue[i], stream, node);
339
+ }
340
+ return _this.promise;
341
+ }
342
+ };