import COMMANDS, { RedisCommand, RedisModules, TransformArgumentsReply } from './commands'; import { RedisLuaScript, RedisLuaScripts } from './lua-script'; import { CommandOptions, isCommandOptions } from './command-options'; type Instantiable = new(...args: Array) => T; type CommandExecutor = (this: InstanceType, command: RedisCommand, args: Array) => unknown; export function extendWithDefaultCommands(BaseClass: T, executor: CommandExecutor): void { for (const [name, command] of Object.entries(COMMANDS)) { BaseClass.prototype[name] = function (...args: Array): unknown { return executor.call(this, command, args); }; } } interface ExtendWithModulesAndScriptsConfig< T extends Instantiable, M extends RedisModules, S extends RedisLuaScripts > { BaseClass: T; modules: M | undefined; modulesCommandsExecutor: CommandExecutor; scripts: S | undefined; scriptsExecutor(this: InstanceType, script: RedisLuaScript, args: Array): unknown; } export function extendWithModulesAndScripts< T extends Instantiable, M extends RedisModules, S extends RedisLuaScripts, >(config: ExtendWithModulesAndScriptsConfig): T { let Commander: T | undefined, modulesBaseObject: Record; if (config.modules) { modulesBaseObject = Object.create(null); Commander = class extends config.BaseClass { constructor(...args: Array) { super(...args); modulesBaseObject.self = this; } }; for (const [moduleName, module] of Object.entries(config.modules)) { Commander.prototype[moduleName] = Object.create(modulesBaseObject); for (const [commandName, command] of Object.entries(module)) { Commander.prototype[moduleName][commandName] = function (...args: Array): unknown { return config.modulesCommandsExecutor.call(this.self, command, args); }; } } } if (config.scripts) { Commander ??= class extends config.BaseClass {}; for (const [name, script] of Object.entries(config.scripts)) { Commander.prototype[name] = function (...args: Array): unknown { return config.scriptsExecutor.call(this, script, args); }; } } return (Commander ?? config.BaseClass) as any; } export function transformCommandArguments( command: RedisCommand, args: Array ): { args: TransformArgumentsReply; options: CommandOptions | undefined; } { let options; if (isCommandOptions(args[0])) { options = args[0]; args = args.slice(1); } return { args: command.transformArguments(...args), options }; }