1
0
mirror of https://github.com/redis/node-redis.git synced 2025-12-09 21:21:11 +03:00

fix: add typed/untyped mode support for multi-commands (#3084)

This commit is contained in:
Pavel Pashov
2025-10-01 16:33:22 +03:00
committed by Nikolay Karadzhov
parent 7b56e9a3dc
commit 17fdb8c667
4 changed files with 30 additions and 8 deletions

View File

@@ -10,7 +10,7 @@ import { TcpSocketConnectOpts } from 'node:net';
import { PUBSUB_TYPE, PubSubType, PubSubListener, PubSubTypeListeners, ChannelListeners } from './pub-sub';
import { Command, CommandSignature, TypeMapping, CommanderConfig, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, ReplyUnion, RespVersions, RedisArgument, ReplyWithTypeMapping, SimpleStringReply, TransformReply, CommandArguments } from '../RESP/types';
import RedisClientMultiCommand, { RedisClientMultiCommandType } from './multi-command';
import { RedisMultiQueuedCommand } from '../multi-command';
import { MULTI_MODE, MultiMode, RedisMultiQueuedCommand } from '../multi-command';
import HELLO, { HelloOptions } from '../commands/HELLO';
import { ScanOptions, ScanCommonOptions } from '../commands/SCAN';
import { RedisLegacyClient, RedisLegacyClientType } from './legacy-mode';
@@ -1187,8 +1187,8 @@ export default class RedisClient<
return execResult as Array<unknown>;
}
MULTI() {
type Multi = new (...args: ConstructorParameters<typeof RedisClientMultiCommand>) => RedisClientMultiCommandType<[], M, F, S, RESP, TYPE_MAPPING>;
MULTI<isTyped extends MultiMode = MULTI_MODE['TYPED']>() {
type Multi = new (...args: ConstructorParameters<typeof RedisClientMultiCommand>) => RedisClientMultiCommandType<isTyped, [], M, F, S, RESP, TYPE_MAPPING>;
return new ((this as any).Multi as Multi)(
this._executeMulti.bind(this),
this._executePipeline.bind(this),

View File

@@ -1,5 +1,5 @@
import COMMANDS from '../commands';
import RedisMultiCommand, { MULTI_REPLY, MultiReply, MultiReplyType, RedisMultiQueuedCommand } from '../multi-command';
import RedisMultiCommand, { MULTI_MODE, MULTI_REPLY, MultiMode, MultiReply, MultiReplyType, RedisMultiQueuedCommand } from '../multi-command';
import { ReplyWithTypeMapping, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, TypeMapping } from '../RESP/types';
import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander';
import { BasicCommandParser } from './parser';
@@ -13,7 +13,7 @@ type CommandSignature<
S extends RedisScripts,
RESP extends RespVersions,
TYPE_MAPPING extends TypeMapping
> = (...args: Tail<Parameters<C['parseCommand']>>) => RedisClientMultiCommandType<
> = (...args: Tail<Parameters<C['parseCommand']>>) => InternalRedisClientMultiCommandType<
[...REPLIES, ReplyWithTypeMapping<CommandReply<C, RESP>, TYPE_MAPPING>],
M,
F,
@@ -70,7 +70,7 @@ type WithScripts<
[P in keyof S]: CommandSignature<REPLIES, S[P], M, F, S, RESP, TYPE_MAPPING>;
};
export type RedisClientMultiCommandType<
type InternalRedisClientMultiCommandType<
REPLIES extends Array<any>,
M extends RedisModules,
F extends RedisFunctions,
@@ -85,6 +85,19 @@ export type RedisClientMultiCommandType<
WithScripts<REPLIES, M, F, S, RESP, TYPE_MAPPING>
);
type TypedOrAny<Flag extends MultiMode, T> =
[Flag] extends [MULTI_MODE['TYPED']] ? T : any;
export type RedisClientMultiCommandType<
isTyped extends MultiMode,
REPLIES extends Array<any>,
M extends RedisModules,
F extends RedisFunctions,
S extends RedisScripts,
RESP extends RespVersions,
TYPE_MAPPING extends TypeMapping
> = TypedOrAny<isTyped, InternalRedisClientMultiCommandType<REPLIES, M, F, S, RESP, TYPE_MAPPING>>;
type ExecuteMulti = (commands: Array<RedisMultiQueuedCommand>, selectedDB?: number) => Promise<Array<unknown>>;
export default class RedisClientMultiCommand<REPLIES = []> {

View File

@@ -10,6 +10,7 @@ import RedisClientMultiCommand, { RedisClientMultiCommandType } from './multi-co
import { BasicPooledClientSideCache, ClientSideCacheConfig, PooledClientSideCacheProvider } from './cache';
import { BasicCommandParser } from './parser';
import SingleEntryCache from '../single-entry-cache';
import { MULTI_MODE, MultiMode } from '../multi-command';
export interface RedisPoolOptions {
/**
@@ -486,8 +487,9 @@ export class RedisClientPool<
return this.execute(client => client.sendCommand(args, options));
}
MULTI() {
type Multi = new (...args: ConstructorParameters<typeof RedisClientMultiCommand>) => RedisClientMultiCommandType<[], M, F, S, RESP, TYPE_MAPPING>;
MULTI<isTyped extends MultiMode = MULTI_MODE['TYPED']>() {
type Multi = new (...args: ConstructorParameters<typeof RedisClientMultiCommand>) => RedisClientMultiCommandType<isTyped, [], M, F, S, RESP, TYPE_MAPPING>;
return new ((this as any).Multi as Multi)(
(commands, selectedDB) => this.execute(client => client._executeMulti(commands, selectedDB)),
commands => this.execute(client => client._executePipeline(commands)),

View File

@@ -6,6 +6,13 @@ export type MULTI_REPLY = {
TYPED: 'typed';
};
export type MULTI_MODE = {
TYPED: 'typed';
UNTYPED: 'untyped';
};
export type MultiMode = MULTI_MODE[keyof MULTI_MODE];
export type MultiReply = MULTI_REPLY[keyof MULTI_REPLY];
export type MultiReplyType<T extends MultiReply, REPLIES> = T extends MULTI_REPLY['TYPED'] ? REPLIES : Array<ReplyUnion>;