1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-06 02:15:48 +03:00

new "transform arguments" API for better key and metadata extraction (#2733)

* Parser support with all commands

* remove "dist" from all imports for consistency

* address most of my review comments

* small tweak to multi type mapping handling

* tweak multi commands / fix addScript cases

* nits

* addressed all in person review comments

* revert addCommand/addScript changes to multi-commands

addCommand needs to be there for sendCommand like ability within a multi.

If its there, it might as well be used by createCommand() et al, to avoid repeating code.

addScript is there (even though only used once), but now made private to keep the logic for bookkeeping near each other.
This commit is contained in:
Shaya Potter
2024-10-31 18:16:59 +02:00
committed by GitHub
parent 5ace34b9c9
commit 4708736f3b
1016 changed files with 6347 additions and 6542 deletions

View File

@@ -1,5 +1,6 @@
import { BasicCommandParser, CommandParser } from '../client/parser';
import { RESP_TYPES } from '../RESP/decoder';
import { UnwrapReply, ArrayReply, BlobStringReply, BooleanReply, CommandArguments, DoubleReply, NullReply, NumberReply, RedisArgument, TuplesReply, MapReply, TypeMapping } from '../RESP/types';
import { UnwrapReply, ArrayReply, BlobStringReply, BooleanReply, CommandArguments, DoubleReply, NullReply, NumberReply, RedisArgument, TuplesReply, MapReply, TypeMapping, Command } from '../RESP/types';
export function isNullReply(reply: unknown): reply is NullReply {
return reply === null;
@@ -107,6 +108,19 @@ export interface Stringable {
toString(): string;
}
export function transformTuplesToMap<T>(
reply: UnwrapReply<ArrayReply<any>>,
func: (elem: any) => T,
) {
const message = Object.create(null);
for (let i = 0; i < reply.length; i+= 2) {
message[reply[i].toString()] = func(reply[i + 1]);
}
return message;
}
export function createTransformTuplesReplyFunc<T extends Stringable>(preserve?: any, typeMapping?: TypeMapping) {
return (reply: ArrayReply<T>) => {
return transformTuplesReply<T>(reply, preserve, typeMapping);
@@ -255,16 +269,16 @@ export function pushVariadicArgument(
return args;
}
export function pushOptionalVariadicArgument(
args: CommandArguments,
export function parseOptionalVariadicArgument(
parser: CommandParser,
name: RedisArgument,
value?: RedisVariadicArgument
): CommandArguments {
if (value === undefined) return args;
) {
if (value === undefined) return;
args.push(name);
parser.push(name);
return pushVariadicArgument(args, value);
parser.pushVariadicWithLength(value);
}
export enum CommandFlags {
@@ -393,29 +407,27 @@ export interface SlotRange {
end: number;
}
function pushSlotRangeArguments(
args: CommandArguments,
function parseSlotRangeArguments(
parser: CommandParser,
range: SlotRange
): void {
args.push(
parser.push(
range.start.toString(),
range.end.toString()
);
}
export function pushSlotRangesArguments(
args: CommandArguments,
export function parseSlotRangesArguments(
parser: CommandParser,
ranges: SlotRange | Array<SlotRange>
): CommandArguments {
) {
if (Array.isArray(ranges)) {
for (const range of ranges) {
pushSlotRangeArguments(args, range);
parseSlotRangeArguments(parser, range);
}
} else {
pushSlotRangeArguments(args, ranges);
parseSlotRangeArguments(parser, ranges);
}
return args;
}
export type RawRangeReply = [
@@ -444,41 +456,36 @@ export type ZVariadicKeys<T> = T | [T, ...Array<T>];
export type ZKeys = ZVariadicKeys<RedisArgument> | ZVariadicKeys<ZKeyAndWeight>;
export function pushZKeysArguments(
args: CommandArguments,
export function parseZKeysArguments(
parser: CommandParser,
keys: ZKeys
) {
if (Array.isArray(keys)) {
args.push(keys.length.toString());
parser.push(keys.length.toString());
if (keys.length) {
if (isPlainKeys(keys)) {
args = args.concat(keys);
parser.pushKeys(keys);
} else {
const start = args.length;
args[start + keys.length] = 'WEIGHTS';
for (let i = 0; i < keys.length; i++) {
const index = start + i;
args[index] = keys[i].key;
args[index + 1 + keys.length] = transformDoubleArgument(keys[i].weight);
parser.pushKey(keys[i].key)
}
parser.push('WEIGHTS');
for (let i = 0; i < keys.length; i++) {
parser.push(transformDoubleArgument(keys[i].weight));
}
}
}
} else {
args.push('1');
parser.push('1');
if (isPlainKey(keys)) {
args.push(keys);
parser.pushKey(keys);
} else {
args.push(
keys.key,
'WEIGHTS',
transformDoubleArgument(keys.weight)
);
parser.pushKey(keys.key);
parser.push('WEIGHTS', transformDoubleArgument(keys.weight));
}
}
return args;
}
function isPlainKey(key: RedisArgument | ZKeyAndWeight): key is RedisArgument {
@@ -489,6 +496,22 @@ function isPlainKeys(keys: Array<RedisArgument> | Array<ZKeyAndWeight>): keys is
return isPlainKey(keys[0]);
}
export type Tail<T extends unknown[]> = T extends [infer Head, ...infer Tail] ? Tail : never;
/**
* @deprecated
*/
export function parseArgs(command: Command, ...args: Array<any>): CommandArguments {
const parser = new BasicCommandParser();
command.parseCommand!(parser, ...args);
const redisArgs: CommandArguments = parser.redisArgs;
if (parser.preserve) {
redisArgs.preserve = parser.preserve;
}
return redisArgs;
}
export type StreamMessageRawReply = TuplesReply<[
id: BlobStringReply,
message: ArrayReply<BlobStringReply>