diff --git a/packages/client/lib/client/index.spec.ts b/packages/client/lib/client/index.spec.ts index 0b5fd05b9b..442b10ef52 100644 --- a/packages/client/lib/client/index.spec.ts +++ b/packages/client/lib/client/index.spec.ts @@ -468,6 +468,20 @@ describe('Client', () => { ['PONG'] ); }, GLOBAL.SERVERS.OPEN); + + testUtils.testWithClient('should remember selected db', async client => { + await client.multi() + .select(1) + .exec(); + await killClient(client); + assert.equal( + (await client.clientInfo()).db, + 1 + ); + }, { + ...GLOBAL.SERVERS.OPEN, + minimumDockerVersion: [6, 2] // CLIENT INFO + }); }); testUtils.testWithClient('scripts', async client => { diff --git a/packages/client/lib/client/index.ts b/packages/client/lib/client/index.ts index fb86908bd2..9664b3645b 100644 --- a/packages/client/lib/client/index.ts +++ b/packages/client/lib/client/index.ts @@ -606,18 +606,26 @@ export default class RedisClient< ); } - multiExecutor(commands: Array, chainId?: symbol): Promise> { + async multiExecutor( + commands: Array, + selectedDB?: number, + chainId?: symbol + ): Promise> { const promise = Promise.all( commands.map(({ args }) => { - return this.#queue.addCommand(args, RedisClient.commandOptions({ - chainId - })); + return this.#queue.addCommand(args, { chainId }); }) ); this.#tick(); - return promise; + const results = await promise; + + if (selectedDB !== undefined) { + this.#selectedDB = selectedDB; + } + + return results; } async* scanIterator(options?: ScanCommandOptions): AsyncIterable { diff --git a/packages/client/lib/client/multi-command.ts b/packages/client/lib/client/multi-command.ts index 2eea429abe..1d6df1a483 100644 --- a/packages/client/lib/client/multi-command.ts +++ b/packages/client/lib/client/multi-command.ts @@ -58,13 +58,13 @@ type InstantiableRedisMultiCommand< S extends RedisScripts > = new (...args: ConstructorParameters) => RedisClientMultiCommandType; - -export type RedisClientMultiExecutor = (queue: Array, chainId?: symbol) => Promise>; +export type RedisClientMultiExecutor = ( + queue: Array, + selectedDB?: number, + chainId?: symbol +) => Promise>; export default class RedisClientMultiCommand { - readonly #multi = new RedisMultiCommand(); - readonly #executor: RedisClientMultiExecutor; - static extend< M extends RedisModules, F extends RedisFunctions, @@ -81,7 +81,10 @@ export default class RedisClientMultiCommand { }); } + readonly #multi = new RedisMultiCommand(); + readonly #executor: RedisClientMultiExecutor; readonly v4: Record = {}; + #selectedDB?: number; constructor(executor: RedisClientMultiExecutor, legacyMode = false) { this.#executor = executor; @@ -136,6 +139,13 @@ export default class RedisClientMultiCommand { ); } + SELECT(db: number, transformReply?: RedisCommand['transformReply']): this { + this.#selectedDB = db; + return this.addCommand(['SELECT', db.toString()], transformReply); + } + + select = this.SELECT; + addCommand(args: RedisCommandArguments, transformReply?: RedisCommand['transformReply']): this { this.#multi.addCommand(args, transformReply); return this; @@ -160,7 +170,11 @@ export default class RedisClientMultiCommand { if (!commands) return []; return this.#multi.handleExecReplies( - await this.#executor(commands, RedisMultiCommand.generateChainId()) + await this.#executor( + commands, + this.#selectedDB, + RedisMultiCommand.generateChainId() + ) ); } @@ -168,7 +182,10 @@ export default class RedisClientMultiCommand { async execAsPipeline(): Promise> { return this.#multi.transformReplies( - await this.#executor(this.#multi.queue) + await this.#executor( + this.#multi.queue, + this.#selectedDB + ) ); } } diff --git a/packages/client/lib/cluster/index.ts b/packages/client/lib/cluster/index.ts index f1a4cb42af..57ec6ff705 100644 --- a/packages/client/lib/cluster/index.ts +++ b/packages/client/lib/cluster/index.ts @@ -230,7 +230,7 @@ export default class RedisCluster< return this.#execute( firstKey, false, - client => client.multiExecutor(commands, chainId) + client => client.multiExecutor(commands, undefined, chainId) ); }, routing