import COMMANDS from './commands'; import { RedisCommand, RedisCommandArgument, RedisCommandArguments, RedisCommandRawReply, RedisModules, RedisPlugins, RedisScript, RedisScripts } from '../commands'; import RedisMultiCommand, { RedisMultiQueuedCommand } from '../multi-command'; import { extendWithCommands, extendWithModulesAndScripts } from '../commander'; import RedisCluster from '.'; import { ExcludeMappedString } from '../client'; type RedisClusterMultiCommandSignature = (...args: Parameters) => RedisClusterMultiCommandType; type WithCommands = { [P in keyof typeof COMMANDS]: RedisClusterMultiCommandSignature<(typeof COMMANDS)[P], M, S> }; type WithModules = { [P in keyof M as ExcludeMappedString

]: { [C in keyof M[P] as ExcludeMappedString]: RedisClusterMultiCommandSignature; }; }; type WithScripts = { [P in keyof S as ExcludeMappedString

]: RedisClusterMultiCommandSignature }; export type RedisClusterMultiCommandType = RedisClusterMultiCommand & WithCommands & WithModules & WithScripts; export type RedisClusterMultiExecutor = (queue: Array, firstKey?: RedisCommandArgument, chainId?: symbol) => Promise>; export default class RedisClusterMultiCommand { readonly #multi = new RedisMultiCommand(); readonly #executor: RedisClusterMultiExecutor; #firstKey: RedisCommandArgument | undefined; static extend( plugins?: RedisPlugins ): new (...args: ConstructorParameters) => RedisClusterMultiCommandType { return extendWithModulesAndScripts({ BaseClass: RedisClusterMultiCommand, modules: plugins?.modules, modulesCommandsExecutor: RedisClusterMultiCommand.prototype.commandsExecutor, scripts: plugins?.scripts, scriptsExecutor: RedisClusterMultiCommand.prototype.scriptsExecutor }); } constructor(executor: RedisClusterMultiExecutor, firstKey?: RedisCommandArgument) { this.#executor = executor; this.#firstKey = firstKey; } commandsExecutor(command: RedisCommand, args: Array): this { const transformedArguments = command.transformArguments(...args); if (!this.#firstKey) { this.#firstKey = RedisCluster.extractFirstKey(command, args, transformedArguments); } return this.addCommand( undefined, transformedArguments, command.transformReply ); } addCommand( firstKey: RedisCommandArgument | undefined, args: RedisCommandArguments, transformReply?: RedisCommand['transformReply'] ): this { if (!this.#firstKey) { this.#firstKey = firstKey; } this.#multi.addCommand(args, transformReply); return this; } scriptsExecutor(script: RedisScript, args: Array): this { const transformedArguments = this.#multi.addScript(script, args); if (!this.#firstKey) { this.#firstKey = RedisCluster.extractFirstKey(script, args, transformedArguments); } return this.addCommand(undefined, transformedArguments); } async exec(execAsPipeline = false): Promise> { if (execAsPipeline) { return this.execAsPipeline(); } const commands = this.#multi.exec(); if (!commands) return []; return this.#multi.handleExecReplies( await this.#executor(commands, this.#firstKey, RedisMultiCommand.generateChainId()) ); } EXEC = this.exec; async execAsPipeline(): Promise> { return this.#multi.transformReplies( await this.#executor(this.#multi.queue, this.#firstKey) ); } } extendWithCommands({ BaseClass: RedisClusterMultiCommand, commands: COMMANDS, executor: RedisClusterMultiCommand.prototype.commandsExecutor });