import COMMANDS from './commands/client'; import { RedisCommand, RedisModule, RedisModules, RedisReply } from './commands'; import RedisCommandsQueue from './commands-queue'; type RedisMultiCommandSignature = (...args: Parameters) => RedisMultiCommandType; type RedisMultiWithCommands = { [P in keyof typeof COMMANDS]: RedisMultiCommandSignature<(typeof COMMANDS)[P], M> }; type RedisMultiWithModules> = { [P in keyof M[number]]: RedisMultiCommandSignature }; export type RedisMultiCommandType = RedisMultiCommand & RedisMultiWithCommands & RedisMultiWithModules; export interface MultiQueuedCommand { encodedCommand: string; transformReply?: RedisCommand['transformReply']; } export type RedisMultiExecutor = (encodedCommands: Array, chainId: Symbol) => Promise>; export default class RedisMultiCommand { static defineCommand(on: any, name: string, command: RedisCommand) { on[name] = function (...args: Array) { return this.addCommand(command.transformArguments(...args), command.transformReply); }; } static create(executor: RedisMultiExecutor, modules?: M): RedisMultiCommandType { return new RedisMultiCommand(executor, modules); } readonly #executor: RedisMultiExecutor; readonly #queue: Array = []; constructor(executor: RedisMultiExecutor, modules?: RedisModules) { this.#executor = executor; this.#initiateModules(modules); } #initiateModules(modules?: RedisModules) { if (!modules) return; for (const m of modules) { for (const [name, command] of Object.entries(m)) { RedisMultiCommand.defineCommand(this, name, command); } } } addCommand(args: Array, transformReply?: RedisCommand['transformReply']): this { this.#queue.push({ encodedCommand: RedisCommandsQueue.encodeCommand(args), transformReply }); return this; } async exec(): Promise> { const results = await this.#executor(this.#queue, Symbol('[RedisMultiCommand] Chain ID')); return this.#queue.map(({transformReply}, i) => { const reply = results[i]; return transformReply ? transformReply(reply) : reply; }); }; } for (const [name, command] of Object.entries(COMMANDS)) { RedisMultiCommand.defineCommand(RedisMultiCommand.prototype, name, command); }