From 7983dd4c269997ff288de5a67896170be54997cc Mon Sep 17 00:00:00 2001
From: leibale
Date: Thu, 2 Sep 2021 11:12:55 -0400
Subject: [PATCH 01/40] update workflows & README
---
.github/workflows/benchmark.yml | 3 ++-
.github/workflows/documentation.yml | 3 ++-
.github/workflows/tests.yml | 3 ++-
README.md | 4 ++--
4 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml
index b6e5802a914..2df438eb19c 100644
--- a/.github/workflows/benchmark.yml
+++ b/.github/workflows/benchmark.yml
@@ -3,7 +3,8 @@ name: Benchmark
on:
push:
branches:
- - v4
+ - master
+ - v4.0
jobs:
benchmark:
diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml
index 16ca16b5608..9575d4639b9 100644
--- a/.github/workflows/documentation.yml
+++ b/.github/workflows/documentation.yml
@@ -3,7 +3,8 @@ name: Documentation
on:
push:
branches:
- - v4
+ - master
+ - v4.0
jobs:
documentation:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 028600f1a17..557d4f452dc 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -3,7 +3,8 @@ name: Tests
on:
push:
branches:
- - v4
+ - master
+ - v4.0
jobs:
tests:
diff --git a/README.md b/README.md
index acc229b69c2..db0fa71cc7f 100644
--- a/README.md
+++ b/README.md
@@ -6,8 +6,8 @@
-
-
+
+
From e421dc4bed75ae50eac927103b5254780e7d8994 Mon Sep 17 00:00:00 2001
From: leibale
Date: Thu, 2 Sep 2021 11:20:57 -0400
Subject: [PATCH 02/40] add .deepsource.toml
---
.deepsource.toml | 9 +++++++++
1 file changed, 9 insertions(+)
create mode 100644 .deepsource.toml
diff --git a/.deepsource.toml b/.deepsource.toml
new file mode 100644
index 00000000000..72aefc7b07a
--- /dev/null
+++ b/.deepsource.toml
@@ -0,0 +1,9 @@
+version = 1
+
+[[analyzers]]
+name = "javascript"
+enabled = true
+
+ [analyzers.meta]
+ environment = ["nodejs"]
+ dialect = "typescript"
From b80afc6346ab51a77123a5e3f59bd06524a0e02e Mon Sep 17 00:00:00 2001
From: leibale
Date: Thu, 2 Sep 2021 14:00:52 -0400
Subject: [PATCH 03/40] fix client.quit, add error events on cluster, fix some
"deepsource.io" warnings
---
lib/client.ts | 5 +-
lib/cluster-slots.ts | 43 ++++-------
lib/cluster.ts | 7 +-
lib/commander.ts | 4 +-
lib/commands-queue.ts | 13 +++-
lib/commands/MIGRATE.ts | 2 +-
lib/commands/generic-transformers.spec.ts | 1 -
package-lock.json | 94 +++++++++++------------
package.json | 2 +-
9 files changed, 86 insertions(+), 85 deletions(-)
diff --git a/lib/client.ts b/lib/client.ts
index a8da7f5ddd5..ed06317c14c 100644
--- a/lib/client.ts
+++ b/lib/client.ts
@@ -298,9 +298,10 @@ export default class RedisClient {
- return this.#socket.quit(async () => {
- this.#queue.addEncodedCommand(encodeCommand(['QUIT']));
+ return this.#socket.quit(() => {
+ const promise = this.#queue.addEncodedCommand(encodeCommand(['QUIT']));
this.#tick();
+ return promise;
});
}
diff --git a/lib/cluster-slots.ts b/lib/cluster-slots.ts
index 3e255fc2a66..5fae5b92342 100644
--- a/lib/cluster-slots.ts
+++ b/lib/cluster-slots.ts
@@ -17,54 +17,40 @@ interface SlotNodes {
clientIterator: IterableIterator> | undefined;
}
+type OnError = (err: unknown) => void;
+
export default class RedisClusterSlots {
readonly #options: RedisClusterOptions;
+ readonly #onError: OnError;
readonly #nodeByUrl = new Map>();
readonly #slots: Array> = [];
- constructor(options: RedisClusterOptions) {
+ constructor(options: RedisClusterOptions, onError: OnError) {
this.#options = options;
+ this.#onError = onError;
}
async connect(): Promise {
for (const rootNode of this.#options.rootNodes) {
- try {
- await this.#discoverNodes(rootNode);
- return;
- } catch (err) {
- console.error(err);
- // this.emit('error', err);
- }
+ if (await this.#discoverNodes(rootNode)) return;
}
throw new Error('None of the root nodes is available');
}
async discover(startWith: RedisClientType): Promise {
- try {
- await this.#discoverNodes(startWith.options?.socket);
- return;
- } catch (err) {
- console.error(err);
- // this.emit('error', err);
- }
+ if (await this.#discoverNodes(startWith.options?.socket)) return;
for (const { client } of this.#nodeByUrl.values()) {
if (client === startWith) continue;
-
- try {
- await this.#discoverNodes(client.options?.socket);
- return;
- } catch (err) {
- console.error(err);
- // this.emit('error', err);
- }
+
+ if (await this.#discoverNodes(client.options?.socket)) return;
}
throw new Error('None of the cluster nodes is available');
}
- async #discoverNodes(socketOptions?: RedisSocketOptions): Promise {
+ async #discoverNodes(socketOptions?: RedisSocketOptions): Promise {
const client = RedisClient.create({
socket: socketOptions
});
@@ -73,8 +59,14 @@ export default class RedisClusterSlots {
rootNodes: Array;
@@ -17,7 +18,7 @@ export interface RedisClusterOptions {
export type RedisClusterType =
WithPlugins & RedisCluster;
-export default class RedisCluster {
+export default class RedisCluster extends EventEmitter {
static #extractFirstKey(command: RedisCommand, originalArgs: Array, redisArgs: Array): string | undefined {
if (command.FIRST_KEY_INDEX === undefined) {
return undefined;
@@ -83,8 +84,10 @@ export default class RedisCluster) => RedisMultiCommandType;
constructor(options: RedisClusterOptions) {
+ super();
+
this.#options = options;
- this.#slots = new RedisClusterSlots(options);
+ this.#slots = new RedisClusterSlots(options, err => this.emit('error', err));
this.#Multi = RedisMultiCommand.extend(options);
}
diff --git a/lib/commander.ts b/lib/commander.ts
index 51adc417ba9..e8ff91cc7bf 100644
--- a/lib/commander.ts
+++ b/lib/commander.ts
@@ -97,12 +97,12 @@ export function transformCommandArguments(
export function encodeCommand(args: Array): string {
const encoded = [
`*${args.length}`,
- `$${Buffer.byteLength(args[0])}`,
+ `$${Buffer.byteLength(args[0]).toString()}`,
args[0]
];
for (let i = 1; i < args.length; i++) {
- encoded.push(`$${Buffer.byteLength(args[i])}`, args[i]);
+ encoded.push(`$${Buffer.byteLength(args[i]).toString()}`, args[i]);
}
return encoded.join('\r\n') + '\r\n';
diff --git a/lib/commands-queue.ts b/lib/commands-queue.ts
index 1890e0a00a9..cae3fd6130e 100644
--- a/lib/commands-queue.ts
+++ b/lib/commands-queue.ts
@@ -12,6 +12,7 @@ export interface QueueCommandOptions {
interface CommandWaitingToBeSent extends CommandWaitingForReply {
encodedCommand: string;
+ byteLength: number;
chainId?: symbol;
abort?: {
signal: any; // TODO: `AbortSignal` type is incorrect
@@ -130,6 +131,7 @@ export default class RedisCommandsQueue {
return new Promise((resolve, reject) => {
const node = new LinkedList.Node({
encodedCommand,
+ byteLength: Buffer.byteLength(encodedCommand),
chainId: options?.chainId,
resolve,
reject
@@ -156,7 +158,7 @@ export default class RedisCommandsQueue {
this.#waitingToBeSent.pushNode(node);
}
- this.#waitingToBeSentCommandsLength += encodedCommand.length;
+ this.#waitingToBeSentCommandsLength += node.value.byteLength;
});
}
@@ -230,8 +232,12 @@ export default class RedisCommandsQueue {
}
this.#pubSubState[inProgressKey] += channelsCounter;
+
+ const encodedCommand = encodeCommand(commandArgs),
+ byteLength = Buffer.byteLength(encodedCommand);
this.#waitingToBeSent.push({
- encodedCommand: encodeCommand(commandArgs),
+ encodedCommand,
+ byteLength,
channelsCounter,
resolve: () => {
this.#pubSubState[inProgressKey] -= channelsCounter;
@@ -243,6 +249,7 @@ export default class RedisCommandsQueue {
reject();
}
});
+ this.#waitingToBeSentCommandsLength += byteLength;
});
}
@@ -268,7 +275,7 @@ export default class RedisCommandsQueue {
lastCommandChainId: symbol | undefined;
for (const command of this.#waitingToBeSent) {
encoded.push(command.encodedCommand);
- size += command.encodedCommand.length;
+ size += command.byteLength;
if (size > recommendedSize) {
lastCommandChainId = command.chainId;
break;
diff --git a/lib/commands/MIGRATE.ts b/lib/commands/MIGRATE.ts
index 1d2fc075efe..14dbe741be2 100644
--- a/lib/commands/MIGRATE.ts
+++ b/lib/commands/MIGRATE.ts
@@ -19,7 +19,7 @@ export function transformArguments(
isKeyString = typeof key === 'string';
if (isKeyString) {
- args.push(key as string);
+ args.push(key);
} else {
args.push('""');
}
diff --git a/lib/commands/generic-transformers.spec.ts b/lib/commands/generic-transformers.spec.ts
index 5335255f910..9ac72bb1b25 100644
--- a/lib/commands/generic-transformers.spec.ts
+++ b/lib/commands/generic-transformers.spec.ts
@@ -1,5 +1,4 @@
import { strict as assert } from 'assert';
-import { isObject } from 'util';
import {
transformReplyBoolean,
transformReplyBooleanArray,
diff --git a/package-lock.json b/package-lock.json
index 3b7397b61e4..cb1132ddb21 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -17,7 +17,7 @@
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/mocha": "^9.0.0",
- "@types/node": "^16.7.8",
+ "@types/node": "^16.7.10",
"@types/sinon": "^10.0.2",
"@types/which": "^2.0.1",
"@types/yallist": "^4.0.1",
@@ -642,9 +642,9 @@
}
},
"node_modules/@octokit/graphql": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.7.0.tgz",
- "integrity": "sha512-diY0qMPyQjfu4rDu3kDhJ9qIZadIm4IISO3RJSv9ajYUWJUCO0AykbgzLcg1xclxtXgzY583u3gAv66M6zz5SA==",
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"dev": true,
"dependencies": {
"@octokit/request": "^5.6.0",
@@ -653,18 +653,18 @@
}
},
"node_modules/@octokit/openapi-types": {
- "version": "9.7.0",
- "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-9.7.0.tgz",
- "integrity": "sha512-TUJ16DJU8mekne6+KVcMV5g6g/rJlrnIKn7aALG9QrNpnEipFc1xjoarh0PKaAWf2Hf+HwthRKYt+9mCm5RsRg==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-10.0.0.tgz",
+ "integrity": "sha512-k1iO2zKuEjjRS1EJb4FwSLk+iF6EGp+ZV0OMRViQoWhQ1fZTk9hg1xccZII5uyYoiqcbC73MRBmT45y1vp2PPg==",
"dev": true
},
"node_modules/@octokit/plugin-paginate-rest": {
- "version": "2.15.1",
- "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.15.1.tgz",
- "integrity": "sha512-47r52KkhQDkmvUKZqXzA1lKvcyJEfYh3TKAIe5+EzMeyDM3d+/s5v11i2gTk8/n6No6DPi3k5Ind6wtDbo/AEg==",
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.0.tgz",
+ "integrity": "sha512-8YYzALPMvEZ35kgy5pdYvQ22Roz+BIuEaedO575GwE2vb/ACDqQn0xQrTJR4tnZCJn7pi8+AWPVjrFDaERIyXQ==",
"dev": true,
"dependencies": {
- "@octokit/types": "^6.24.0"
+ "@octokit/types": "^6.26.0"
},
"peerDependencies": {
"@octokit/core": ">=2"
@@ -730,12 +730,12 @@
}
},
"node_modules/@octokit/types": {
- "version": "6.25.0",
- "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.25.0.tgz",
- "integrity": "sha512-bNvyQKfngvAd/08COlYIN54nRgxskmejgywodizQNyiKoXmWRAjKup2/LYwm+T9V0gsKH6tuld1gM0PzmOiB4Q==",
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.26.0.tgz",
+ "integrity": "sha512-RDxZBAFMtqs1ZPnbUu1e7ohPNfoNhTiep4fErY7tZs995BeHu369Vsh5woMIaFbllRWEZBfvTCS4hvDnMPiHrA==",
"dev": true,
"dependencies": {
- "@octokit/openapi-types": "^9.5.0"
+ "@octokit/openapi-types": "^10.0.0"
}
},
"node_modules/@sindresorhus/is": {
@@ -855,9 +855,9 @@
"dev": true
},
"node_modules/@types/node": {
- "version": "16.7.8",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.8.tgz",
- "integrity": "sha512-8upnoQU0OPzbIkm+ZMM0zCeFCkw2s3mS0IWdx0+AAaWqm4fkBb0UJp8Edl7FVKRamYbpJC/aVsHpKWBIbiC7Zg==",
+ "version": "16.7.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.10.tgz",
+ "integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==",
"dev": true
},
"node_modules/@types/parse-json": {
@@ -1845,9 +1845,9 @@
"dev": true
},
"node_modules/electron-to-chromium": {
- "version": "1.3.822",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.822.tgz",
- "integrity": "sha512-k7jG5oYYHxF4jx6PcqwHX3JVME/OjzolqOZiIogi9xtsfsmTjTdie4x88OakYFPEa8euciTgCCzvVNwvmjHb1Q==",
+ "version": "1.3.827",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.827.tgz",
+ "integrity": "sha512-ye+4uQOY/jbjRutMcE/EmOcNwUeo1qo9aKL2tPyb09cU3lmxNeyDF4RWiemmkknW+p29h7dyDqy02higTxc9/A==",
"dev": true
},
"node_modules/emoji-regex": {
@@ -4773,9 +4773,9 @@
}
},
"node_modules/shiki": {
- "version": "0.9.8",
- "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.8.tgz",
- "integrity": "sha512-499zQUTjcNTVwwiaPrWldUTXIV3T9HZWxDwE82bY+9GE7P2uD6hpHUTXNbTof3iOG6WT+/062+OMbl0lDoG8WQ==",
+ "version": "0.9.10",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.10.tgz",
+ "integrity": "sha512-xeM7Oc6hY+6iW5O/T5hor8ul7mEprzyl5y4r5zthEHToQNw7MIhREMgU3r2gKDB0NaMLNrkcEQagudCdzE13Lg==",
"dev": true,
"dependencies": {
"json5": "^2.2.0",
@@ -6164,9 +6164,9 @@
}
},
"@octokit/graphql": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.7.0.tgz",
- "integrity": "sha512-diY0qMPyQjfu4rDu3kDhJ9qIZadIm4IISO3RJSv9ajYUWJUCO0AykbgzLcg1xclxtXgzY583u3gAv66M6zz5SA==",
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
"dev": true,
"requires": {
"@octokit/request": "^5.6.0",
@@ -6175,18 +6175,18 @@
}
},
"@octokit/openapi-types": {
- "version": "9.7.0",
- "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-9.7.0.tgz",
- "integrity": "sha512-TUJ16DJU8mekne6+KVcMV5g6g/rJlrnIKn7aALG9QrNpnEipFc1xjoarh0PKaAWf2Hf+HwthRKYt+9mCm5RsRg==",
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-10.0.0.tgz",
+ "integrity": "sha512-k1iO2zKuEjjRS1EJb4FwSLk+iF6EGp+ZV0OMRViQoWhQ1fZTk9hg1xccZII5uyYoiqcbC73MRBmT45y1vp2PPg==",
"dev": true
},
"@octokit/plugin-paginate-rest": {
- "version": "2.15.1",
- "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.15.1.tgz",
- "integrity": "sha512-47r52KkhQDkmvUKZqXzA1lKvcyJEfYh3TKAIe5+EzMeyDM3d+/s5v11i2gTk8/n6No6DPi3k5Ind6wtDbo/AEg==",
+ "version": "2.16.0",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.0.tgz",
+ "integrity": "sha512-8YYzALPMvEZ35kgy5pdYvQ22Roz+BIuEaedO575GwE2vb/ACDqQn0xQrTJR4tnZCJn7pi8+AWPVjrFDaERIyXQ==",
"dev": true,
"requires": {
- "@octokit/types": "^6.24.0"
+ "@octokit/types": "^6.26.0"
}
},
"@octokit/plugin-request-log": {
@@ -6244,12 +6244,12 @@
}
},
"@octokit/types": {
- "version": "6.25.0",
- "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.25.0.tgz",
- "integrity": "sha512-bNvyQKfngvAd/08COlYIN54nRgxskmejgywodizQNyiKoXmWRAjKup2/LYwm+T9V0gsKH6tuld1gM0PzmOiB4Q==",
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.26.0.tgz",
+ "integrity": "sha512-RDxZBAFMtqs1ZPnbUu1e7ohPNfoNhTiep4fErY7tZs995BeHu369Vsh5woMIaFbllRWEZBfvTCS4hvDnMPiHrA==",
"dev": true,
"requires": {
- "@octokit/openapi-types": "^9.5.0"
+ "@octokit/openapi-types": "^10.0.0"
}
},
"@sindresorhus/is": {
@@ -6360,9 +6360,9 @@
"dev": true
},
"@types/node": {
- "version": "16.7.8",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.8.tgz",
- "integrity": "sha512-8upnoQU0OPzbIkm+ZMM0zCeFCkw2s3mS0IWdx0+AAaWqm4fkBb0UJp8Edl7FVKRamYbpJC/aVsHpKWBIbiC7Zg==",
+ "version": "16.7.10",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.10.tgz",
+ "integrity": "sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA==",
"dev": true
},
"@types/parse-json": {
@@ -7108,9 +7108,9 @@
"dev": true
},
"electron-to-chromium": {
- "version": "1.3.822",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.822.tgz",
- "integrity": "sha512-k7jG5oYYHxF4jx6PcqwHX3JVME/OjzolqOZiIogi9xtsfsmTjTdie4x88OakYFPEa8euciTgCCzvVNwvmjHb1Q==",
+ "version": "1.3.827",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.827.tgz",
+ "integrity": "sha512-ye+4uQOY/jbjRutMcE/EmOcNwUeo1qo9aKL2tPyb09cU3lmxNeyDF4RWiemmkknW+p29h7dyDqy02higTxc9/A==",
"dev": true
},
"emoji-regex": {
@@ -9284,9 +9284,9 @@
}
},
"shiki": {
- "version": "0.9.8",
- "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.8.tgz",
- "integrity": "sha512-499zQUTjcNTVwwiaPrWldUTXIV3T9HZWxDwE82bY+9GE7P2uD6hpHUTXNbTof3iOG6WT+/062+OMbl0lDoG8WQ==",
+ "version": "0.9.10",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.9.10.tgz",
+ "integrity": "sha512-xeM7Oc6hY+6iW5O/T5hor8ul7mEprzyl5y4r5zthEHToQNw7MIhREMgU3r2gKDB0NaMLNrkcEQagudCdzE13Lg==",
"dev": true,
"requires": {
"json5": "^2.2.0",
diff --git a/package.json b/package.json
index fd309d970f6..32cf674a4d2 100644
--- a/package.json
+++ b/package.json
@@ -35,7 +35,7 @@
"devDependencies": {
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@types/mocha": "^9.0.0",
- "@types/node": "^16.7.8",
+ "@types/node": "^16.7.10",
"@types/sinon": "^10.0.2",
"@types/which": "^2.0.1",
"@types/yallist": "^4.0.1",
From 18ad329ccc2950b5481109367594d72ecaeecf27 Mon Sep 17 00:00:00 2001
From: leibale
Date: Mon, 6 Sep 2021 15:59:52 -0400
Subject: [PATCH 04/40] Release 4.0.0-rc.1
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index cb1132ddb21..ac623c60e6a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "redis",
- "version": "4.0.0-rc.0",
+ "version": "4.0.0-rc.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "redis",
- "version": "4.0.0-rc.0",
+ "version": "4.0.0-rc.1",
"license": "MIT",
"dependencies": {
"cluster-key-slot": "1.1.0",
diff --git a/package.json b/package.json
index 32cf674a4d2..56a7ed38c65 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "redis",
- "version": "4.0.0-rc.0",
+ "version": "4.0.0-rc.1",
"description": "A high performance Redis client.",
"keywords": [
"database",
From 1413a69a6b75253b606ffd211f7f119ec5337894 Mon Sep 17 00:00:00 2001
From: leibale
Date: Thu, 9 Sep 2021 16:58:31 -0400
Subject: [PATCH 05/40] add cluster.duplicate, add some tests
---
lib/client.ts | 2 +-
lib/cluster.ts | 4 +++
lib/commands/GEOPOS.spec.ts | 50 +++++++++++++++++++++++++----
lib/commands/GEOSEARCHSTORE.spec.ts | 9 +++++-
lib/commands/PUBSUB_NUMSUB.spec.ts | 2 +-
5 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/lib/client.ts b/lib/client.ts
index ed06317c14c..139ec647fc3 100644
--- a/lib/client.ts
+++ b/lib/client.ts
@@ -184,7 +184,7 @@ export default class RedisClient this.#socket.write(encodedCommands)
+ encodedCommands => this.#socket.write(encodedCommands)
);
}
diff --git a/lib/cluster.ts b/lib/cluster.ts
index 2c1b23465ee..3eeaed5009f 100644
--- a/lib/cluster.ts
+++ b/lib/cluster.ts
@@ -91,6 +91,10 @@ export default class RedisCluster {
+ return new (Object.getPrototypeOf(this).constructor)(this.#options);
+ }
+
async connect(): Promise {
return this.#slots.connect();
}
diff --git a/lib/commands/GEOPOS.spec.ts b/lib/commands/GEOPOS.spec.ts
index 98cfa6aa2d3..e15abeff516 100644
--- a/lib/commands/GEOPOS.spec.ts
+++ b/lib/commands/GEOPOS.spec.ts
@@ -1,6 +1,6 @@
import { strict as assert } from 'assert';
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
-import { transformArguments } from './GEOPOS';
+import { transformArguments, transformReply } from './GEOPOS';
describe('GEOPOS', () => {
describe('transformArguments', () => {
@@ -19,11 +19,49 @@ describe('GEOPOS', () => {
});
});
- itWithClient(TestRedisServers.OPEN, 'client.geoPos', async client => {
- assert.deepEqual(
- await client.geoPos('key', 'member'),
- [null]
- );
+ describe('transformReply', () => {
+ it('null', () => {
+ assert.deepEqual(
+ transformReply([null]),
+ [null]
+ );
+ });
+
+ it('with member', () => {
+ assert.deepEqual(
+ transformReply([['1', '2']]),
+ [{
+ longitude: '1',
+ latitude: '2'
+ }]
+ );
+ });
+ });
+
+ describe('client.geoPos', () => {
+ itWithClient(TestRedisServers.OPEN, 'null', async client => {
+ assert.deepEqual(
+ await client.geoPos('key', 'member'),
+ [null]
+ );
+ });
+
+ itWithClient(TestRedisServers.OPEN, 'with member', async client => {
+ const coordinates = {
+ longitude: '-122.06429868936538696',
+ latitude: '37.37749628831998194'
+ };
+
+ await client.geoAdd('key', {
+ member: 'member',
+ ...coordinates
+ });
+
+ assert.deepEqual(
+ await client.geoPos('key', 'member'),
+ [coordinates]
+ );
+ });
});
itWithCluster(TestRedisClusters.OPEN, 'cluster.geoPos', async cluster => {
diff --git a/lib/commands/GEOSEARCHSTORE.spec.ts b/lib/commands/GEOSEARCHSTORE.spec.ts
index 1983537077c..ad33c62b78c 100644
--- a/lib/commands/GEOSEARCHSTORE.spec.ts
+++ b/lib/commands/GEOSEARCHSTORE.spec.ts
@@ -1,6 +1,6 @@
import { strict as assert } from 'assert';
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster, describeHandleMinimumRedisVersion } from '../test-utils';
-import { transformArguments } from './GEOSEARCHSTORE';
+import { transformArguments, transformReply } from './GEOSEARCHSTORE';
describe('GEOSEARCHSTORE', () => {
describeHandleMinimumRedisVersion([6, 2]);
@@ -40,6 +40,13 @@ describe('GEOSEARCHSTORE', () => {
});
});
+ it('transformReply with empty array (https://github.com/redis/redis/issues/9261)', () => {
+ assert.throws(
+ () => (transformReply as any)([]),
+ TypeError
+ );
+ });
+
itWithClient(TestRedisServers.OPEN, 'client.geoSearchStore', async client => {
await client.geoAdd('source', {
longitude: 1,
diff --git a/lib/commands/PUBSUB_NUMSUB.spec.ts b/lib/commands/PUBSUB_NUMSUB.spec.ts
index 74065dbb48f..403732f8f9d 100644
--- a/lib/commands/PUBSUB_NUMSUB.spec.ts
+++ b/lib/commands/PUBSUB_NUMSUB.spec.ts
@@ -33,7 +33,7 @@ describe('PUBSUB NUMSUB', () => {
);
});
- itWithCluster(TestRedisClusters.OPEN, 'cluster.pubSubNumPat', async cluster => {
+ itWithCluster(TestRedisClusters.OPEN, 'cluster.pubSubNumSub', async cluster => {
assert.deepEqual(
await cluster.pubSubNumSub(),
Object.create(null)
From 08837c864801558ad8020278ad75a3b14a2ed560 Mon Sep 17 00:00:00 2001
From: leibale
Date: Mon, 13 Sep 2021 19:49:39 -0400
Subject: [PATCH 06/40] fix #1650 - add support for Buffer in some commands,
add GET_BUFFER command
---
lib/client.spec.ts | 7 ++
lib/client.ts | 94 ++++++++++-------------
lib/cluster-slots.ts | 2 +-
lib/cluster.ts | 29 +++----
lib/commander.spec.ts | 22 +++++-
lib/commander.ts | 20 ++---
lib/commands-queue.ts | 80 +++++--------------
lib/commands/ACL_DELUSER.ts | 3 +-
lib/commands/ACL_SETUSER.ts | 3 +-
lib/commands/BITOP.ts | 3 +-
lib/commands/BLPOP.ts | 3 +-
lib/commands/BRPOP.ts | 3 +-
lib/commands/BZPOPMAX.ts | 3 +-
lib/commands/BZPOPMIN.ts | 3 +-
lib/commands/DEL.ts | 3 +-
lib/commands/EXISTS.ts | 3 +-
lib/commands/GEOHASH.ts | 3 +-
lib/commands/GEOPOS.ts | 3 +-
lib/commands/GET.ts | 3 +-
lib/commands/GET_BUFFER.spec.ts | 22 ++++++
lib/commands/GET_BUFFER.ts | 7 ++
lib/commands/HDEL.ts | 3 +-
lib/commands/HMGET.ts | 3 +-
lib/commands/LPUSH.ts | 3 +-
lib/commands/LPUSHX.ts | 3 +-
lib/commands/PFADD.ts | 3 +-
lib/commands/PFCOUNT.ts | 3 +-
lib/commands/PFMERGE.ts | 3 +-
lib/commands/RPUSH.ts | 3 +-
lib/commands/RPUSHX.ts | 3 +-
lib/commands/SADD.ts | 3 +-
lib/commands/SCRIPT_EXISTS.ts | 3 +-
lib/commands/SDIFF.ts | 3 +-
lib/commands/SDIFFSTORE.ts | 3 +-
lib/commands/SET.spec.ts | 2 +-
lib/commands/SET.ts | 4 +-
lib/commands/SETEX.ts | 3 +-
lib/commands/SINTER.ts | 3 +-
lib/commands/SINTERSTORE.ts | 3 +-
lib/commands/SREM.ts | 3 +-
lib/commands/SUNION.ts | 3 +-
lib/commands/SUNIONSTORE.ts | 3 +-
lib/commands/TOUCH.ts | 3 +-
lib/commands/UNLINK.ts | 3 +-
lib/commands/WATCH.ts | 3 +-
lib/commands/XACK.ts | 3 +-
lib/commands/XDEL.ts | 3 +-
lib/commands/ZDIFF.ts | 3 +-
lib/commands/ZDIFFSTORE.ts | 3 +-
lib/commands/ZDIFF_WITHSCORES.ts | 3 +-
lib/commands/ZINTER.ts | 3 +-
lib/commands/ZINTERSTORE.ts | 3 +-
lib/commands/ZINTER_WITHSCORES.ts | 3 +-
lib/commands/ZMSCORE.ts | 3 +-
lib/commands/ZREM.ts | 3 +-
lib/commands/ZUNION.ts | 3 +-
lib/commands/ZUNIONSTORE.ts | 3 +-
lib/commands/ZUNION_WITHSCORES.ts | 3 +-
lib/commands/generic-transformers.ts | 12 ++-
lib/commands/index.ts | 10 ++-
lib/multi-command.spec.ts | 23 +++---
lib/multi-command.ts | 20 +++--
lib/socket.ts | 28 +++++--
lib/ts-declarations/cluster-key-slot.d.ts | 2 +-
lib/ts-declarations/redis-parser.d.ts | 2 +
65 files changed, 300 insertions(+), 227 deletions(-)
create mode 100644 lib/commands/GET_BUFFER.spec.ts
create mode 100644 lib/commands/GET_BUFFER.ts
diff --git a/lib/client.spec.ts b/lib/client.spec.ts
index f73049d2286..9f18e184c88 100644
--- a/lib/client.spec.ts
+++ b/lib/client.spec.ts
@@ -195,6 +195,13 @@ describe('Client', () => {
assert.equal(await client.sendCommand(['PING']), 'PONG');
});
+ itWithClient(TestRedisServers.OPEN, 'bufferMode', async client => {
+ assert.deepEqual(
+ await client.sendCommand(['PING'], undefined, true),
+ Buffer.from('PONG')
+ );
+ });
+
describe('AbortController', () => {
before(function () {
if (!global.AbortController) {
diff --git a/lib/client.ts b/lib/client.ts
index 139ec647fc3..aaa982da1cc 100644
--- a/lib/client.ts
+++ b/lib/client.ts
@@ -1,6 +1,6 @@
import RedisSocket, { RedisSocketOptions } from './socket';
import RedisCommandsQueue, { PubSubListener, PubSubSubscribeCommands, PubSubUnsubscribeCommands, QueueCommandOptions } from './commands-queue';
-import COMMANDS from './commands';
+import COMMANDS, { TransformArgumentsReply } from './commands';
import { RedisCommand, RedisModules, RedisReply } from './commands';
import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command';
import EventEmitter from 'events';
@@ -62,12 +62,10 @@ export default class RedisClient> {
const { args: redisArgs, options } = transformCommandArguments(command, args);
- const reply = command.transformReply(
- await this.#sendCommand(redisArgs, options),
- redisArgs.preserve
+ return command.transformReply(
+ await this.#sendCommand(redisArgs, options, command.BUFFER_MODE),
+ redisArgs.preserve,
);
-
- return reply;
}
static async #scriptsExecutor(
@@ -77,12 +75,10 @@ export default class RedisClient {
const { args: redisArgs, options } = transformCommandArguments(script, args);
- const reply = script.transformReply(
- await this.executeScript(script, redisArgs, options),
+ return script.transformReply(
+ await this.executeScript(script, redisArgs, options, script.BUFFER_MODE),
redisArgs.preserve
);
-
- return reply;
}
static create(options?: RedisClientOptions): RedisClientType {
@@ -182,10 +178,7 @@ export default class RedisClient this.#socket.write(encodedCommands)
- );
+ return new RedisCommandsQueue(this.#options?.commandsQueueMaxLength);
}
#legacyMode(): void {
@@ -299,7 +292,7 @@ export default class RedisClient {
return this.#socket.quit(() => {
- const promise = this.#queue.addEncodedCommand(encodeCommand(['QUIT']));
+ const promise = this.#queue.addCommand(['QUIT']);
this.#tick();
return promise;
});
@@ -307,46 +300,64 @@ export default class RedisClient(args: Array, options?: ClientCommandOptions): Promise {
- return this.#sendCommand(args, options);
+ sendCommand(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise {
+ return this.#sendCommand(args, options, bufferMode);
}
// using `#sendCommand` cause `sendCommand` is overwritten in legacy mode
- #sendCommand(args: Array, options?: ClientCommandOptions): Promise {
- return this.sendEncodedCommand(encodeCommand(args), options);
- }
-
- async sendEncodedCommand(encodedCommand: string, options?: ClientCommandOptions): Promise {
+ async #sendCommand(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise {
if (!this.#socket.isOpen) {
throw new ClientClosedError();
}
if (options?.isolated) {
return this.executeIsolated(isolatedClient =>
- isolatedClient.sendEncodedCommand(encodedCommand, {
+ isolatedClient.sendCommand(args, {
...options,
isolated: false
})
);
}
- const promise = this.#queue.addEncodedCommand(encodedCommand, options);
+ const promise = this.#queue.addCommand(args, options, bufferMode);
this.#tick();
return await promise;
}
+ #tick(): void {
+ if (!this.#socket.isSocketExists) {
+ return;
+ }
+
+ this.#socket.cork();
+
+ while (true) {
+ const args = this.#queue.getCommandToSend();
+ if (args === undefined) break;
+
+ let writeResult;
+ for (const toWrite of encodeCommand(args)) {
+ writeResult = this.#socket.write(toWrite);
+ }
+
+ if (!writeResult) {
+ break;
+ }
+ }
+ }
+
executeIsolated(fn: (client: RedisClientType) => T | Promise): Promise {
return this.#isolationPool.use(fn);
}
- async executeScript(script: RedisLuaScript, args: Array, options?: ClientCommandOptions): Promise> {
+ async executeScript(script: RedisLuaScript, args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise> {
try {
return await this.#sendCommand([
'EVALSHA',
script.SHA1,
script.NUMBER_OF_KEYS.toString(),
...args
- ], options);
+ ], options, bufferMode);
} catch (err: any) {
if (!err?.message?.startsWith?.('NOSCRIPT')) {
throw err;
@@ -357,14 +368,14 @@ export default class RedisClient, chainId?: symbol): Promise> {
const promise = Promise.all(
- commands.map(({encodedCommand}) => {
- return this.#queue.addEncodedCommand(encodedCommand, RedisClient.commandOptions({
+ commands.map(({ args }) => {
+ return this.#queue.addCommand(args, RedisClient.commandOptions({
chainId
}));
})
@@ -438,31 +449,6 @@ export default class RedisClient this.#tick());
- this.#isTickQueued = true;
- return;
- }
-
- const isBuffering = this.#queue.executeChunk(chunkRecommendedSize);
- if (isBuffering === true) {
- this.#socket.once('drain', () => this.#tick());
- } else if (isBuffering === false) {
- this.#tick();
- return;
- }
-
- this.#isTickQueued = false;
- }
}
extendWithDefaultCommands(RedisClient, RedisClient.commandsExecutor);
diff --git a/lib/cluster-slots.ts b/lib/cluster-slots.ts
index 5fae5b92342..a5155cc53db 100644
--- a/lib/cluster-slots.ts
+++ b/lib/cluster-slots.ts
@@ -172,7 +172,7 @@ export default class RedisClusterSlots {
+ getClient(firstKey?: string | Buffer, isReadonly?: boolean): RedisClientType {
if (!firstKey) {
return this.#getRandomClient();
}
diff --git a/lib/cluster.ts b/lib/cluster.ts
index 3eeaed5009f..4f1b27cb05f 100644
--- a/lib/cluster.ts
+++ b/lib/cluster.ts
@@ -1,4 +1,4 @@
-import { RedisCommand, RedisModules } from './commands';
+import { RedisCommand, RedisModules, TransformArgumentsReply } from './commands';
import RedisClient, { ClientCommandOptions, RedisClientType, WithPlugins } from './client';
import { RedisSocketOptions } from './socket';
import RedisClusterSlots, { ClusterNode } from './cluster-slots';
@@ -6,6 +6,7 @@ import { RedisLuaScript, RedisLuaScripts } from './lua-script';
import { extendWithModulesAndScripts, extendWithDefaultCommands, transformCommandArguments } from './commander';
import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command';
import { EventEmitter } from 'events';
+import cluster from 'cluster';
export interface RedisClusterOptions {
rootNodes: Array;
@@ -19,7 +20,7 @@ export type RedisClusterType
WithPlugins & RedisCluster;
export default class RedisCluster extends EventEmitter {
- static #extractFirstKey(command: RedisCommand, originalArgs: Array, redisArgs: Array): string | undefined {
+ static #extractFirstKey(command: RedisCommand, originalArgs: Array, redisArgs: TransformArgumentsReply): string | Buffer | undefined {
if (command.FIRST_KEY_INDEX === undefined) {
return undefined;
} else if (typeof command.FIRST_KEY_INDEX === 'number') {
@@ -41,7 +42,8 @@ export default class RedisCluster(
- firstKey: string | undefined,
+ firstKey: string | Buffer | undefined,
isReadonly: boolean | undefined,
- args: Array,
+ args: TransformArgumentsReply,
options?: ClientCommandOptions,
+ bufferMode?: boolean,
redirections = 0
): Promise> {
const client = this.#slots.getClient(firstKey, isReadonly);
try {
- return await client.sendCommand(args, options);
+ return await client.sendCommand(args, options, bufferMode);
} catch (err: any) {
const shouldRetry = await this.#handleCommandError(err, client, redirections);
if (shouldRetry === true) {
- return this.sendCommand(firstKey, isReadonly, args, options, redirections + 1);
+ return this.sendCommand(firstKey, isReadonly, args, options, bufferMode, redirections + 1);
} else if (shouldRetry) {
- return shouldRetry.sendCommand(args, options);
+ return shouldRetry.sendCommand(args, options, bufferMode);
}
throw err;
@@ -125,7 +128,7 @@ export default class RedisCluster,
- redisArgs: Array,
+ redisArgs: TransformArgumentsReply,
options?: ClientCommandOptions,
redirections = 0
): Promise> {
@@ -135,13 +138,13 @@ export default class RedisCluster {
- return client.sendEncodedCommand(encodedCommand, RedisClient.commandOptions({
+ commands.map(({ args }) => {
+ return client.sendCommand(args, RedisClient.commandOptions({
chainId
}));
})
diff --git a/lib/commander.spec.ts b/lib/commander.spec.ts
index a38330abada..b6ec1004613 100644
--- a/lib/commander.spec.ts
+++ b/lib/commander.spec.ts
@@ -2,27 +2,43 @@ import { strict as assert } from 'assert';
import { describe } from 'mocha';
import { encodeCommand } from './commander';
+function encodeCommandToString(...args: Parameters): string {
+ const arr = [];
+ for (const item of encodeCommand(...args)) {
+ arr.push(item.toString());
+ }
+
+ return arr.join('');
+}
+
describe('Commander', () => {
describe('encodeCommand (see #1628)', () => {
it('1 byte', () => {
assert.equal(
- encodeCommand(['a', 'z']),
+ encodeCommandToString(['a', 'z']),
'*2\r\n$1\r\na\r\n$1\r\nz\r\n'
);
});
it('2 bytes', () => {
assert.equal(
- encodeCommand(['א', 'ת']),
+ encodeCommandToString(['א', 'ת']),
'*2\r\n$2\r\nא\r\n$2\r\nת\r\n'
);
});
it('4 bytes', () => {
assert.equal(
- encodeCommand(['🐣', '🐤']),
+ encodeCommandToString(['🐣', '🐤']),
'*2\r\n$4\r\n🐣\r\n$4\r\n🐤\r\n'
);
});
+
+ it('with a buffer', () => {
+ assert.equal(
+ encodeCommandToString([Buffer.from('string')]),
+ '*1\r\n$6\r\nstring\r\n'
+ );
+ });
});
});
diff --git a/lib/commander.ts b/lib/commander.ts
index e8ff91cc7bf..c2b1918709a 100644
--- a/lib/commander.ts
+++ b/lib/commander.ts
@@ -2,6 +2,7 @@
import COMMANDS, { RedisCommand, RedisModules, TransformArgumentsReply } from './commands';
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
import { CommandOptions, isCommandOptions } from './command-options';
+import { off } from 'process';
type Instantiable = new(...args: Array) => T;
@@ -94,16 +95,15 @@ export function transformCommandArguments(
};
}
-export function encodeCommand(args: Array): string {
- const encoded = [
- `*${args.length}`,
- `$${Buffer.byteLength(args[0]).toString()}`,
- args[0]
- ];
+const DELIMITER = '\r\n';
- for (let i = 1; i < args.length; i++) {
- encoded.push(`$${Buffer.byteLength(args[i]).toString()}`, args[i]);
- }
+export function* encodeCommand(args: TransformArgumentsReply): IterableIterator {
+ yield `*${args.length}${DELIMITER}`;
- return encoded.join('\r\n') + '\r\n';
+ for (const arg of args) {
+ const byteLength = typeof arg === 'string' ? Buffer.byteLength(arg): arg.length;
+ yield `$${byteLength.toString()}${DELIMITER}`;
+ yield arg;
+ yield DELIMITER;
+ }
}
diff --git a/lib/commands-queue.ts b/lib/commands-queue.ts
index cae3fd6130e..27c83965529 100644
--- a/lib/commands-queue.ts
+++ b/lib/commands-queue.ts
@@ -2,17 +2,15 @@ import LinkedList from 'yallist';
import RedisParser from 'redis-parser';
import { AbortError } from './errors';
import { RedisReply } from './commands';
-import { encodeCommand } from './commander';
export interface QueueCommandOptions {
asap?: boolean;
- signal?: any; // TODO: `AbortSignal` type is incorrect
chainId?: symbol;
+ signal?: any; // TODO: `AbortSignal` type is incorrect
}
interface CommandWaitingToBeSent extends CommandWaitingForReply {
- encodedCommand: string;
- byteLength: number;
+ args: Array;
chainId?: symbol;
abort?: {
signal: any; // TODO: `AbortSignal` type is incorrect
@@ -24,10 +22,9 @@ interface CommandWaitingForReply {
resolve(reply?: any): void;
reject(err: Error): void;
channelsCounter?: number;
+ bufferMode?: boolean;
}
-export type CommandsQueueExecutor = (encodedCommands: string) => boolean | undefined;
-
export enum PubSubSubscribeCommands {
SUBSCRIBE = 'SUBSCRIBE',
PSUBSCRIBE = 'PSUBSCRIBE'
@@ -57,16 +54,8 @@ export default class RedisCommandsQueue {
readonly #maxLength: number | null | undefined;
- readonly #executor: CommandsQueueExecutor;
-
readonly #waitingToBeSent = new LinkedList();
- #waitingToBeSentCommandsLength = 0;
-
- get waitingToBeSentCommandsLength() {
- return this.#waitingToBeSentCommandsLength;
- }
-
readonly #waitingForReply = new LinkedList();
readonly #pubSubState = {
@@ -114,12 +103,11 @@ export default class RedisCommandsQueue {
#chainInExecution: symbol | undefined;
- constructor(maxLength: number | null | undefined, executor: CommandsQueueExecutor) {
+ constructor(maxLength: number | null | undefined) {
this.#maxLength = maxLength;
- this.#executor = executor;
}
- addEncodedCommand(encodedCommand: string, options?: QueueCommandOptions): Promise {
+ addCommand(args: Array, options?: QueueCommandOptions, bufferMode?: boolean): Promise {
if (this.#pubSubState.subscribing || this.#pubSubState.subscribed) {
return Promise.reject(new Error('Cannot send commands in PubSub mode'));
} else if (this.#maxLength && this.#waitingToBeSent.length + this.#waitingForReply.length >= this.#maxLength) {
@@ -130,11 +118,11 @@ export default class RedisCommandsQueue {
return new Promise((resolve, reject) => {
const node = new LinkedList.Node({
- encodedCommand,
- byteLength: Buffer.byteLength(encodedCommand),
+ args,
chainId: options?.chainId,
+ bufferMode,
resolve,
- reject
+ reject,
});
if (options?.signal) {
@@ -157,8 +145,6 @@ export default class RedisCommandsQueue {
} else {
this.#waitingToBeSent.pushNode(node);
}
-
- this.#waitingToBeSentCommandsLength += node.value.byteLength;
});
}
@@ -233,11 +219,8 @@ export default class RedisCommandsQueue {
this.#pubSubState[inProgressKey] += channelsCounter;
- const encodedCommand = encodeCommand(commandArgs),
- byteLength = Buffer.byteLength(encodedCommand);
this.#waitingToBeSent.push({
- encodedCommand,
- byteLength,
+ args: commandArgs,
channelsCounter,
resolve: () => {
this.#pubSubState[inProgressKey] -= channelsCounter;
@@ -249,7 +232,6 @@ export default class RedisCommandsQueue {
reject();
}
});
- this.#waitingToBeSentCommandsLength += byteLength;
});
}
@@ -267,47 +249,25 @@ export default class RedisCommandsQueue {
]);
}
- executeChunk(recommendedSize: number): boolean | undefined {
- if (!this.#waitingToBeSent.length) return;
-
- const encoded: Array = [];
- let size = 0,
- lastCommandChainId: symbol | undefined;
- for (const command of this.#waitingToBeSent) {
- encoded.push(command.encodedCommand);
- size += command.byteLength;
- if (size > recommendedSize) {
- lastCommandChainId = command.chainId;
- break;
- }
- }
-
- if (!lastCommandChainId && encoded.length === this.#waitingToBeSent.length) {
- lastCommandChainId = this.#waitingToBeSent.tail!.value.chainId;
- }
-
- lastCommandChainId ??= this.#waitingToBeSent.tail?.value.chainId;
-
- this.#executor(encoded.join(''));
-
- for (let i = 0; i < encoded.length; i++) {
- const waitingToBeSent = this.#waitingToBeSent.shift()!;
- if (waitingToBeSent.abort) {
- waitingToBeSent.abort.signal.removeEventListener('abort', waitingToBeSent.abort.listener);
- }
+ getCommandToSend(): Array | undefined {
+ const toSend = this.#waitingToBeSent.shift();
+ if (toSend) {
this.#waitingForReply.push({
- resolve: waitingToBeSent.resolve,
- reject: waitingToBeSent.reject,
- channelsCounter: waitingToBeSent.channelsCounter
+ resolve: toSend.resolve,
+ reject: toSend.reject,
+ channelsCounter: toSend.channelsCounter,
+ bufferMode: toSend.bufferMode
});
}
- this.#chainInExecution = lastCommandChainId;
- this.#waitingToBeSentCommandsLength -= size;
+ this.#chainInExecution = toSend?.chainId;
+
+ return toSend?.args;
}
parseResponse(data: Buffer): void {
+ this.#parser.setReturnBuffers(!!this.#waitingForReply.head?.value.bufferMode);
this.#parser.execute(data);
}
diff --git a/lib/commands/ACL_DELUSER.ts b/lib/commands/ACL_DELUSER.ts
index 7fb4904be41..85a916c4379 100644
--- a/lib/commands/ACL_DELUSER.ts
+++ b/lib/commands/ACL_DELUSER.ts
@@ -1,6 +1,7 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
-export function transformArguments(username: string | Array): Array {
+export function transformArguments(username: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['ACL', 'DELUSER'], username);
}
diff --git a/lib/commands/ACL_SETUSER.ts b/lib/commands/ACL_SETUSER.ts
index b2829ca964f..e55a8942e02 100644
--- a/lib/commands/ACL_SETUSER.ts
+++ b/lib/commands/ACL_SETUSER.ts
@@ -1,6 +1,7 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
-export function transformArguments(username: string, rule: string | Array): Array {
+export function transformArguments(username: string, rule: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['ACL', 'SETUSER', username], rule);
}
diff --git a/lib/commands/BITOP.ts b/lib/commands/BITOP.ts
index fe7d339f5d1..bb965da6dfa 100644
--- a/lib/commands/BITOP.ts
+++ b/lib/commands/BITOP.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 2;
type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT';
-export function transformArguments(operation: BitOperations, destKey: string, key: string | Array): Array {
+export function transformArguments(operation: BitOperations, destKey: string, key: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['BITOP', operation, destKey], key);
}
diff --git a/lib/commands/BLPOP.ts b/lib/commands/BLPOP.ts
index 7c352951fb3..1061f5e113a 100644
--- a/lib/commands/BLPOP.ts
+++ b/lib/commands/BLPOP.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(keys: string | Array, timeout: number): Array {
+export function transformArguments(keys: string | Buffer | Array, timeout: number): TransformArgumentsReply {
const args = pushVerdictArguments(['BLPOP'], keys);
args.push(timeout.toString());
diff --git a/lib/commands/BRPOP.ts b/lib/commands/BRPOP.ts
index a03c278309a..93ded4dbf1a 100644
--- a/lib/commands/BRPOP.ts
+++ b/lib/commands/BRPOP.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string | Array, timeout: number): Array {
+export function transformArguments(key: string | Array, timeout: number): TransformArgumentsReply {
const args = pushVerdictArguments(['BRPOP'], key);
args.push(timeout.toString());
diff --git a/lib/commands/BZPOPMAX.ts b/lib/commands/BZPOPMAX.ts
index ccd84272a50..3db9ca42cbb 100644
--- a/lib/commands/BZPOPMAX.ts
+++ b/lib/commands/BZPOPMAX.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string | Array, timeout: number): Array {
+export function transformArguments(key: string | Array, timeout: number): TransformArgumentsReply {
const args = pushVerdictArguments(['BZPOPMAX'], key);
args.push(timeout.toString());
diff --git a/lib/commands/BZPOPMIN.ts b/lib/commands/BZPOPMIN.ts
index 0c299cdb9df..9106ae770da 100644
--- a/lib/commands/BZPOPMIN.ts
+++ b/lib/commands/BZPOPMIN.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string | Array, timeout: number): Array {
+export function transformArguments(key: string | Array, timeout: number): TransformArgumentsReply {
const args = pushVerdictArguments(['BZPOPMIN'], key);
args.push(timeout.toString());
diff --git a/lib/commands/DEL.ts b/lib/commands/DEL.ts
index 3d9a78212f8..f96b6988f1c 100644
--- a/lib/commands/DEL.ts
+++ b/lib/commands/DEL.ts
@@ -1,6 +1,7 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
-export function transformArguments(keys: string | Array): Array {
+export function transformArguments(keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['DEL'], keys);
}
diff --git a/lib/commands/EXISTS.ts b/lib/commands/EXISTS.ts
index 5a76ca833fb..00d10b9eebc 100644
--- a/lib/commands/EXISTS.ts
+++ b/lib/commands/EXISTS.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
-export function transformArguments(keys: string | Array): Array {
+export function transformArguments(keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['EXISTS'], keys);
}
diff --git a/lib/commands/GEOHASH.ts b/lib/commands/GEOHASH.ts
index a46738955d3..a95ae443408 100644
--- a/lib/commands/GEOHASH.ts
+++ b/lib/commands/GEOHASH.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
-export function transformArguments(key: string, member: string | Array): Array {
+export function transformArguments(key: string, member: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['GEOHASH', key], member);
}
diff --git a/lib/commands/GEOPOS.ts b/lib/commands/GEOPOS.ts
index 46b0a153ba9..893048cf6da 100644
--- a/lib/commands/GEOPOS.ts
+++ b/lib/commands/GEOPOS.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
-export function transformArguments(key: string, member: string | Array): Array {
+export function transformArguments(key: string, member: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['GEOPOS', key], member);
}
diff --git a/lib/commands/GET.ts b/lib/commands/GET.ts
index 714ad953d8e..6c6475a9d24 100644
--- a/lib/commands/GET.ts
+++ b/lib/commands/GET.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { transformReplyString } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
-export function transformArguments(key: string): Array {
+export function transformArguments(key: string | Buffer): TransformArgumentsReply {
return ['GET', key];
}
diff --git a/lib/commands/GET_BUFFER.spec.ts b/lib/commands/GET_BUFFER.spec.ts
new file mode 100644
index 00000000000..533eb808c49
--- /dev/null
+++ b/lib/commands/GET_BUFFER.spec.ts
@@ -0,0 +1,22 @@
+import { strict as assert } from 'assert';
+import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
+
+describe('GET_BUFFER', () => {
+ itWithClient(TestRedisServers.OPEN, 'client.getBuffer', async client => {
+ const buffer = Buffer.from('string');
+ await client.set('key', buffer);
+ assert.deepEqual(
+ buffer,
+ await client.getBuffer('key')
+ );
+ });
+
+ itWithCluster(TestRedisClusters.OPEN, 'cluster.getBuffer', async cluster => {
+ const buffer = Buffer.from('string');
+ await cluster.set('key', buffer);
+ assert.deepEqual(
+ buffer,
+ await cluster.getBuffer('key')
+ );
+ });
+});
diff --git a/lib/commands/GET_BUFFER.ts b/lib/commands/GET_BUFFER.ts
new file mode 100644
index 00000000000..3d6f454898b
--- /dev/null
+++ b/lib/commands/GET_BUFFER.ts
@@ -0,0 +1,7 @@
+import { transformReplyBuffer } from './generic-transformers';
+
+export { FIRST_KEY_INDEX, IS_READ_ONLY, transformArguments } from './GET';
+
+export const BUFFER_MODE = true;
+
+export const transformReply = transformReplyBuffer;
diff --git a/lib/commands/HDEL.ts b/lib/commands/HDEL.ts
index ee961931449..4785b0e67f9 100644
--- a/lib/commands/HDEL.ts
+++ b/lib/commands/HDEL.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, field: string | Array): Array {
+export function transformArguments(key: string, field: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['HDEL', key], field);
}
diff --git a/lib/commands/HMGET.ts b/lib/commands/HMGET.ts
index fc0f91d8224..9f26eeba640 100644
--- a/lib/commands/HMGET.ts
+++ b/lib/commands/HMGET.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
-export function transformArguments(key: string, fields: string | Array): Array {
+export function transformArguments(key: string, fields: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['HMGET', key], fields);
}
diff --git a/lib/commands/LPUSH.ts b/lib/commands/LPUSH.ts
index 434ad619cb7..7416d4946ea 100644
--- a/lib/commands/LPUSH.ts
+++ b/lib/commands/LPUSH.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, elements: string | Array): Array {
+export function transformArguments(key: string, elements: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['LPUSH', key], elements);}
export const transformReply = transformReplyNumber;
diff --git a/lib/commands/LPUSHX.ts b/lib/commands/LPUSHX.ts
index f1a989d9625..f89623ace3a 100644
--- a/lib/commands/LPUSHX.ts
+++ b/lib/commands/LPUSHX.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, element: string | Array): Array {
+export function transformArguments(key: string, element: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['LPUSHX', key], element);
}
diff --git a/lib/commands/PFADD.ts b/lib/commands/PFADD.ts
index 3348a98852a..cc99bed7f65 100644
--- a/lib/commands/PFADD.ts
+++ b/lib/commands/PFADD.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, element: string | Array): Array {
+export function transformArguments(key: string, element: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['PFADD', key], element);
}
diff --git a/lib/commands/PFCOUNT.ts b/lib/commands/PFCOUNT.ts
index eac710a3543..52963697adf 100644
--- a/lib/commands/PFCOUNT.ts
+++ b/lib/commands/PFCOUNT.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string | Array): Array {
+export function transformArguments(key: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['PFCOUNT'], key);
}
diff --git a/lib/commands/PFMERGE.ts b/lib/commands/PFMERGE.ts
index 73a4a2edb9a..c4ba11877f7 100644
--- a/lib/commands/PFMERGE.ts
+++ b/lib/commands/PFMERGE.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(destination: string, source: string | Array): Array {
+export function transformArguments(destination: string, source: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['PFMERGE', destination], source);
}
diff --git a/lib/commands/RPUSH.ts b/lib/commands/RPUSH.ts
index 191d2704e09..665094f47a5 100644
--- a/lib/commands/RPUSH.ts
+++ b/lib/commands/RPUSH.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, element: string | Array): Array {
+export function transformArguments(key: string, element: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['RPUSH', key], element);
}
diff --git a/lib/commands/RPUSHX.ts b/lib/commands/RPUSHX.ts
index a07615a58e0..fe1f969f3f6 100644
--- a/lib/commands/RPUSHX.ts
+++ b/lib/commands/RPUSHX.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, element: string | Array): Array {
+export function transformArguments(key: string, element: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['RPUSHX', key], element);
}
diff --git a/lib/commands/SADD.ts b/lib/commands/SADD.ts
index a14ba1686c0..a432ccfef59 100644
--- a/lib/commands/SADD.ts
+++ b/lib/commands/SADD.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, members: string | Array): Array {
+export function transformArguments(key: string, members: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SADD', key], members);
}
diff --git a/lib/commands/SCRIPT_EXISTS.ts b/lib/commands/SCRIPT_EXISTS.ts
index b127a0b261b..47a7f456e9b 100644
--- a/lib/commands/SCRIPT_EXISTS.ts
+++ b/lib/commands/SCRIPT_EXISTS.ts
@@ -1,6 +1,7 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyBooleanArray } from './generic-transformers';
-export function transformArguments(sha1: string | Array): Array {
+export function transformArguments(sha1: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SCRIPT', 'EXISTS'], sha1);
}
diff --git a/lib/commands/SDIFF.ts b/lib/commands/SDIFF.ts
index 496ed593370..4d5aaea1a06 100644
--- a/lib/commands/SDIFF.ts
+++ b/lib/commands/SDIFF.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(keys: string | Array): Array {
+export function transformArguments(keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SDIFF'], keys);
}
diff --git a/lib/commands/SDIFFSTORE.ts b/lib/commands/SDIFFSTORE.ts
index 295433602fb..69883d4124c 100644
--- a/lib/commands/SDIFFSTORE.ts
+++ b/lib/commands/SDIFFSTORE.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(destination: string, keys: string | Array): Array {
+export function transformArguments(destination: string, keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SDIFFSTORE', destination], keys);
}
diff --git a/lib/commands/SET.spec.ts b/lib/commands/SET.spec.ts
index a587f6c3120..32d138f2920 100644
--- a/lib/commands/SET.spec.ts
+++ b/lib/commands/SET.spec.ts
@@ -106,7 +106,7 @@ describe('SET', () => {
'OK'
);
});
-
+
itWithClient(TestRedisServers.OPEN, 'with GET on empty key', async client => {
assert.equal(
await client.set('key', 'value', {
diff --git a/lib/commands/SET.ts b/lib/commands/SET.ts
index 4d5919cde21..03853b3f7d6 100644
--- a/lib/commands/SET.ts
+++ b/lib/commands/SET.ts
@@ -1,3 +1,5 @@
+import { TransformArgumentsReply } from '.';
+
export const FIRST_KEY_INDEX = 1;
interface EX {
@@ -38,7 +40,7 @@ interface SetCommonOptions {
type SetOptions = SetTTL & SetGuards & (SetCommonOptions | {});
-export function transformArguments(key: string, value: string, options?: SetOptions): Array {
+export function transformArguments(key: string | Buffer, value: string | Buffer, options?: SetOptions): TransformArgumentsReply {
const args = ['SET', key, value];
if (!options) {
diff --git a/lib/commands/SETEX.ts b/lib/commands/SETEX.ts
index 57c32db6ffe..320278c9264 100644
--- a/lib/commands/SETEX.ts
+++ b/lib/commands/SETEX.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { transformReplyString } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, seconds: number, value: string): Array {
+export function transformArguments(key: string | Buffer, seconds: number, value: string): TransformArgumentsReply {
return [
'SETEX',
key,
diff --git a/lib/commands/SINTER.ts b/lib/commands/SINTER.ts
index 104e81b9214..43869652370 100644
--- a/lib/commands/SINTER.ts
+++ b/lib/commands/SINTER.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(keys: string | Array): Array {
+export function transformArguments(keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SINTER'], keys);
}
diff --git a/lib/commands/SINTERSTORE.ts b/lib/commands/SINTERSTORE.ts
index a7a4d4fd106..5ad1b11cbac 100644
--- a/lib/commands/SINTERSTORE.ts
+++ b/lib/commands/SINTERSTORE.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(destination: string, keys: string | Array): Array {
+export function transformArguments(destination: string, keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SINTERSTORE', destination], keys);
}
diff --git a/lib/commands/SREM.ts b/lib/commands/SREM.ts
index d1021bb3a19..4ae33245d29 100644
--- a/lib/commands/SREM.ts
+++ b/lib/commands/SREM.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, members: string | Array): Array {
+export function transformArguments(key: string, members: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SREM', key], members);
}
diff --git a/lib/commands/SUNION.ts b/lib/commands/SUNION.ts
index 3f06138b1b6..705bff29927 100644
--- a/lib/commands/SUNION.ts
+++ b/lib/commands/SUNION.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
-export function transformArguments(keys: string | Array): Array {
+export function transformArguments(keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SUNION'], keys);
}
diff --git a/lib/commands/SUNIONSTORE.ts b/lib/commands/SUNIONSTORE.ts
index 7a1aab80117..af717f627df 100644
--- a/lib/commands/SUNIONSTORE.ts
+++ b/lib/commands/SUNIONSTORE.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(destination: string, keys: string | Array): Array {
+export function transformArguments(destination: string, keys: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['SUNIONSTORE', destination], keys);
}
diff --git a/lib/commands/TOUCH.ts b/lib/commands/TOUCH.ts
index f2fb0548970..abff4160392 100644
--- a/lib/commands/TOUCH.ts
+++ b/lib/commands/TOUCH.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string | Array): Array {
+export function transformArguments(key: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['TOUCH'], key);
}
diff --git a/lib/commands/UNLINK.ts b/lib/commands/UNLINK.ts
index 9dfe0ca48ea..4647a976e42 100644
--- a/lib/commands/UNLINK.ts
+++ b/lib/commands/UNLINK.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string | Array): Array {
+export function transformArguments(key: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['UNLINK'], key);
}
diff --git a/lib/commands/WATCH.ts b/lib/commands/WATCH.ts
index 5e24ca37952..e644ab0f462 100644
--- a/lib/commands/WATCH.ts
+++ b/lib/commands/WATCH.ts
@@ -1,6 +1,7 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
-export function transformArguments(key: string | Array): Array {
+export function transformArguments(key: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['WATCH'], key);
}
diff --git a/lib/commands/XACK.ts b/lib/commands/XACK.ts
index 969f9b6a8b9..a6de28151eb 100644
--- a/lib/commands/XACK.ts
+++ b/lib/commands/XACK.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, group: string, id: string | Array): Array {
+export function transformArguments(key: string, group: string, id: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['XACK', key, group], id);
}
diff --git a/lib/commands/XDEL.ts b/lib/commands/XDEL.ts
index 9d173271c28..083ea77ef0f 100644
--- a/lib/commands/XDEL.ts
+++ b/lib/commands/XDEL.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, id: string | Array): Array {
+export function transformArguments(key: string, id: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['XDEL', key], id);
}
diff --git a/lib/commands/ZDIFF.ts b/lib/commands/ZDIFF.ts
index f557b597ec4..7154947fea7 100644
--- a/lib/commands/ZDIFF.ts
+++ b/lib/commands/ZDIFF.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 2;
export const IS_READ_ONLY = true;
-export function transformArguments(keys: Array | string): Array {
+export function transformArguments(keys: Array | string): TransformArgumentsReply {
return pushVerdictArgument(['ZDIFF'], keys);
}
diff --git a/lib/commands/ZDIFFSTORE.ts b/lib/commands/ZDIFFSTORE.ts
index de409c0939a..f91d4c869ba 100644
--- a/lib/commands/ZDIFFSTORE.ts
+++ b/lib/commands/ZDIFFSTORE.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(destination: string, keys: Array | string): Array {
+export function transformArguments(destination: string, keys: Array | string): TransformArgumentsReply {
return pushVerdictArgument(['ZDIFFSTORE', destination], keys);
}
diff --git a/lib/commands/ZDIFF_WITHSCORES.ts b/lib/commands/ZDIFF_WITHSCORES.ts
index 26effab7189..84126853361 100644
--- a/lib/commands/ZDIFF_WITHSCORES.ts
+++ b/lib/commands/ZDIFF_WITHSCORES.ts
@@ -1,9 +1,10 @@
+import { TransformArgumentsReply } from '.';
import { transformReplySortedSetWithScores } from './generic-transformers';
import { transformArguments as transformZDiffArguments } from './ZDIFF';
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZDIFF';
-export function transformArguments(...args: Parameters): Array {
+export function transformArguments(...args: Parameters): TransformArgumentsReply {
return [
...transformZDiffArguments(...args),
'WITHSCORES'
diff --git a/lib/commands/ZINTER.ts b/lib/commands/ZINTER.ts
index 90a42eda0d3..91d7982a8e7 100644
--- a/lib/commands/ZINTER.ts
+++ b/lib/commands/ZINTER.ts
@@ -1,3 +1,4 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 2;
@@ -9,7 +10,7 @@ interface ZInterOptions {
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
}
-export function transformArguments(keys: Array | string, options?: ZInterOptions): Array {
+export function transformArguments(keys: Array | string, options?: ZInterOptions): TransformArgumentsReply {
const args = pushVerdictArgument(['ZINTER'], keys);
if (options?.WEIGHTS) {
diff --git a/lib/commands/ZINTERSTORE.ts b/lib/commands/ZINTERSTORE.ts
index a026916ce1f..6e79e423cb0 100644
--- a/lib/commands/ZINTERSTORE.ts
+++ b/lib/commands/ZINTERSTORE.ts
@@ -1,3 +1,4 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
@@ -7,7 +8,7 @@ interface ZInterStoreOptions {
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
}
-export function transformArguments(destination: string, keys: Array | string, options?: ZInterStoreOptions): Array {
+export function transformArguments(destination: string, keys: Array | string, options?: ZInterStoreOptions): TransformArgumentsReply {
const args = pushVerdictArgument(['ZINTERSTORE', destination], keys);
if (options?.WEIGHTS) {
diff --git a/lib/commands/ZINTER_WITHSCORES.ts b/lib/commands/ZINTER_WITHSCORES.ts
index 0a82228fce9..f4287d1a684 100644
--- a/lib/commands/ZINTER_WITHSCORES.ts
+++ b/lib/commands/ZINTER_WITHSCORES.ts
@@ -1,9 +1,10 @@
+import { TransformArgumentsReply } from '.';
import { transformReplySortedSetWithScores } from './generic-transformers';
import { transformArguments as transformZInterArguments } from './ZINTER';
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZINTER';
-export function transformArguments(...args: Parameters): Array {
+export function transformArguments(...args: Parameters): TransformArgumentsReply {
return [
...transformZInterArguments(...args),
'WITHSCORES'
diff --git a/lib/commands/ZMSCORE.ts b/lib/commands/ZMSCORE.ts
index 8a6f73c7836..373adac3cf0 100644
--- a/lib/commands/ZMSCORE.ts
+++ b/lib/commands/ZMSCORE.ts
@@ -1,10 +1,11 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumberInfinityNullArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
export const IS_READ_ONLY = true;
-export function transformArguments(key: string, member: string | Array): Array {
+export function transformArguments(key: string, member: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['ZMSCORE', key], member);
}
diff --git a/lib/commands/ZREM.ts b/lib/commands/ZREM.ts
index 089b6136afd..8419291f2fd 100644
--- a/lib/commands/ZREM.ts
+++ b/lib/commands/ZREM.ts
@@ -1,8 +1,9 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
-export function transformArguments(key: string, member: string | Array): Array {
+export function transformArguments(key: string, member: string | Array): TransformArgumentsReply {
return pushVerdictArguments(['ZREM', key], member);
}
diff --git a/lib/commands/ZUNION.ts b/lib/commands/ZUNION.ts
index efdfccb1ff4..87158b8425a 100644
--- a/lib/commands/ZUNION.ts
+++ b/lib/commands/ZUNION.ts
@@ -1,3 +1,4 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
export const FIRST_KEY_INDEX = 2;
@@ -9,7 +10,7 @@ interface ZUnionOptions {
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
}
-export function transformArguments(keys: Array | string, options?: ZUnionOptions): Array {
+export function transformArguments(keys: Array | string, options?: ZUnionOptions): TransformArgumentsReply {
const args = pushVerdictArgument(['ZUNION'], keys);
if (options?.WEIGHTS) {
diff --git a/lib/commands/ZUNIONSTORE.ts b/lib/commands/ZUNIONSTORE.ts
index c03f1203706..4ebbdbd8591 100644
--- a/lib/commands/ZUNIONSTORE.ts
+++ b/lib/commands/ZUNIONSTORE.ts
@@ -1,3 +1,4 @@
+import { TransformArgumentsReply } from '.';
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
export const FIRST_KEY_INDEX = 1;
@@ -7,7 +8,7 @@ interface ZUnionOptions {
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
}
-export function transformArguments(destination: string, keys: Array | string, options?: ZUnionOptions): Array {
+export function transformArguments(destination: string, keys: Array | string, options?: ZUnionOptions): TransformArgumentsReply {
const args = pushVerdictArgument(['ZUNIONSTORE', destination], keys);
if (options?.WEIGHTS) {
diff --git a/lib/commands/ZUNION_WITHSCORES.ts b/lib/commands/ZUNION_WITHSCORES.ts
index d0cef45cfb1..2215dad9749 100644
--- a/lib/commands/ZUNION_WITHSCORES.ts
+++ b/lib/commands/ZUNION_WITHSCORES.ts
@@ -1,9 +1,10 @@
+import { TransformArgumentsReply } from '.';
import { transformReplySortedSetWithScores } from './generic-transformers';
import { transformArguments as transformZUnionArguments } from './ZUNION';
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZUNION';
-export function transformArguments(...args: Parameters): Array {
+export function transformArguments(...args: Parameters): TransformArgumentsReply {
return [
...transformZUnionArguments(...args),
'WITHSCORES'
diff --git a/lib/commands/generic-transformers.ts b/lib/commands/generic-transformers.ts
index 8105bfe903f..496745cb1f1 100644
--- a/lib/commands/generic-transformers.ts
+++ b/lib/commands/generic-transformers.ts
@@ -20,6 +20,10 @@ export function transformReplyString(reply: string): string {
return reply;
}
+export function transformReplyBuffer(reply: Buffer): Buffer {
+ return reply;
+}
+
export function transformReplyStringNull(reply: string | null): string | null {
return reply;
}
@@ -352,11 +356,11 @@ export function pushStringTuplesArguments(args: Array, tuples: StringTup
return args;
}
-export function pushVerdictArguments(args: TransformArgumentsReply, value: string | Array): TransformArgumentsReply {
- if (typeof value === 'string') {
- args.push(value);
- } else {
+export function pushVerdictArguments(args: TransformArgumentsReply, value: string | Buffer | Array): TransformArgumentsReply {
+ if (Array.isArray(value)) {
args.push(...value);
+ } else {
+ args.push(value);
}
return args;
diff --git a/lib/commands/index.ts b/lib/commands/index.ts
index cffb47c668a..dce28ac0937 100644
--- a/lib/commands/index.ts
+++ b/lib/commands/index.ts
@@ -61,6 +61,7 @@ import * as GEOPOS from './GEOPOS';
import * as GEOSEARCH_WITH from './GEOSEARCH_WITH';
import * as GEOSEARCH from './GEOSEARCH';
import * as GEOSEARCHSTORE from './GEOSEARCHSTORE';
+import * as GET_BUFFER from './GET_BUFFER';
import * as GET from './GET';
import * as GETBIT from './GETBIT';
import * as GETDEL from './GETDEL';
@@ -370,6 +371,8 @@ export default {
geoSearch: GEOSEARCH,
GEOSEARCHSTORE,
geoSearchStore: GEOSEARCHSTORE,
+ GET_BUFFER,
+ getBuffer: GET_BUFFER,
GET,
get: GET,
GETBIT,
@@ -733,15 +736,16 @@ export default {
zUnionStore: ZUNIONSTORE
};
-export type RedisReply = string | number | Array | null | undefined;
+export type RedisReply = string | number | Buffer | Array | null | undefined;
-export type TransformArgumentsReply = Array & { preserve?: unknown };
+export type TransformArgumentsReply = Array & { preserve?: unknown };
export interface RedisCommand {
FIRST_KEY_INDEX?: number | ((...args: Array) => string);
IS_READ_ONLY?: boolean;
transformArguments(...args: Array): TransformArgumentsReply;
- transformReply(reply: RedisReply, preserved: unknown): any;
+ BUFFER_MODE?: boolean;
+ transformReply(reply: RedisReply, preserved?: unknown): any;
}
export interface RedisCommands {
diff --git a/lib/multi-command.spec.ts b/lib/multi-command.spec.ts
index a78cc8b2e08..52ecfb94b1c 100644
--- a/lib/multi-command.spec.ts
+++ b/lib/multi-command.spec.ts
@@ -1,6 +1,5 @@
import { strict as assert } from 'assert';
import RedisMultiCommand from './multi-command';
-import { encodeCommand } from './commander';
import { WatchError } from './errors';
import { spy } from 'sinon';
import { SQUARE_SCRIPT } from './client.spec';
@@ -10,11 +9,11 @@ describe('Multi Command', () => {
it('simple', async () => {
const multi = RedisMultiCommand.create((queue, symbol) => {
assert.deepEqual(
- queue.map(({encodedCommand}) => encodedCommand),
+ queue.map(({ args }) => args),
[
- encodeCommand(['MULTI']),
- encodeCommand(['PING']),
- encodeCommand(['EXEC']),
+ ['MULTI'],
+ ['PING'],
+ ['EXEC'],
]
);
@@ -55,8 +54,8 @@ describe('Multi Command', () => {
it('execAsPipeline', async () => {
const multi = RedisMultiCommand.create(queue => {
assert.deepEqual(
- queue.map(({encodedCommand}) => encodedCommand),
- [encodeCommand(['PING'])]
+ queue.map(({ args }) => args),
+ [['PING']]
);
return Promise.resolve(['PONG']);
@@ -75,8 +74,8 @@ describe('Multi Command', () => {
it('simple', async () => {
const multi = RedisMultiCommand.create(queue => {
assert.deepEqual(
- queue.map(({encodedCommand}) => encodedCommand),
- [encodeCommand(['PING'])]
+ queue.map(({ args }) => args),
+ [['PING']]
);
return Promise.resolve(['PONG']);
@@ -111,10 +110,10 @@ describe('Multi Command', () => {
assert.deepEqual(
await new MultiWithScript(queue => {
assert.deepEqual(
- queue.map(({encodedCommand}) => encodedCommand),
+ queue.map(({ args }) => args),
[
- encodeCommand(['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '2']),
- encodeCommand(['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '3']),
+ ['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '2'],
+ ['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '3'],
]
);
diff --git a/lib/multi-command.ts b/lib/multi-command.ts
index c8a50765967..53f439d8f36 100644
--- a/lib/multi-command.ts
+++ b/lib/multi-command.ts
@@ -2,7 +2,7 @@ import COMMANDS, { TransformArgumentsReply } from './commands';
import { RedisCommand, RedisModules, RedisReply } from './commands';
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
import { RedisClientOptions } from './client';
-import { extendWithModulesAndScripts, extendWithDefaultCommands, encodeCommand } from './commander';
+import { extendWithModulesAndScripts, extendWithDefaultCommands } from './commander';
import { WatchError } from './errors';
type RedisMultiCommandSignature = (...args: Parameters) => RedisMultiCommandType;
@@ -24,7 +24,7 @@ type WithScripts