You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-07 13:22:56 +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:
@@ -2,7 +2,7 @@ import { RedisArgument } from './types';
|
||||
|
||||
const CRLF = '\r\n';
|
||||
|
||||
export default function encodeCommand(args: Array<RedisArgument>): Array<RedisArgument> {
|
||||
export default function encodeCommand(args: ReadonlyArray<RedisArgument>): ReadonlyArray<RedisArgument> {
|
||||
const toWrite: Array<RedisArgument> = [];
|
||||
|
||||
let strings = '*' + args.length + CRLF;
|
||||
|
@@ -1,3 +1,5 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { Tail } from '../commands/generic-transformers';
|
||||
import { BlobError, SimpleError } from '../errors';
|
||||
import { RedisScriptConfig, SHA1 } from '../lua-script';
|
||||
import { RESP_TYPES } from './decoder';
|
||||
@@ -272,15 +274,16 @@ export type CommandArguments = Array<RedisArgument> & { preserve?: unknown };
|
||||
// };
|
||||
|
||||
export type Command = {
|
||||
FIRST_KEY_INDEX?: number | ((this: void, ...args: Array<any>) => RedisArgument | undefined);
|
||||
CACHEABLE?: boolean;
|
||||
IS_READ_ONLY?: boolean;
|
||||
/**
|
||||
* @internal
|
||||
* TODO: remove once `POLICIES` is implemented
|
||||
*/
|
||||
IS_FORWARD_COMMAND?: boolean;
|
||||
NOT_KEYED_COMMAND?: true;
|
||||
// POLICIES?: CommandPolicies;
|
||||
transformArguments(this: void, ...args: Array<any>): CommandArguments;
|
||||
parseCommand(this: void, parser: CommandParser, ...args: Array<any>): void;
|
||||
TRANSFORM_LEGACY_REPLY?: boolean;
|
||||
transformReply: TransformReply | Record<RespVersions, TransformReply>;
|
||||
unstableResp3?: boolean;
|
||||
@@ -365,7 +368,7 @@ export type CommandSignature<
|
||||
COMMAND extends Command,
|
||||
RESP extends RespVersions,
|
||||
TYPE_MAPPING extends TypeMapping
|
||||
> = (...args: Parameters<COMMAND['transformArguments']>) => Promise<ReplyWithTypeMapping<CommandReply<COMMAND, RESP>, TYPE_MAPPING>>;
|
||||
> = (...args: Tail<Parameters<COMMAND['parseCommand']>>) => Promise<ReplyWithTypeMapping<CommandReply<COMMAND, RESP>, TYPE_MAPPING>>;
|
||||
|
||||
// export type CommandWithPoliciesSignature<
|
||||
// COMMAND extends Command,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { SinglyLinkedList, DoublyLinkedNode, DoublyLinkedList } from './linked-list';
|
||||
import encodeCommand from '../RESP/encoder';
|
||||
import { Decoder, PUSH_TYPE_MAPPING, RESP_TYPES } from '../RESP/decoder';
|
||||
import { CommandArguments, TypeMapping, ReplyUnion, RespVersions } from '../RESP/types';
|
||||
import { TypeMapping, ReplyUnion, RespVersions, RedisArgument } from '../RESP/types';
|
||||
import { ChannelListeners, PubSub, PubSubCommand, PubSubListener, PubSubType, PubSubTypeListeners } from './pub-sub';
|
||||
import { AbortError, ErrorReply } from '../errors';
|
||||
import { MonitorCallback } from '.';
|
||||
@@ -17,7 +17,7 @@ export interface CommandOptions<T = TypeMapping> {
|
||||
}
|
||||
|
||||
export interface CommandToWrite extends CommandWaitingForReply {
|
||||
args: CommandArguments;
|
||||
args: ReadonlyArray<RedisArgument>;
|
||||
chainId: symbol | undefined;
|
||||
abort: {
|
||||
signal: AbortSignal;
|
||||
@@ -117,7 +117,7 @@ export default class RedisCommandsQueue {
|
||||
}
|
||||
|
||||
addCommand<T>(
|
||||
args: CommandArguments,
|
||||
args: ReadonlyArray<RedisArgument>,
|
||||
options?: CommandOptions
|
||||
): Promise<T> {
|
||||
if (this.#maxLength && this.#toWrite.length + this.#waitingForReply.length >= this.#maxLength) {
|
||||
@@ -346,7 +346,7 @@ export default class RedisCommandsQueue {
|
||||
*commandsToWrite() {
|
||||
let toSend = this.#toWrite.shift();
|
||||
while (toSend) {
|
||||
let encoded: CommandArguments;
|
||||
let encoded: ReadonlyArray<RedisArgument>
|
||||
try {
|
||||
encoded = encodeCommand(toSend.args);
|
||||
} catch (err) {
|
||||
|
@@ -9,6 +9,7 @@ import { MATH_FUNCTION, loadMathFunction } from '../commands/FUNCTION_LOAD.spec'
|
||||
import { RESP_TYPES } from '../RESP/decoder';
|
||||
import { BlobStringReply, NumberReply } from '../RESP/types';
|
||||
import { SortedSetMember } from '../commands/generic-transformers';
|
||||
import { CommandParser } from './parser';
|
||||
|
||||
export const SQUARE_SCRIPT = defineScript({
|
||||
SCRIPT:
|
||||
@@ -16,8 +17,8 @@ export const SQUARE_SCRIPT = defineScript({
|
||||
return number * number`,
|
||||
NUMBER_OF_KEYS: 1,
|
||||
FIRST_KEY_INDEX: 0,
|
||||
transformArguments(key: string) {
|
||||
return [key];
|
||||
parseCommand(parser: CommandParser, key: string) {
|
||||
parser.pushKey(key);
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
});
|
||||
@@ -318,8 +319,8 @@ describe('Client', () => {
|
||||
|
||||
const module = {
|
||||
echo: {
|
||||
transformArguments(message: string) {
|
||||
return ['ECHO', message];
|
||||
parseCommand(parser: CommandParser, message: string) {
|
||||
parser.push('ECHO', message);
|
||||
},
|
||||
transformReply: undefined as unknown as () => BlobStringReply
|
||||
}
|
||||
|
@@ -7,14 +7,15 @@ import { ClientClosedError, ClientOfflineError, DisconnectsClientError, WatchErr
|
||||
import { URL } from 'node:url';
|
||||
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 } from '../RESP/types';
|
||||
import { Command, CommandSignature, TypeMapping, CommanderConfig, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, ReplyUnion, RespVersions, RedisArgument, ReplyWithTypeMapping, SimpleStringReply, TransformReply } from '../RESP/types';
|
||||
import RedisClientMultiCommand, { RedisClientMultiCommandType } from './multi-command';
|
||||
import { RedisMultiQueuedCommand } from '../multi-command';
|
||||
import HELLO, { HelloOptions } from '../commands/HELLO';
|
||||
import { ScanOptions, ScanCommonOptions } from '../commands/SCAN';
|
||||
import { RedisLegacyClient, RedisLegacyClientType } from './legacy-mode';
|
||||
import { RedisPoolOptions, RedisClientPool } from './pool';
|
||||
import { RedisVariadicArgument, pushVariadicArguments } from '../commands/generic-transformers';
|
||||
import { RedisVariadicArgument, parseArgs, pushVariadicArguments } from '../commands/generic-transformers';
|
||||
import { BasicCommandParser, CommandParser } from './parser';
|
||||
|
||||
export interface RedisClientOptions<
|
||||
M extends RedisModules = RedisModules,
|
||||
@@ -151,64 +152,50 @@ export default class RedisClient<
|
||||
> extends EventEmitter {
|
||||
static #createCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return async function (this: ProxyClient, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args);
|
||||
const typeMapping = this._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const reply = await this.sendCommand(redisArgs, this._commandOptions);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, redisArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
};
|
||||
return this._self._executeCommand(command, parser, this._commandOptions, transformReply);
|
||||
}
|
||||
}
|
||||
|
||||
static #createModuleCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return async function (this: NamespaceProxyClient, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args);
|
||||
const typeMapping = this._self._commandOptions?.typeMapping
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const reply = await this._self.sendCommand(redisArgs, this._self._commandOptions);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, redisArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
return this._self._executeCommand(command, parser, this._self._commandOptions, transformReply);
|
||||
};
|
||||
}
|
||||
|
||||
static #createFunctionCommand(name: string, fn: RedisFunction, resp: RespVersions) {
|
||||
const prefix = functionArgumentsPrefix(name, fn),
|
||||
transformReply = getTransformReply(fn, resp);
|
||||
const prefix = functionArgumentsPrefix(name, fn);
|
||||
const transformReply = getTransformReply(fn, resp);
|
||||
|
||||
return async function (this: NamespaceProxyClient, ...args: Array<unknown>) {
|
||||
const fnArgs = fn.transformArguments(...args);
|
||||
const typeMapping = this._self._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
parser.push(...prefix);
|
||||
fn.parseCommand(parser, ...args);
|
||||
|
||||
const reply = await this._self.sendCommand(
|
||||
prefix.concat(fnArgs),
|
||||
this._self._commandOptions
|
||||
);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, fnArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
return this._self._executeCommand(fn, parser, this._self._commandOptions, transformReply);
|
||||
};
|
||||
}
|
||||
|
||||
static #createScriptCommand(script: RedisScript, resp: RespVersions) {
|
||||
const prefix = scriptArgumentsPrefix(script),
|
||||
transformReply = getTransformReply(script, resp);
|
||||
return async function (this: ProxyClient, ...args: Array<unknown>) {
|
||||
const scriptArgs = script.transformArguments(...args);
|
||||
const redisArgs = prefix.concat(scriptArgs);
|
||||
const typeMapping = this._commandOptions?.typeMapping;
|
||||
const prefix = scriptArgumentsPrefix(script);
|
||||
const transformReply = getTransformReply(script, resp);
|
||||
|
||||
const reply = await this.executeScript(script, redisArgs, this._commandOptions);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, scriptArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
};
|
||||
return async function (this: ProxyClient, ...args: Array<unknown>) {
|
||||
const parser = new BasicCommandParser();
|
||||
parser.push(...prefix);
|
||||
script.parseCommand(parser, ...args)
|
||||
|
||||
return this._executeScript(script, parser, this._commandOptions, transformReply);
|
||||
}
|
||||
}
|
||||
|
||||
static factory<
|
||||
@@ -376,12 +363,12 @@ export default class RedisClient<
|
||||
}
|
||||
|
||||
commands.push(
|
||||
HELLO.transformArguments(this.#options.RESP, hello)
|
||||
parseArgs(HELLO, this.#options.RESP, hello)
|
||||
);
|
||||
} else {
|
||||
if (this.#options?.username || this.#options?.password) {
|
||||
commands.push(
|
||||
COMMANDS.AUTH.transformArguments({
|
||||
parseArgs(COMMANDS.AUTH, {
|
||||
username: this.#options.username,
|
||||
password: this.#options.password ?? ''
|
||||
})
|
||||
@@ -390,7 +377,7 @@ export default class RedisClient<
|
||||
|
||||
if (this.#options?.name) {
|
||||
commands.push(
|
||||
COMMANDS.CLIENT_SETNAME.transformArguments(this.#options.name)
|
||||
parseArgs(COMMANDS.CLIENT_SETNAME, this.#options.name)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -401,7 +388,7 @@ export default class RedisClient<
|
||||
|
||||
if (this.#options?.readonly) {
|
||||
commands.push(
|
||||
COMMANDS.READONLY.transformArguments()
|
||||
parseArgs(COMMANDS.READONLY)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -585,8 +572,53 @@ export default class RedisClient<
|
||||
return this as unknown as RedisClientType<M, F, S, RESP, TYPE_MAPPING>;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
async _executeCommand(
|
||||
command: Command,
|
||||
parser: CommandParser,
|
||||
commandOptions: CommandOptions<TYPE_MAPPING> | undefined,
|
||||
transformReply: TransformReply | undefined,
|
||||
) {
|
||||
const reply = await this.sendCommand(parser.redisArgs, commandOptions);
|
||||
|
||||
if (transformReply) {
|
||||
return transformReply(reply, parser.preserve, commandOptions?.typeMapping);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
async _executeScript(
|
||||
script: RedisScript,
|
||||
parser: CommandParser,
|
||||
options: CommandOptions | undefined,
|
||||
transformReply: TransformReply | undefined,
|
||||
) {
|
||||
const args = parser.redisArgs as Array<RedisArgument>;
|
||||
|
||||
let reply: ReplyUnion;
|
||||
try {
|
||||
reply = await this.sendCommand(args, options);
|
||||
} catch (err) {
|
||||
if (!(err as Error)?.message?.startsWith?.('NOSCRIPT')) throw err;
|
||||
|
||||
args[0] = 'EVAL';
|
||||
args[1] = script.SCRIPT;
|
||||
reply = await this.sendCommand(args, options);
|
||||
}
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, parser.preserve, options?.typeMapping) :
|
||||
reply;
|
||||
}
|
||||
|
||||
sendCommand<T = ReplyUnion>(
|
||||
args: Array<RedisArgument>,
|
||||
args: ReadonlyArray<RedisArgument>,
|
||||
options?: CommandOptions
|
||||
): Promise<T> {
|
||||
if (!this._self.#socket.isOpen) {
|
||||
@@ -600,22 +632,6 @@ export default class RedisClient<
|
||||
return promise;
|
||||
}
|
||||
|
||||
async executeScript(
|
||||
script: RedisScript,
|
||||
args: Array<RedisArgument>,
|
||||
options?: CommandOptions
|
||||
) {
|
||||
try {
|
||||
return await this.sendCommand(args, options);
|
||||
} catch (err) {
|
||||
if (!(err as Error)?.message?.startsWith?.('NOSCRIPT')) throw err;
|
||||
|
||||
args[0] = 'EVAL';
|
||||
args[1] = script.SCRIPT;
|
||||
return await this.sendCommand(args, options);
|
||||
}
|
||||
}
|
||||
|
||||
async SELECT(db: number): Promise<void> {
|
||||
await this.sendCommand(['SELECT', db.toString()]);
|
||||
this._self.#selectedDB = db;
|
||||
|
@@ -2,6 +2,8 @@ import COMMANDS from '../commands';
|
||||
import RedisMultiCommand, { MULTI_REPLY, 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';
|
||||
import { Tail } from '../commands/generic-transformers';
|
||||
|
||||
type CommandSignature<
|
||||
REPLIES extends Array<unknown>,
|
||||
@@ -11,7 +13,7 @@ type CommandSignature<
|
||||
S extends RedisScripts,
|
||||
RESP extends RespVersions,
|
||||
TYPE_MAPPING extends TypeMapping
|
||||
> = (...args: Parameters<C['transformArguments']>) => RedisClientMultiCommandType<
|
||||
> = (...args: Tail<Parameters<C['parseCommand']>>) => RedisClientMultiCommandType<
|
||||
[...REPLIES, ReplyWithTypeMapping<CommandReply<C, RESP>, TYPE_MAPPING>],
|
||||
M,
|
||||
F,
|
||||
@@ -88,9 +90,16 @@ type ExecuteMulti = (commands: Array<RedisMultiQueuedCommand>, selectedDB?: numb
|
||||
export default class RedisClientMultiCommand<REPLIES = []> {
|
||||
static #createCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return function (this: RedisClientMultiCommand, ...args: Array<unknown>) {
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const redisArgs: CommandArguments = parser.redisArgs;
|
||||
redisArgs.preserve = parser.preserve;
|
||||
|
||||
return this.addCommand(
|
||||
command.transformArguments(...args),
|
||||
redisArgs,
|
||||
transformReply
|
||||
);
|
||||
};
|
||||
@@ -98,21 +107,33 @@ export default class RedisClientMultiCommand<REPLIES = []> {
|
||||
|
||||
static #createModuleCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return function (this: { _self: RedisClientMultiCommand }, ...args: Array<unknown>) {
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const redisArgs: CommandArguments = parser.redisArgs;
|
||||
redisArgs.preserve = parser.preserve;
|
||||
|
||||
return this._self.addCommand(
|
||||
command.transformArguments(...args),
|
||||
redisArgs,
|
||||
transformReply
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
static #createFunctionCommand(name: string, fn: RedisFunction, resp: RespVersions) {
|
||||
const prefix = functionArgumentsPrefix(name, fn),
|
||||
transformReply = getTransformReply(fn, resp);
|
||||
const prefix = functionArgumentsPrefix(name, fn);
|
||||
const transformReply = getTransformReply(fn, resp);
|
||||
|
||||
return function (this: { _self: RedisClientMultiCommand }, ...args: Array<unknown>) {
|
||||
const fnArgs = fn.transformArguments(...args),
|
||||
redisArgs: CommandArguments = prefix.concat(fnArgs);
|
||||
redisArgs.preserve = fnArgs.preserve;
|
||||
const parser = new BasicCommandParser();
|
||||
parser.push(...prefix);
|
||||
fn.parseCommand(parser, ...args);
|
||||
|
||||
const redisArgs: CommandArguments = parser.redisArgs;
|
||||
redisArgs.preserve = parser.preserve;
|
||||
|
||||
return this._self.addCommand(
|
||||
redisArgs,
|
||||
transformReply
|
||||
@@ -122,13 +143,19 @@ export default class RedisClientMultiCommand<REPLIES = []> {
|
||||
|
||||
static #createScriptCommand(script: RedisScript, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(script, resp);
|
||||
|
||||
return function (this: RedisClientMultiCommand, ...args: Array<unknown>) {
|
||||
this.#multi.addScript(
|
||||
const parser = new BasicCommandParser();
|
||||
script.parseCommand(parser, ...args);
|
||||
|
||||
const redisArgs: CommandArguments = parser.redisArgs;
|
||||
redisArgs.preserve = parser.preserve;
|
||||
|
||||
return this.#addScript(
|
||||
script,
|
||||
script.transformArguments(...args),
|
||||
redisArgs,
|
||||
transformReply
|
||||
);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -149,17 +176,16 @@ export default class RedisClientMultiCommand<REPLIES = []> {
|
||||
});
|
||||
}
|
||||
|
||||
readonly #multi = new RedisMultiCommand();
|
||||
readonly #multi: RedisMultiCommand
|
||||
readonly #executeMulti: ExecuteMulti;
|
||||
readonly #executePipeline: ExecuteMulti;
|
||||
readonly #typeMapping?: TypeMapping;
|
||||
|
||||
#selectedDB?: number;
|
||||
|
||||
constructor(executeMulti: ExecuteMulti, executePipeline: ExecuteMulti, typeMapping?: TypeMapping) {
|
||||
this.#multi = new RedisMultiCommand(typeMapping);
|
||||
this.#executeMulti = executeMulti;
|
||||
this.#executePipeline = executePipeline;
|
||||
this.#typeMapping = typeMapping;
|
||||
}
|
||||
|
||||
SELECT(db: number, transformReply?: TransformReply): this {
|
||||
@@ -175,12 +201,21 @@ export default class RedisClientMultiCommand<REPLIES = []> {
|
||||
return this;
|
||||
}
|
||||
|
||||
#addScript(
|
||||
script: RedisScript,
|
||||
args: CommandArguments,
|
||||
transformReply?: TransformReply
|
||||
) {
|
||||
this.#multi.addScript(script, args, transformReply);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async exec<T extends MultiReply = MULTI_REPLY['GENERIC']>(execAsPipeline = false): Promise<MultiReplyType<T, REPLIES>> {
|
||||
if (execAsPipeline) return this.execAsPipeline<T>();
|
||||
|
||||
return this.#multi.transformReplies(
|
||||
await this.#executeMulti(this.#multi.queue, this.#selectedDB),
|
||||
this.#typeMapping
|
||||
await this.#executeMulti(this.#multi.queue, this.#selectedDB)
|
||||
) as MultiReplyType<T, REPLIES>;
|
||||
}
|
||||
|
||||
@@ -194,8 +229,7 @@ export default class RedisClientMultiCommand<REPLIES = []> {
|
||||
if (this.#multi.queue.length === 0) return [] as MultiReplyType<T, REPLIES>;
|
||||
|
||||
return this.#multi.transformReplies(
|
||||
await this.#executePipeline(this.#multi.queue, this.#selectedDB),
|
||||
this.#typeMapping
|
||||
await this.#executePipeline(this.#multi.queue, this.#selectedDB)
|
||||
) as MultiReplyType<T, REPLIES>;
|
||||
}
|
||||
|
||||
|
92
packages/client/lib/client/parser.ts
Normal file
92
packages/client/lib/client/parser.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { RedisArgument } from '../RESP/types';
|
||||
import { RedisVariadicArgument } from '../commands/generic-transformers';
|
||||
|
||||
export interface CommandParser {
|
||||
redisArgs: ReadonlyArray<RedisArgument>;
|
||||
keys: ReadonlyArray<RedisArgument>;
|
||||
firstKey: RedisArgument | undefined;
|
||||
preserve: unknown;
|
||||
|
||||
push: (...arg: Array<RedisArgument>) => unknown;
|
||||
pushVariadic: (vals: RedisVariadicArgument) => unknown;
|
||||
pushVariadicWithLength: (vals: RedisVariadicArgument) => unknown;
|
||||
pushVariadicNumber: (vals: number | Array<number>) => unknown;
|
||||
pushKey: (key: RedisArgument) => unknown; // normal push of keys
|
||||
pushKeys: (keys: RedisVariadicArgument) => unknown; // push multiple keys at a time
|
||||
pushKeysLength: (keys: RedisVariadicArgument) => unknown; // push multiple keys at a time
|
||||
}
|
||||
|
||||
export class BasicCommandParser implements CommandParser {
|
||||
#redisArgs: Array<RedisArgument> = [];
|
||||
#keys: Array<RedisArgument> = [];
|
||||
preserve: unknown;
|
||||
|
||||
get redisArgs() {
|
||||
return this.#redisArgs;
|
||||
}
|
||||
|
||||
get keys() {
|
||||
return this.#keys;
|
||||
}
|
||||
|
||||
get firstKey() {
|
||||
return this.#keys[0];
|
||||
}
|
||||
|
||||
push(...arg: Array<RedisArgument>) {
|
||||
this.#redisArgs.push(...arg);
|
||||
};
|
||||
|
||||
pushVariadic(vals: RedisVariadicArgument) {
|
||||
if (Array.isArray(vals)) {
|
||||
for (const val of vals) {
|
||||
this.push(val);
|
||||
}
|
||||
} else {
|
||||
this.push(vals);
|
||||
}
|
||||
}
|
||||
|
||||
pushVariadicWithLength(vals: RedisVariadicArgument) {
|
||||
if (Array.isArray(vals)) {
|
||||
this.#redisArgs.push(vals.length.toString());
|
||||
} else {
|
||||
this.#redisArgs.push('1');
|
||||
}
|
||||
this.pushVariadic(vals);
|
||||
}
|
||||
|
||||
pushVariadicNumber(vals: number | number[]) {
|
||||
if (Array.isArray(vals)) {
|
||||
for (const val of vals) {
|
||||
this.push(val.toString());
|
||||
}
|
||||
} else {
|
||||
this.push(vals.toString());
|
||||
}
|
||||
}
|
||||
|
||||
pushKey(key: RedisArgument) {
|
||||
this.#keys.push(key);
|
||||
this.#redisArgs.push(key);
|
||||
}
|
||||
|
||||
pushKeysLength(keys: RedisVariadicArgument) {
|
||||
if (Array.isArray(keys)) {
|
||||
this.#redisArgs.push(keys.length.toString());
|
||||
} else {
|
||||
this.#redisArgs.push('1');
|
||||
}
|
||||
this.pushKeys(keys);
|
||||
}
|
||||
|
||||
pushKeys(keys: RedisVariadicArgument) {
|
||||
if (Array.isArray(keys)) {
|
||||
this.#keys.push(...keys);
|
||||
this.#redisArgs.push(...keys);
|
||||
} else {
|
||||
this.#keys.push(keys);
|
||||
this.#redisArgs.push(keys);
|
||||
}
|
||||
}
|
||||
}
|
@@ -7,6 +7,7 @@ import { TimeoutError } from '../errors';
|
||||
import { attachConfig, functionArgumentsPrefix, getTransformReply, scriptArgumentsPrefix } from '../commander';
|
||||
import { CommandOptions } from './commands-queue';
|
||||
import RedisClientMultiCommand, { RedisClientMultiCommandType } from './multi-command';
|
||||
import { BasicCommandParser } from './parser';
|
||||
|
||||
export interface RedisPoolOptions {
|
||||
/**
|
||||
@@ -64,63 +65,48 @@ export class RedisClientPool<
|
||||
> extends EventEmitter {
|
||||
static #createCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return async function (this: ProxyPool, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args);
|
||||
const typeMapping = this._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const reply = await this.sendCommand(redisArgs, this._commandOptions);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, redisArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
return this.execute(client => client._executeCommand(command, parser, this._commandOptions, transformReply))
|
||||
};
|
||||
}
|
||||
|
||||
static #createModuleCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return async function (this: NamespaceProxyPool, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args);
|
||||
const typeMapping = this._self._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const reply = await this._self.sendCommand(redisArgs, this._self._commandOptions);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, redisArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
return this._self.execute(client => client._executeCommand(command, parser, this._self._commandOptions, transformReply))
|
||||
};
|
||||
}
|
||||
|
||||
static #createFunctionCommand(name: string, fn: RedisFunction, resp: RespVersions) {
|
||||
const prefix = functionArgumentsPrefix(name, fn),
|
||||
transformReply = getTransformReply(fn, resp);
|
||||
const prefix = functionArgumentsPrefix(name, fn);
|
||||
const transformReply = getTransformReply(fn, resp);
|
||||
|
||||
return async function (this: NamespaceProxyPool, ...args: Array<unknown>) {
|
||||
const fnArgs = fn.transformArguments(...args);
|
||||
const typeMapping = this._self._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
parser.push(...prefix);
|
||||
fn.parseCommand(parser, ...args);
|
||||
|
||||
const reply = await this._self.sendCommand(
|
||||
prefix.concat(fnArgs),
|
||||
this._self._commandOptions
|
||||
);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, fnArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
};
|
||||
return this._self.execute(client => client._executeCommand(fn, parser, this._self._commandOptions, transformReply)) };
|
||||
}
|
||||
|
||||
static #createScriptCommand(script: RedisScript, resp: RespVersions) {
|
||||
const prefix = scriptArgumentsPrefix(script),
|
||||
transformReply = getTransformReply(script, resp);
|
||||
return async function (this: ProxyPool, ...args: Array<unknown>) {
|
||||
const scriptArgs = script.transformArguments(...args);
|
||||
const redisArgs = prefix.concat(scriptArgs);
|
||||
const typeMapping = this._commandOptions?.typeMapping;
|
||||
const prefix = scriptArgumentsPrefix(script);
|
||||
const transformReply = getTransformReply(script, resp);
|
||||
|
||||
const reply = await this.executeScript(script, redisArgs, this._commandOptions);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, scriptArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
return async function (this: ProxyPool, ...args: Array<unknown>) {
|
||||
const parser = new BasicCommandParser();
|
||||
parser.pushVariadic(prefix);
|
||||
script.parseCommand(parser, ...args);
|
||||
|
||||
return this.execute(client => client._executeScript(script, parser, this._commandOptions, transformReply))
|
||||
};
|
||||
}
|
||||
|
||||
@@ -426,14 +412,6 @@ export class RedisClientPool<
|
||||
return this.execute(client => client.sendCommand(args, options));
|
||||
}
|
||||
|
||||
executeScript(
|
||||
script: RedisScript,
|
||||
args: Array<RedisArgument>,
|
||||
options?: CommandOptions
|
||||
) {
|
||||
return this.execute(client => client.executeScript(script, args, options));
|
||||
}
|
||||
|
||||
MULTI() {
|
||||
type Multi = new (...args: ConstructorParameters<typeof RedisClientMultiCommand>) => RedisClientMultiCommandType<[], M, F, S, RESP, TYPE_MAPPING>;
|
||||
return new ((this as any).Multi as Multi)(
|
||||
|
@@ -271,7 +271,7 @@ export default class RedisSocket extends EventEmitter {
|
||||
});
|
||||
}
|
||||
|
||||
write(iterable: Iterable<Array<RedisArgument>>) {
|
||||
write(iterable: Iterable<ReadonlyArray<RedisArgument>>) {
|
||||
if (!this.#socket) return;
|
||||
|
||||
this.#socket.cork();
|
||||
|
@@ -9,6 +9,9 @@ import RedisClusterMultiCommand, { RedisClusterMultiCommandType } from './multi-
|
||||
import { PubSubListener } from '../client/pub-sub';
|
||||
import { ErrorReply } from '../errors';
|
||||
import { RedisTcpSocketOptions } from '../client/socket';
|
||||
import ASKING from '../commands/ASKING';
|
||||
import { BasicCommandParser } from '../client/parser';
|
||||
import { parseArgs } from '../commands/generic-transformers';
|
||||
|
||||
interface ClusterCommander<
|
||||
M extends RedisModules,
|
||||
@@ -69,7 +72,7 @@ export interface RedisClusterOptions<
|
||||
type ClusterCommand<
|
||||
NAME extends PropertyKey,
|
||||
COMMAND extends Command
|
||||
> = COMMAND['FIRST_KEY_INDEX'] extends undefined ? (
|
||||
> = COMMAND['NOT_KEYED_COMMAND'] extends true ? (
|
||||
COMMAND['IS_FORWARD_COMMAND'] extends true ? NAME : never
|
||||
) : NAME;
|
||||
|
||||
@@ -143,131 +146,70 @@ export default class RedisCluster<
|
||||
TYPE_MAPPING extends TypeMapping,
|
||||
// POLICIES extends CommandPolicies
|
||||
> extends EventEmitter {
|
||||
static extractFirstKey<C extends Command>(
|
||||
command: C,
|
||||
args: Parameters<C['transformArguments']>,
|
||||
redisArgs: Array<RedisArgument>
|
||||
) {
|
||||
let key: RedisArgument | undefined;
|
||||
switch (typeof command.FIRST_KEY_INDEX) {
|
||||
case 'number':
|
||||
key = redisArgs[command.FIRST_KEY_INDEX];
|
||||
break;
|
||||
|
||||
case 'function':
|
||||
key = command.FIRST_KEY_INDEX(...args);
|
||||
break;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static #createCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
return async function (this: ProxyCluster, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args);
|
||||
const typeMapping = this._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const firstKey = RedisCluster.extractFirstKey(
|
||||
command,
|
||||
args,
|
||||
redisArgs
|
||||
);
|
||||
|
||||
const reply = await this.sendCommand(
|
||||
firstKey,
|
||||
return this._self.#execute(
|
||||
parser.firstKey,
|
||||
command.IS_READ_ONLY,
|
||||
redisArgs,
|
||||
this._commandOptions,
|
||||
// command.POLICIES
|
||||
(client, opts) => client._executeCommand(command, parser, opts, transformReply)
|
||||
);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, redisArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
};
|
||||
}
|
||||
|
||||
static #createModuleCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return async function (this: NamespaceProxyCluster, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args);
|
||||
const typeMapping = this._self._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const firstKey = RedisCluster.extractFirstKey(
|
||||
command,
|
||||
args,
|
||||
redisArgs
|
||||
);
|
||||
|
||||
const reply = await this._self.sendCommand(
|
||||
firstKey,
|
||||
return this._self.#execute(
|
||||
parser.firstKey,
|
||||
command.IS_READ_ONLY,
|
||||
redisArgs,
|
||||
this._self._commandOptions,
|
||||
// command.POLICIES
|
||||
(client, opts) => client._executeCommand(command, parser, opts, transformReply)
|
||||
);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, redisArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
};
|
||||
}
|
||||
|
||||
static #createFunctionCommand(name: string, fn: RedisFunction, resp: RespVersions) {
|
||||
const prefix = functionArgumentsPrefix(name, fn),
|
||||
transformReply = getTransformReply(fn, resp);
|
||||
const prefix = functionArgumentsPrefix(name, fn);
|
||||
const transformReply = getTransformReply(fn, resp);
|
||||
|
||||
return async function (this: NamespaceProxyCluster, ...args: Array<unknown>) {
|
||||
const fnArgs = fn.transformArguments(...args);
|
||||
const redisArgs = prefix.concat(fnArgs);
|
||||
const typeMapping = this._self._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
parser.push(...prefix);
|
||||
fn.parseCommand(parser, ...args);
|
||||
|
||||
const firstKey = RedisCluster.extractFirstKey(
|
||||
fn,
|
||||
args,
|
||||
fnArgs
|
||||
);
|
||||
|
||||
const reply = await this._self.sendCommand(
|
||||
firstKey,
|
||||
return this._self.#execute(
|
||||
parser.firstKey,
|
||||
fn.IS_READ_ONLY,
|
||||
redisArgs,
|
||||
this._self._commandOptions,
|
||||
// fn.POLICIES
|
||||
(client, opts) => client._executeCommand(fn, parser, opts, transformReply)
|
||||
);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, fnArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
};
|
||||
}
|
||||
|
||||
static #createScriptCommand(script: RedisScript, resp: RespVersions) {
|
||||
const prefix = scriptArgumentsPrefix(script),
|
||||
transformReply = getTransformReply(script, resp);
|
||||
const prefix = scriptArgumentsPrefix(script);
|
||||
const transformReply = getTransformReply(script, resp);
|
||||
|
||||
return async function (this: ProxyCluster, ...args: Array<unknown>) {
|
||||
const scriptArgs = script.transformArguments(...args);
|
||||
const redisArgs = prefix.concat(scriptArgs);
|
||||
const typeMapping = this._commandOptions?.typeMapping;
|
||||
const parser = new BasicCommandParser();
|
||||
parser.push(...prefix);
|
||||
script.parseCommand(parser, ...args);
|
||||
|
||||
const firstKey = RedisCluster.extractFirstKey(
|
||||
script,
|
||||
args,
|
||||
scriptArgs
|
||||
);
|
||||
|
||||
const reply = await this.executeScript(
|
||||
script,
|
||||
firstKey,
|
||||
return this._self.#execute(
|
||||
parser.firstKey,
|
||||
script.IS_READ_ONLY,
|
||||
redisArgs,
|
||||
this._commandOptions,
|
||||
// script.POLICIES
|
||||
(client, opts) => client._executeScript(script, parser, opts, transformReply)
|
||||
);
|
||||
|
||||
return transformReply ?
|
||||
transformReply(reply, scriptArgs.preserve, typeMapping) :
|
||||
reply;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -443,15 +385,20 @@ export default class RedisCluster<
|
||||
async #execute<T>(
|
||||
firstKey: RedisArgument | undefined,
|
||||
isReadonly: boolean | undefined,
|
||||
fn: (client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>) => Promise<T>
|
||||
options: ClusterCommandOptions | undefined,
|
||||
fn: (client: RedisClientType<M, F, S, RESP, TYPE_MAPPING>, opts?: ClusterCommandOptions) => Promise<T>
|
||||
): Promise<T> {
|
||||
const maxCommandRedirections = this.#options.maxCommandRedirections ?? 16;
|
||||
let client = await this.#slots.getClient(firstKey, isReadonly),
|
||||
i = 0;
|
||||
let client = await this.#slots.getClient(firstKey, isReadonly);
|
||||
let i = 0;
|
||||
let myOpts = options;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
return await fn(client);
|
||||
return await fn(client, myOpts);
|
||||
} catch (err) {
|
||||
// reset to passed in options, if changed by an ask request
|
||||
myOpts = options;
|
||||
// TODO: error class
|
||||
if (++i > maxCommandRedirections || !(err instanceof Error)) {
|
||||
throw err;
|
||||
@@ -469,8 +416,14 @@ export default class RedisCluster<
|
||||
throw new Error(`Cannot find node ${address}`);
|
||||
}
|
||||
|
||||
await redirectTo.asking();
|
||||
client = redirectTo;
|
||||
|
||||
const chainId = Symbol('Asking Chain');
|
||||
myOpts = options ? {...options} : {};
|
||||
myOpts.chainId = chainId;
|
||||
|
||||
client.sendCommand(parseArgs(ASKING), {chainId: chainId}).catch(err => { console.log(`Asking Failed: ${err}`) } );
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -495,21 +448,8 @@ export default class RedisCluster<
|
||||
return this._self.#execute(
|
||||
firstKey,
|
||||
isReadonly,
|
||||
client => client.sendCommand(args, options)
|
||||
);
|
||||
}
|
||||
|
||||
executeScript(
|
||||
script: RedisScript,
|
||||
firstKey: RedisArgument | undefined,
|
||||
isReadonly: boolean | undefined,
|
||||
args: Array<RedisArgument>,
|
||||
options?: CommandOptions
|
||||
) {
|
||||
return this._self.#execute(
|
||||
firstKey,
|
||||
isReadonly,
|
||||
client => client.executeScript(script, args, options)
|
||||
options,
|
||||
(client, opts) => client.sendCommand(args, opts)
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -2,7 +2,8 @@ import COMMANDS from '../commands';
|
||||
import RedisMultiCommand, { MULTI_REPLY, MultiReply, MultiReplyType, RedisMultiQueuedCommand } from '../multi-command';
|
||||
import { ReplyWithTypeMapping, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, TypeMapping, RedisArgument } from '../RESP/types';
|
||||
import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander';
|
||||
import RedisCluster from '.';
|
||||
import { BasicCommandParser } from '../client/parser';
|
||||
import { Tail } from '../commands/generic-transformers';
|
||||
|
||||
type CommandSignature<
|
||||
REPLIES extends Array<unknown>,
|
||||
@@ -12,7 +13,7 @@ type CommandSignature<
|
||||
S extends RedisScripts,
|
||||
RESP extends RespVersions,
|
||||
TYPE_MAPPING extends TypeMapping
|
||||
> = (...args: Parameters<C['transformArguments']>) => RedisClusterMultiCommandType<
|
||||
> = (...args: Tail<Parameters<C['parseCommand']>>) => RedisClusterMultiCommandType<
|
||||
[...REPLIES, ReplyWithTypeMapping<CommandReply<C, RESP>, TYPE_MAPPING>],
|
||||
M,
|
||||
F,
|
||||
@@ -93,13 +94,15 @@ export type ClusterMultiExecute = (
|
||||
export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
static #createCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return function (this: RedisClusterMultiCommand, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args);
|
||||
const firstKey = RedisCluster.extractFirstKey(
|
||||
command,
|
||||
args,
|
||||
redisArgs
|
||||
);
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const redisArgs: CommandArguments = parser.redisArgs;
|
||||
redisArgs.preserve = parser.preserve;
|
||||
const firstKey = parser.firstKey;
|
||||
|
||||
return this.addCommand(
|
||||
firstKey,
|
||||
command.IS_READ_ONLY,
|
||||
@@ -111,13 +114,15 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
|
||||
static #createModuleCommand(command: Command, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(command, resp);
|
||||
|
||||
return function (this: { _self: RedisClusterMultiCommand }, ...args: Array<unknown>) {
|
||||
const redisArgs = command.transformArguments(...args),
|
||||
firstKey = RedisCluster.extractFirstKey(
|
||||
command,
|
||||
args,
|
||||
redisArgs
|
||||
);
|
||||
const parser = new BasicCommandParser();
|
||||
command.parseCommand(parser, ...args);
|
||||
|
||||
const redisArgs: CommandArguments = parser.redisArgs;
|
||||
redisArgs.preserve = parser.preserve;
|
||||
const firstKey = parser.firstKey;
|
||||
|
||||
return this._self.addCommand(
|
||||
firstKey,
|
||||
command.IS_READ_ONLY,
|
||||
@@ -128,17 +133,18 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
}
|
||||
|
||||
static #createFunctionCommand(name: string, fn: RedisFunction, resp: RespVersions) {
|
||||
const prefix = functionArgumentsPrefix(name, fn),
|
||||
transformReply = getTransformReply(fn, resp);
|
||||
const prefix = functionArgumentsPrefix(name, fn);
|
||||
const transformReply = getTransformReply(fn, resp);
|
||||
|
||||
return function (this: { _self: RedisClusterMultiCommand }, ...args: Array<unknown>) {
|
||||
const fnArgs = fn.transformArguments(...args);
|
||||
const redisArgs: CommandArguments = prefix.concat(fnArgs);
|
||||
const firstKey = RedisCluster.extractFirstKey(
|
||||
fn,
|
||||
args,
|
||||
fnArgs
|
||||
);
|
||||
redisArgs.preserve = fnArgs.preserve;
|
||||
const parser = new BasicCommandParser();
|
||||
parser.push(...prefix);
|
||||
fn.parseCommand(parser, ...args);
|
||||
|
||||
const redisArgs: CommandArguments = parser.redisArgs;
|
||||
redisArgs.preserve = parser.preserve;
|
||||
const firstKey = parser.firstKey;
|
||||
|
||||
return this._self.addCommand(
|
||||
firstKey,
|
||||
fn.IS_READ_ONLY,
|
||||
@@ -150,22 +156,22 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
|
||||
static #createScriptCommand(script: RedisScript, resp: RespVersions) {
|
||||
const transformReply = getTransformReply(script, resp);
|
||||
|
||||
return function (this: RedisClusterMultiCommand, ...args: Array<unknown>) {
|
||||
const scriptArgs = script.transformArguments(...args);
|
||||
this.#setState(
|
||||
RedisCluster.extractFirstKey(
|
||||
script,
|
||||
args,
|
||||
scriptArgs
|
||||
),
|
||||
script.IS_READ_ONLY
|
||||
);
|
||||
this.#multi.addScript(
|
||||
const parser = new BasicCommandParser();
|
||||
script.parseCommand(parser, ...args);
|
||||
|
||||
const scriptArgs: CommandArguments = parser.redisArgs;
|
||||
scriptArgs.preserve = parser.preserve;
|
||||
const firstKey = parser.firstKey;
|
||||
|
||||
return this.#addScript(
|
||||
firstKey,
|
||||
script.IS_READ_ONLY,
|
||||
script,
|
||||
scriptArgs,
|
||||
transformReply
|
||||
);
|
||||
return this;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -186,12 +192,12 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
});
|
||||
}
|
||||
|
||||
readonly #multi = new RedisMultiCommand();
|
||||
readonly #multi: RedisMultiCommand
|
||||
|
||||
readonly #executeMulti: ClusterMultiExecute;
|
||||
readonly #executePipeline: ClusterMultiExecute;
|
||||
#firstKey: RedisArgument | undefined;
|
||||
#isReadonly: boolean | undefined = true;
|
||||
readonly #typeMapping?: TypeMapping;
|
||||
|
||||
constructor(
|
||||
executeMulti: ClusterMultiExecute,
|
||||
@@ -199,10 +205,10 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
routing: RedisArgument | undefined,
|
||||
typeMapping?: TypeMapping
|
||||
) {
|
||||
this.#multi = new RedisMultiCommand(typeMapping);
|
||||
this.#executeMulti = executeMulti;
|
||||
this.#executePipeline = executePipeline;
|
||||
this.#firstKey = routing;
|
||||
this.#typeMapping = typeMapping;
|
||||
}
|
||||
|
||||
#setState(
|
||||
@@ -224,6 +230,19 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
return this;
|
||||
}
|
||||
|
||||
#addScript(
|
||||
firstKey: RedisArgument | undefined,
|
||||
isReadonly: boolean | undefined,
|
||||
script: RedisScript,
|
||||
args: CommandArguments,
|
||||
transformReply?: TransformReply
|
||||
) {
|
||||
this.#setState(firstKey, isReadonly);
|
||||
this.#multi.addScript(script, args, transformReply);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async exec<T extends MultiReply = MULTI_REPLY['GENERIC']>(execAsPipeline = false) {
|
||||
if (execAsPipeline) return this.execAsPipeline<T>();
|
||||
|
||||
@@ -232,8 +251,7 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
this.#firstKey,
|
||||
this.#isReadonly,
|
||||
this.#multi.queue
|
||||
),
|
||||
this.#typeMapping
|
||||
)
|
||||
) as MultiReplyType<T, REPLIES>;
|
||||
}
|
||||
|
||||
@@ -251,8 +269,7 @@ export default class RedisClusterMultiCommand<REPLIES = []> {
|
||||
this.#firstKey,
|
||||
this.#isReadonly,
|
||||
this.#multi.queue
|
||||
),
|
||||
this.#typeMapping
|
||||
)
|
||||
) as MultiReplyType<T, REPLIES>;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Command, CommanderConfig, RedisCommands, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, RespVersions } from './RESP/types';
|
||||
import { Command, CommanderConfig, RedisArgument, RedisCommands, RedisFunction, RedisFunctions, RedisModules, RedisScript, RedisScripts, RespVersions, TransformReply } from './RESP/types';
|
||||
|
||||
interface AttachConfigOptions<
|
||||
M extends RedisModules,
|
||||
@@ -87,7 +87,7 @@ function attachNamespace(prototype: any, name: PropertyKey, fns: any) {
|
||||
});
|
||||
}
|
||||
|
||||
export function getTransformReply(command: Command, resp: RespVersions) {
|
||||
export function getTransformReply(command: Command, resp: RespVersions): TransformReply | undefined {
|
||||
switch (typeof command.transformReply) {
|
||||
case 'function':
|
||||
return command.transformReply;
|
||||
@@ -98,7 +98,7 @@ export function getTransformReply(command: Command, resp: RespVersions) {
|
||||
}
|
||||
|
||||
export function functionArgumentsPrefix(name: string, fn: RedisFunction) {
|
||||
const prefix: Array<string | Buffer> = [
|
||||
const prefix: Array<RedisArgument> = [
|
||||
fn.IS_READ_ONLY ? 'FCALL_RO' : 'FCALL',
|
||||
name
|
||||
];
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
import ACL_CAT from './ACL_CAT';
|
||||
|
||||
describe('ACL CAT', () => {
|
||||
@@ -8,14 +9,14 @@ describe('ACL CAT', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
ACL_CAT.transformArguments(),
|
||||
parseArgs(ACL_CAT),
|
||||
['ACL', 'CAT']
|
||||
);
|
||||
});
|
||||
|
||||
it('with categoryName', () => {
|
||||
assert.deepEqual(
|
||||
ACL_CAT.transformArguments('dangerous'),
|
||||
parseArgs(ACL_CAT, 'dangerous'),
|
||||
['ACL', 'CAT', 'dangerous']
|
||||
);
|
||||
});
|
||||
|
@@ -1,16 +1,14 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(categoryName?: RedisArgument) {
|
||||
const args: Array<RedisArgument> = ['ACL', 'CAT'];
|
||||
|
||||
parseCommand(parser: CommandParser, categoryName?: RedisArgument) {
|
||||
parser.push('ACL', 'CAT');
|
||||
if (categoryName) {
|
||||
args.push(categoryName);
|
||||
parser.push(categoryName);
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import ACL_DELUSER from './ACL_DELUSER';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL DELUSER', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
@@ -8,14 +9,14 @@ describe('ACL DELUSER', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
ACL_DELUSER.transformArguments('username'),
|
||||
parseArgs(ACL_DELUSER, 'username'),
|
||||
['ACL', 'DELUSER', 'username']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
ACL_DELUSER.transformArguments(['1', '2']),
|
||||
parseArgs(ACL_DELUSER, ['1', '2']),
|
||||
['ACL', 'DELUSER', '1', '2']
|
||||
);
|
||||
});
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { NumberReply, Command } from '../RESP/types';
|
||||
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
|
||||
import { RedisVariadicArgument } from './generic-transformers';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(username: RedisVariadicArgument) {
|
||||
return pushVariadicArguments(['ACL', 'DELUSER'], username);
|
||||
parseCommand(parser: CommandParser, username: RedisVariadicArgument) {
|
||||
parser.push('ACL', 'DELUSER');
|
||||
parser.pushVariadic(username);
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import ACL_DRYRUN from './ACL_DRYRUN';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL DRYRUN', () => {
|
||||
testUtils.isVersionGreaterThanHook([7]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_DRYRUN.transformArguments('default', ['GET', 'key']),
|
||||
parseArgs(ACL_DRYRUN, 'default', ['GET', 'key']),
|
||||
['ACL', 'DRYRUN', 'default', 'GET', 'key']
|
||||
);
|
||||
});
|
||||
|
@@ -1,15 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, SimpleStringReply, BlobStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(username: RedisArgument, command: Array<RedisArgument>) {
|
||||
return [
|
||||
'ACL',
|
||||
'DRYRUN',
|
||||
username,
|
||||
...command
|
||||
];
|
||||
parseCommand(parser: CommandParser, username: RedisArgument, command: Array<RedisArgument>) {
|
||||
parser.push('ACL', 'DRYRUN', username, ...command);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'> | BlobStringReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import ACL_GENPASS from './ACL_GENPASS';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL GENPASS', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
@@ -8,14 +9,14 @@ describe('ACL GENPASS', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
ACL_GENPASS.transformArguments(),
|
||||
parseArgs(ACL_GENPASS),
|
||||
['ACL', 'GENPASS']
|
||||
);
|
||||
});
|
||||
|
||||
it('with bits', () => {
|
||||
assert.deepEqual(
|
||||
ACL_GENPASS.transformArguments(128),
|
||||
parseArgs(ACL_GENPASS, 128),
|
||||
['ACL', 'GENPASS', '128']
|
||||
);
|
||||
});
|
||||
|
@@ -1,16 +1,14 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { BlobStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(bits?: number) {
|
||||
const args = ['ACL', 'GENPASS'];
|
||||
|
||||
parseCommand(parser: CommandParser, bits?: number) {
|
||||
parser.push('ACL', 'GENPASS');
|
||||
if (bits) {
|
||||
args.push(bits.toString());
|
||||
parser.push(bits.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => BlobStringReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import ACL_GETUSER from './ACL_GETUSER';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL GETUSER', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_GETUSER.transformArguments('username'),
|
||||
parseArgs(ACL_GETUSER, 'username'),
|
||||
['ACL', 'GETUSER', 'username']
|
||||
);
|
||||
});
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, TuplesToMapReply, BlobStringReply, ArrayReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
|
||||
|
||||
type AclUser = TuplesToMapReply<[
|
||||
@@ -17,10 +18,10 @@ type AclUser = TuplesToMapReply<[
|
||||
]>;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(username: RedisArgument) {
|
||||
return ['ACL', 'GETUSER', username];
|
||||
parseCommand(parser: CommandParser, username: RedisArgument) {
|
||||
parser.push('ACL', 'GETUSER', username);
|
||||
},
|
||||
transformReply: {
|
||||
2: (reply: UnwrapReply<Resp2Reply<AclUser>>) => ({
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import ACL_LIST from './ACL_LIST';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL LIST', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_LIST.transformArguments(),
|
||||
parseArgs(ACL_LIST),
|
||||
['ACL', 'LIST']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['ACL', 'LIST'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('ACL', 'LIST');
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils from '../test-utils';
|
||||
import ACL_LOAD from './ACL_LOAD';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL LOAD', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_LOAD.transformArguments(),
|
||||
parseArgs(ACL_LOAD),
|
||||
['ACL', 'LOAD']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['ACL', 'LOAD'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('ACL', 'LOAD');
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import ACL_LOG from './ACL_LOG';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL LOG', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
@@ -8,14 +9,14 @@ describe('ACL LOG', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
ACL_LOG.transformArguments(),
|
||||
parseArgs(ACL_LOG),
|
||||
['ACL', 'LOG']
|
||||
);
|
||||
});
|
||||
|
||||
it('with count', () => {
|
||||
assert.deepEqual(
|
||||
ACL_LOG.transformArguments(10),
|
||||
parseArgs(ACL_LOG, 10),
|
||||
['ACL', 'LOG', '10']
|
||||
);
|
||||
});
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, DoubleReply, UnwrapReply, Resp2Reply, Command, TypeMapping } from '../RESP/types';
|
||||
import { transformDoubleReply } from './generic-transformers';
|
||||
|
||||
@@ -18,16 +19,13 @@ export type AclLogReply = ArrayReply<TuplesToMapReply<[
|
||||
]>>;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(count?: number) {
|
||||
const args = ['ACL', 'LOG'];
|
||||
|
||||
if (count !== undefined) {
|
||||
args.push(count.toString());
|
||||
parseCommand(parser: CommandParser, count?: number) {
|
||||
parser.push('ACL', 'LOG');
|
||||
if (count != undefined) {
|
||||
parser.push(count.toString());
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: {
|
||||
2: (reply: UnwrapReply<Resp2Reply<AclLogReply>>, preserve?: any, typeMapping?: TypeMapping) => {
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import ACL_LOG_RESET from './ACL_LOG_RESET';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL LOG RESET', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_LOG_RESET.transformArguments(),
|
||||
parseArgs(ACL_LOG_RESET),
|
||||
['ACL', 'LOG', 'RESET']
|
||||
);
|
||||
});
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
import ACL_LOG from './ACL_LOG';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: ACL_LOG.IS_READ_ONLY,
|
||||
transformArguments() {
|
||||
return ['ACL', 'LOG', 'RESET'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('ACL', 'LOG', 'RESET');
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils from '../test-utils';
|
||||
import ACL_SAVE from './ACL_SAVE';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL SAVE', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_SAVE.transformArguments(),
|
||||
parseArgs(ACL_SAVE),
|
||||
['ACL', 'SAVE']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['ACL', 'SAVE'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('ACL', 'SAVE');
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils from '../test-utils';
|
||||
import ACL_SETUSER from './ACL_SETUSER';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL SETUSER', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
@@ -8,14 +9,14 @@ describe('ACL SETUSER', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
ACL_SETUSER.transformArguments('username', 'allkeys'),
|
||||
parseArgs(ACL_SETUSER, 'username', 'allkeys'),
|
||||
['ACL', 'SETUSER', 'username', 'allkeys']
|
||||
);
|
||||
});
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
ACL_SETUSER.transformArguments('username', ['allkeys', 'allchannels']),
|
||||
parseArgs(ACL_SETUSER, 'username', ['allkeys', 'allchannels']),
|
||||
['ACL', 'SETUSER', 'username', 'allkeys', 'allchannels']
|
||||
);
|
||||
});
|
||||
|
@@ -1,11 +1,13 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
|
||||
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
|
||||
import { RedisVariadicArgument } from './generic-transformers';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(username: RedisArgument, rule: RedisVariadicArgument) {
|
||||
return pushVariadicArguments(['ACL', 'SETUSER', username], rule);
|
||||
parseCommand(parser: CommandParser, username: RedisArgument, rule: RedisVariadicArgument) {
|
||||
parser.push('ACL', 'SETUSER', username);
|
||||
parser.pushVariadic(rule);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils from '../test-utils';
|
||||
import ACL_USERS from './ACL_USERS';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL USERS', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_USERS.transformArguments(),
|
||||
parseArgs(ACL_USERS),
|
||||
['ACL', 'USERS']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { ArrayReply, BlobStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['ACL', 'USERS'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('ACL', 'USERS');
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<BlobStringReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils from '../test-utils';
|
||||
import ACL_WHOAMI from './ACL_WHOAMI';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ACL WHOAMI', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ACL_WHOAMI.transformArguments(),
|
||||
parseArgs(ACL_WHOAMI),
|
||||
['ACL', 'WHOAMI']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { BlobStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['ACL', 'WHOAMI'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('ACL', 'WHOAMI');
|
||||
},
|
||||
transformReply: undefined as unknown as () => BlobStringReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import APPEND from './APPEND';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('APPEND', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
APPEND.transformArguments('key', 'value'),
|
||||
parseArgs(APPEND, 'key', 'value'),
|
||||
['APPEND', 'key', 'value']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, NumberReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(key: RedisArgument, value: RedisArgument) {
|
||||
return ['APPEND', key, value];
|
||||
parseCommand(parser: CommandParser, key: RedisArgument, value: RedisArgument) {
|
||||
parser.push('APPEND', key, value);
|
||||
},
|
||||
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import ASKING from './ASKING';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('ASKING', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
ASKING.transformArguments(),
|
||||
parseArgs(ASKING),
|
||||
['ASKING']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,13 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export const ASKING_CMD = 'ASKING';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['ASKING'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push(ASKING_CMD);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import AUTH from './AUTH';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('AUTH', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('password only', () => {
|
||||
assert.deepEqual(
|
||||
AUTH.transformArguments({
|
||||
parseArgs(AUTH, {
|
||||
password: 'password'
|
||||
}),
|
||||
['AUTH', 'password']
|
||||
@@ -14,7 +15,7 @@ describe('AUTH', () => {
|
||||
|
||||
it('username & password', () => {
|
||||
assert.deepEqual(
|
||||
AUTH.transformArguments({
|
||||
parseArgs(AUTH, {
|
||||
username: 'username',
|
||||
password: 'password'
|
||||
}),
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export interface AuthOptions {
|
||||
@@ -6,18 +7,14 @@ export interface AuthOptions {
|
||||
}
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments({ username, password }: AuthOptions) {
|
||||
const args: Array<RedisArgument> = ['AUTH'];
|
||||
|
||||
parseCommand(parser: CommandParser, { username, password }: AuthOptions) {
|
||||
parser.push('AUTH');
|
||||
if (username !== undefined) {
|
||||
args.push(username);
|
||||
parser.push(username);
|
||||
}
|
||||
|
||||
args.push(password);
|
||||
|
||||
return args;
|
||||
parser.push(password);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import BGREWRITEAOF from './BGREWRITEAOF';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BGREWRITEAOF', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
BGREWRITEAOF.transformArguments(),
|
||||
parseArgs(BGREWRITEAOF),
|
||||
['BGREWRITEAOF']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['BGREWRITEAOF'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('BGREWRITEAOF');
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import BGSAVE from './BGSAVE';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BGSAVE', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
BGSAVE.transformArguments(),
|
||||
parseArgs(BGSAVE),
|
||||
['BGSAVE']
|
||||
);
|
||||
});
|
||||
|
||||
it('with SCHEDULE', () => {
|
||||
assert.deepEqual(
|
||||
BGSAVE.transformArguments({
|
||||
parseArgs(BGSAVE, {
|
||||
SCHEDULE: true
|
||||
}),
|
||||
['BGSAVE', 'SCHEDULE']
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export interface BgSaveOptions {
|
||||
@@ -5,16 +6,13 @@ export interface BgSaveOptions {
|
||||
}
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(options?: BgSaveOptions) {
|
||||
const args = ['BGSAVE'];
|
||||
|
||||
parseCommand(parser: CommandParser, options?: BgSaveOptions) {
|
||||
parser.push('BGSAVE');
|
||||
if (options?.SCHEDULE) {
|
||||
args.push('SCHEDULE');
|
||||
parser.push('SCHEDULE');
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,12 +1,13 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import BITCOUNT from './BITCOUNT';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BITCOUNT', () => {
|
||||
describe('transformArguments', () => {
|
||||
describe('parseCommand', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
BITCOUNT.transformArguments('key'),
|
||||
parseArgs(BITCOUNT, 'key'),
|
||||
['BITCOUNT', 'key']
|
||||
);
|
||||
});
|
||||
@@ -14,7 +15,7 @@ describe('BITCOUNT', () => {
|
||||
describe('with range', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
BITCOUNT.transformArguments('key', {
|
||||
parseArgs(BITCOUNT, 'key', {
|
||||
start: 0,
|
||||
end: 1
|
||||
}),
|
||||
@@ -24,7 +25,7 @@ describe('BITCOUNT', () => {
|
||||
|
||||
it('with mode', () => {
|
||||
assert.deepEqual(
|
||||
BITCOUNT.transformArguments('key', {
|
||||
parseArgs(BITCOUNT, 'key', {
|
||||
start: 0,
|
||||
end: 1,
|
||||
mode: 'BIT'
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, NumberReply, Command } from '../RESP/types';
|
||||
|
||||
export interface BitCountRange {
|
||||
@@ -7,23 +8,19 @@ export interface BitCountRange {
|
||||
}
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
CACHEABLE: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(key: RedisArgument, range?: BitCountRange) {
|
||||
const args = ['BITCOUNT', key];
|
||||
|
||||
parseCommand(parser: CommandParser, key: RedisArgument, range?: BitCountRange) {
|
||||
parser.push('BITCOUNT');
|
||||
parser.pushKey(key);
|
||||
if (range) {
|
||||
args.push(
|
||||
range.start.toString(),
|
||||
range.end.toString()
|
||||
);
|
||||
parser.push(range.start.toString());
|
||||
parser.push(range.end.toString());
|
||||
|
||||
if (range.mode) {
|
||||
args.push(range.mode);
|
||||
parser.push(range.mode);
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import BITFIELD from './BITFIELD';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BITFIELD', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
BITFIELD.transformArguments('key', [{
|
||||
parseArgs(BITFIELD, 'key', [{
|
||||
operation: 'OVERFLOW',
|
||||
behavior: 'WRAP'
|
||||
}, {
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, ArrayReply, NumberReply, NullReply, Command } from '../RESP/types';
|
||||
|
||||
export type BitFieldEncoding = `${'i' | 'u'}${number}`;
|
||||
@@ -39,15 +40,15 @@ export type BitFieldRoOperations = Array<
|
||||
>;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(key: RedisArgument, operations: BitFieldOperations) {
|
||||
const args = ['BITFIELD', key];
|
||||
parseCommand(parser: CommandParser, key: RedisArgument, operations: BitFieldOperations) {
|
||||
parser.push('BITFIELD');
|
||||
parser.pushKey(key);
|
||||
|
||||
for (const options of operations) {
|
||||
switch (options.operation) {
|
||||
case 'GET':
|
||||
args.push(
|
||||
parser.push(
|
||||
'GET',
|
||||
options.encoding,
|
||||
options.offset.toString()
|
||||
@@ -55,7 +56,7 @@ export default {
|
||||
break;
|
||||
|
||||
case 'SET':
|
||||
args.push(
|
||||
parser.push(
|
||||
'SET',
|
||||
options.encoding,
|
||||
options.offset.toString(),
|
||||
@@ -64,7 +65,7 @@ export default {
|
||||
break;
|
||||
|
||||
case 'INCRBY':
|
||||
args.push(
|
||||
parser.push(
|
||||
'INCRBY',
|
||||
options.encoding,
|
||||
options.offset.toString(),
|
||||
@@ -73,15 +74,13 @@ export default {
|
||||
break;
|
||||
|
||||
case 'OVERFLOW':
|
||||
args.push(
|
||||
parser.push(
|
||||
'OVERFLOW',
|
||||
options.behavior
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<NumberReply | NullReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import BITFIELD_RO from './BITFIELD_RO';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BITFIELD_RO', () => {
|
||||
testUtils.isVersionGreaterThanHook([6, 2]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
it('parseCommand', () => {
|
||||
assert.deepEqual(
|
||||
BITFIELD_RO.transformArguments('key', [{
|
||||
parseArgs(BITFIELD_RO, 'key', [{
|
||||
encoding: 'i8',
|
||||
offset: 0
|
||||
}]),
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, ArrayReply, NumberReply, Command } from '../RESP/types';
|
||||
import { BitFieldGetOperation } from './BITFIELD';
|
||||
|
||||
@@ -6,20 +7,17 @@ export type BitFieldRoOperations = Array<
|
||||
>;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
CACHEABLE: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(key: RedisArgument, operations: BitFieldRoOperations) {
|
||||
const args = ['BITFIELD_RO', key];
|
||||
parseCommand(parser: CommandParser, key: RedisArgument, operations: BitFieldRoOperations) {
|
||||
parser.push('BITFIELD_RO');
|
||||
parser.pushKey(key);
|
||||
|
||||
for (const operation of operations) {
|
||||
args.push(
|
||||
'GET',
|
||||
operation.encoding,
|
||||
operation.offset.toString()
|
||||
);
|
||||
parser.push('GET');
|
||||
parser.push(operation.encoding);
|
||||
parser.push(operation.offset.toString())
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => ArrayReply<NumberReply>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import BITOP from './BITOP';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BITOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single key', () => {
|
||||
assert.deepEqual(
|
||||
BITOP.transformArguments('AND', 'destKey', 'key'),
|
||||
parseArgs(BITOP, 'AND', 'destKey', 'key'),
|
||||
['BITOP', 'AND', 'destKey', 'key']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple keys', () => {
|
||||
assert.deepEqual(
|
||||
BITOP.transformArguments('AND', 'destKey', ['1', '2']),
|
||||
parseArgs(BITOP, 'AND', 'destKey', ['1', '2']),
|
||||
['BITOP', 'AND', 'destKey', '1', '2']
|
||||
);
|
||||
});
|
||||
|
@@ -1,17 +1,20 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { NumberReply, Command, RedisArgument } from '../RESP/types';
|
||||
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
|
||||
import { RedisVariadicArgument } from './generic-transformers';
|
||||
|
||||
export type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 2,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(
|
||||
parseCommand(
|
||||
parser: CommandParser,
|
||||
operation: BitOperations,
|
||||
destKey: RedisArgument,
|
||||
key: RedisVariadicArgument
|
||||
) {
|
||||
return pushVariadicArguments(['BITOP', operation, destKey], key);
|
||||
parser.push('BITOP', operation);
|
||||
parser.pushKey(destKey);
|
||||
parser.pushKeys(key);
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,33 +1,34 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import BITPOS from './BITPOS';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BITPOS', () => {
|
||||
describe('transformArguments', () => {
|
||||
describe('parseCommand', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
BITPOS.transformArguments('key', 1),
|
||||
parseArgs(BITPOS, 'key', 1),
|
||||
['BITPOS', 'key', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with start', () => {
|
||||
assert.deepEqual(
|
||||
BITPOS.transformArguments('key', 1, 1),
|
||||
parseArgs(BITPOS, 'key', 1, 1),
|
||||
['BITPOS', 'key', '1', '1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with start and end', () => {
|
||||
assert.deepEqual(
|
||||
BITPOS.transformArguments('key', 1, 1, -1),
|
||||
parseArgs(BITPOS, 'key', 1, 1, -1),
|
||||
['BITPOS', 'key', '1', '1', '-1']
|
||||
);
|
||||
});
|
||||
|
||||
it('with start, end and mode', () => {
|
||||
assert.deepEqual(
|
||||
BITPOS.transformArguments('key', 1, 1, -1, 'BIT'),
|
||||
parseArgs(BITPOS, 'key', 1, 1, -1, 'BIT'),
|
||||
['BITPOS', 'key', '1', '1', '-1', 'BIT']
|
||||
);
|
||||
});
|
||||
|
@@ -1,31 +1,32 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, NumberReply, Command } from '../RESP/types';
|
||||
import { BitValue } from './generic-transformers';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
CACHEABLE: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(
|
||||
parseCommand(parser: CommandParser,
|
||||
key: RedisArgument,
|
||||
bit: BitValue,
|
||||
start?: number,
|
||||
end?: number,
|
||||
mode?: 'BYTE' | 'BIT'
|
||||
) {
|
||||
const args = ['BITPOS', key, bit.toString()];
|
||||
parser.push('BITPOS');
|
||||
parser.pushKey(key);
|
||||
parser.push(bit.toString());
|
||||
|
||||
if (start !== undefined) {
|
||||
args.push(start.toString());
|
||||
parser.push(start.toString());
|
||||
}
|
||||
|
||||
if (end !== undefined) {
|
||||
args.push(end.toString());
|
||||
parser.push(end.toString());
|
||||
}
|
||||
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
parser.push(mode);
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BLMOVE from './BLMOVE';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BLMOVE', () => {
|
||||
testUtils.isVersionGreaterThanHook([6, 2]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
BLMOVE.transformArguments('source', 'destination', 'LEFT', 'RIGHT', 0),
|
||||
parseArgs(BLMOVE, 'source', 'destination', 'LEFT', 'RIGHT', 0),
|
||||
['BLMOVE', 'source', 'destination', 'LEFT', 'RIGHT', '0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,24 +1,20 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
|
||||
import { ListSide } from './generic-transformers';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(
|
||||
parseCommand(
|
||||
parser: CommandParser,
|
||||
source: RedisArgument,
|
||||
destination: RedisArgument,
|
||||
sourceSide: ListSide,
|
||||
destinationSide: ListSide,
|
||||
timeout: number
|
||||
) {
|
||||
return [
|
||||
'BLMOVE',
|
||||
source,
|
||||
destination,
|
||||
sourceSide,
|
||||
destinationSide,
|
||||
timeout.toString()
|
||||
];
|
||||
parser.push('BLMOVE');
|
||||
parser.pushKeys([source, destination]);
|
||||
parser.push(sourceSide, destinationSide, timeout.toString())
|
||||
},
|
||||
transformReply: undefined as unknown as () => BlobStringReply | NullReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BLMPOP from './BLMPOP';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BLMPOP', () => {
|
||||
testUtils.isVersionGreaterThanHook([7]);
|
||||
@@ -8,14 +9,14 @@ describe('BLMPOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
BLMPOP.transformArguments(0, 'key', 'LEFT'),
|
||||
parseArgs(BLMPOP, 0, 'key', 'LEFT'),
|
||||
['BLMPOP', '0', '1', 'key', 'LEFT']
|
||||
);
|
||||
});
|
||||
|
||||
it('with COUNT', () => {
|
||||
assert.deepEqual(
|
||||
BLMPOP.transformArguments(0, 'key', 'LEFT', {
|
||||
parseArgs(BLMPOP, 0, 'key', 'LEFT', {
|
||||
COUNT: 1
|
||||
}),
|
||||
['BLMPOP', '0', '1', 'key', 'LEFT', 'COUNT', '1']
|
||||
|
@@ -1,17 +1,12 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { Command } from '../RESP/types';
|
||||
import LMPOP, { LMPopArguments, transformLMPopArguments } from './LMPOP';
|
||||
import LMPOP, { LMPopArguments, parseLMPopArguments } from './LMPOP';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 3,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(
|
||||
timeout: number,
|
||||
...args: LMPopArguments
|
||||
) {
|
||||
return transformLMPopArguments(
|
||||
['BLMPOP', timeout.toString()],
|
||||
...args
|
||||
);
|
||||
},
|
||||
parseCommand(parser: CommandParser, timeout: number, ...args: LMPopArguments) {
|
||||
parser.push('BLMPOP', timeout.toString());
|
||||
parseLMPopArguments(parser, ...args);
|
||||
},
|
||||
transformReply: LMPOP.transformReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BLPOP from './BLPOP';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BLPOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
BLPOP.transformArguments('key', 0),
|
||||
parseArgs(BLPOP, 'key', 0),
|
||||
['BLPOP', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
BLPOP.transformArguments(['1', '2'], 0),
|
||||
parseArgs(BLPOP, ['1', '2'], 0),
|
||||
['BLPOP', '1', '2', '0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,16 +1,13 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { UnwrapReply, NullReply, TuplesReply, BlobStringReply, Command } from '../RESP/types';
|
||||
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
|
||||
import { RedisVariadicArgument } from './generic-transformers';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(
|
||||
key: RedisVariadicArgument,
|
||||
timeout: number
|
||||
) {
|
||||
const args = pushVariadicArguments(['BLPOP'], key);
|
||||
args.push(timeout.toString());
|
||||
return args;
|
||||
parseCommand(parser: CommandParser, key: RedisVariadicArgument, timeout: number) {
|
||||
parser.push('BLPOP');
|
||||
parser.pushKeys(key);
|
||||
parser.push(timeout.toString());
|
||||
},
|
||||
transformReply(reply: UnwrapReply<NullReply | TuplesReply<[BlobStringReply, BlobStringReply]>>) {
|
||||
if (reply === null) return null;
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BRPOP from './BRPOP';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BRPOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
BRPOP.transformArguments('key', 0),
|
||||
parseArgs(BRPOP, 'key', 0),
|
||||
['BRPOP', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
BRPOP.transformArguments(['1', '2'], 0),
|
||||
parseArgs(BRPOP, ['1', '2'], 0),
|
||||
['BRPOP', '1', '2', '0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,17 +1,14 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { Command } from '../RESP/types';
|
||||
import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers';
|
||||
import { RedisVariadicArgument } from './generic-transformers';
|
||||
import BLPOP from './BLPOP';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(
|
||||
key: RedisVariadicArgument,
|
||||
timeout: number
|
||||
) {
|
||||
const args = pushVariadicArguments(['BRPOP'], key);
|
||||
args.push(timeout.toString());
|
||||
return args;
|
||||
parseCommand(parser: CommandParser, key: RedisVariadicArgument, timeout: number) {
|
||||
parser.push('BRPOP');
|
||||
parser.pushKeys(key);
|
||||
parser.push(timeout.toString());
|
||||
},
|
||||
transformReply: BLPOP.transformReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BRPOPLPUSH from './BRPOPLPUSH';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BRPOPLPUSH', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
BRPOPLPUSH.transformArguments('source', 'destination', 0),
|
||||
parseArgs(BRPOPLPUSH, 'source', 'destination', 0),
|
||||
['BRPOPLPUSH', 'source', 'destination', '0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,14 +1,12 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(
|
||||
source: RedisArgument,
|
||||
destination: RedisArgument,
|
||||
timeout: number
|
||||
) {
|
||||
return ['BRPOPLPUSH', source, destination, timeout.toString()];
|
||||
parseCommand(parser: CommandParser, source: RedisArgument, destination: RedisArgument, timeout: number) {
|
||||
parser.push('BRPOPLPUSH');
|
||||
parser.pushKeys([source, destination]);
|
||||
parser.push(timeout.toString());
|
||||
},
|
||||
transformReply: undefined as unknown as () => BlobStringReply | NullReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BZMPOP from './BZMPOP';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BZMPOP', () => {
|
||||
testUtils.isVersionGreaterThanHook([7]);
|
||||
@@ -8,14 +9,14 @@ describe('BZMPOP', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
BZMPOP.transformArguments(0, 'key', 'MIN'),
|
||||
parseArgs(BZMPOP, 0, 'key', 'MIN'),
|
||||
['BZMPOP', '0', '1', 'key', 'MIN']
|
||||
);
|
||||
});
|
||||
|
||||
it('with COUNT', () => {
|
||||
assert.deepEqual(
|
||||
BZMPOP.transformArguments(0, 'key', 'MIN', {
|
||||
parseArgs(BZMPOP, 0, 'key', 'MIN', {
|
||||
COUNT: 2
|
||||
}),
|
||||
['BZMPOP', '0', '1', 'key', 'MIN', 'COUNT', '2']
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { Command } from '../RESP/types';
|
||||
import ZMPOP, { ZMPopArguments, transformZMPopArguments } from './ZMPOP';
|
||||
import ZMPOP, { parseZMPopArguments, ZMPopArguments } from './ZMPOP';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 3,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(timeout: number, ...args: ZMPopArguments) {
|
||||
return transformZMPopArguments(['BZMPOP', timeout.toString()], ...args);
|
||||
parseCommand(parser: CommandParser, timeout: number, ...args: ZMPopArguments) {
|
||||
parser.push('BZMPOP', timeout.toString());
|
||||
parseZMPopArguments(parser, ...args);
|
||||
},
|
||||
transformReply: ZMPOP.transformReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BZPOPMAX from './BZPOPMAX';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BZPOPMAX', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
BZPOPMAX.transformArguments('key', 0),
|
||||
parseArgs(BZPOPMAX, 'key', 0),
|
||||
['BZPOPMAX', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
BZPOPMAX.transformArguments(['1', '2'], 0),
|
||||
parseArgs(BZPOPMAX, ['1', '2'], 0),
|
||||
['BZPOPMAX', '1', '2', '0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,23 +1,13 @@
|
||||
import { RedisArgument, NullReply, TuplesReply, BlobStringReply, DoubleReply, UnwrapReply, Command, TypeMapping } from '../RESP/types';
|
||||
import { RedisVariadicArgument, pushVariadicArguments, transformDoubleReply } from './generic-transformers';
|
||||
|
||||
export function transformBZPopArguments(
|
||||
command: RedisArgument,
|
||||
key: RedisVariadicArgument,
|
||||
timeout: number
|
||||
) {
|
||||
const args = pushVariadicArguments([command], key);
|
||||
args.push(timeout.toString());
|
||||
return args;
|
||||
}
|
||||
|
||||
export type BZPopArguments = typeof transformBZPopArguments extends (_: any, ...args: infer T) => any ? T : never;
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { NullReply, TuplesReply, BlobStringReply, DoubleReply, UnwrapReply, Command, TypeMapping } from '../RESP/types';
|
||||
import { RedisVariadicArgument, transformDoubleReply } from './generic-transformers';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: 1,
|
||||
IS_READ_ONLY: false,
|
||||
transformArguments(...args: BZPopArguments) {
|
||||
return transformBZPopArguments('BZPOPMAX', ...args);
|
||||
parseCommand(parser: CommandParser, keys: RedisVariadicArgument, timeout: number) {
|
||||
parser.push('BZPOPMAX');
|
||||
parser.pushKeys(keys);
|
||||
parser.push(timeout.toString());
|
||||
},
|
||||
transformReply: {
|
||||
2(
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL, BLOCKING_MIN_VALUE } from '../test-utils';
|
||||
import BZPOPMIN from './BZPOPMIN';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('BZPOPMIN', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('single', () => {
|
||||
assert.deepEqual(
|
||||
BZPOPMIN.transformArguments('key', 0),
|
||||
parseArgs(BZPOPMIN, 'key', 0),
|
||||
['BZPOPMIN', 'key', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('multiple', () => {
|
||||
assert.deepEqual(
|
||||
BZPOPMIN.transformArguments(['1', '2'], 0),
|
||||
parseArgs(BZPOPMIN, ['1', '2'], 0),
|
||||
['BZPOPMIN', '1', '2', '0']
|
||||
);
|
||||
});
|
||||
|
@@ -1,11 +1,14 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { Command } from '../RESP/types';
|
||||
import BZPOPMAX, { BZPopArguments, transformBZPopArguments } from './BZPOPMAX';
|
||||
import { RedisVariadicArgument } from './generic-transformers';
|
||||
import BZPOPMAX from './BZPOPMAX';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: BZPOPMAX.FIRST_KEY_INDEX,
|
||||
IS_READ_ONLY: BZPOPMAX.IS_READ_ONLY,
|
||||
transformArguments(...args: BZPopArguments) {
|
||||
return transformBZPopArguments('BZPOPMIN', ...args);
|
||||
parseCommand(parser: CommandParser, keys: RedisVariadicArgument, timeout: number) {
|
||||
parser.push('BZPOPMIN');
|
||||
parser.pushKeys(keys);
|
||||
parser.push(timeout.toString());
|
||||
},
|
||||
transformReply: BZPOPMAX.transformReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,18 +1,19 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import CLIENT_CACHING from './CLIENT_CACHING';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT CACHING', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('true', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_CACHING.transformArguments(true),
|
||||
parseArgs(CLIENT_CACHING, true),
|
||||
['CLIENT', 'CACHING', 'YES']
|
||||
);
|
||||
});
|
||||
|
||||
it('false', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_CACHING.transformArguments(false),
|
||||
parseArgs(CLIENT_CACHING, false),
|
||||
['CLIENT', 'CACHING', 'NO']
|
||||
);
|
||||
});
|
||||
|
@@ -1,14 +1,15 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(value: boolean) {
|
||||
return [
|
||||
parseCommand(parser: CommandParser, value: boolean) {
|
||||
parser.push(
|
||||
'CLIENT',
|
||||
'CACHING',
|
||||
value ? 'YES' : 'NO'
|
||||
];
|
||||
);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CLIENT_GETNAME from './CLIENT_GETNAME';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT GETNAME', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_GETNAME.transformArguments(),
|
||||
parseArgs(CLIENT_GETNAME),
|
||||
['CLIENT', 'GETNAME']
|
||||
);
|
||||
});
|
||||
|
@@ -1,13 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { BlobStringReply, NullReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return [
|
||||
'CLIENT',
|
||||
'GETNAME'
|
||||
];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('CLIENT', 'GETNAME');
|
||||
},
|
||||
transformReply: undefined as unknown as () => BlobStringReply | NullReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import CLIENT_GETREDIR from './CLIENT_GETREDIR';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT GETREDIR', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_GETREDIR.transformArguments(),
|
||||
parseArgs(CLIENT_GETREDIR),
|
||||
['CLIENT', 'GETREDIR']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { NumberReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['CLIENT', 'GETREDIR']
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('CLIENT', 'GETREDIR');
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CLIENT_ID from './CLIENT_ID';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT ID', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_ID.transformArguments(),
|
||||
parseArgs(CLIENT_ID),
|
||||
['CLIENT', 'ID']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { NumberReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['CLIENT', 'ID'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('CLIENT', 'ID');
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import CLIENT_INFO from './CLIENT_INFO';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT INFO', () => {
|
||||
testUtils.isVersionGreaterThanHook([6, 2]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_INFO.transformArguments(),
|
||||
parseArgs(CLIENT_INFO),
|
||||
['CLIENT', 'INFO']
|
||||
);
|
||||
});
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { Command, VerbatimStringReply } from '../RESP/types';
|
||||
|
||||
export interface ClientInfoReply {
|
||||
@@ -56,10 +57,10 @@ export interface ClientInfoReply {
|
||||
const CLIENT_INFO_REGEX = /([^\s=]+)=([^\s]*)/g;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['CLIENT', 'INFO']
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('CLIENT', 'INFO');
|
||||
},
|
||||
transformReply(rawReply: VerbatimStringReply) {
|
||||
const map: Record<string, string> = {};
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import CLIENT_KILL, { CLIENT_KILL_FILTERS } from './CLIENT_KILL';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT KILL', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('ADDRESS', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.ADDRESS,
|
||||
address: 'ip:6379'
|
||||
}),
|
||||
@@ -15,7 +16,7 @@ describe('CLIENT KILL', () => {
|
||||
|
||||
it('LOCAL_ADDRESS', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.LOCAL_ADDRESS,
|
||||
localAddress: 'ip:6379'
|
||||
}),
|
||||
@@ -26,7 +27,7 @@ describe('CLIENT KILL', () => {
|
||||
describe('ID', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.ID,
|
||||
id: '1'
|
||||
}),
|
||||
@@ -36,7 +37,7 @@ describe('CLIENT KILL', () => {
|
||||
|
||||
it('number', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.ID,
|
||||
id: 1
|
||||
}),
|
||||
@@ -47,7 +48,7 @@ describe('CLIENT KILL', () => {
|
||||
|
||||
it('TYPE', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.TYPE,
|
||||
type: 'master'
|
||||
}),
|
||||
@@ -57,7 +58,7 @@ describe('CLIENT KILL', () => {
|
||||
|
||||
it('USER', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.USER,
|
||||
username: 'username'
|
||||
}),
|
||||
@@ -67,7 +68,7 @@ describe('CLIENT KILL', () => {
|
||||
|
||||
it('MAXAGE', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.MAXAGE,
|
||||
maxAge: 10
|
||||
}),
|
||||
@@ -78,14 +79,14 @@ describe('CLIENT KILL', () => {
|
||||
describe('SKIP_ME', () => {
|
||||
it('undefined', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments(CLIENT_KILL_FILTERS.SKIP_ME),
|
||||
parseArgs(CLIENT_KILL, CLIENT_KILL_FILTERS.SKIP_ME),
|
||||
['CLIENT', 'KILL', 'SKIPME']
|
||||
);
|
||||
});
|
||||
|
||||
it('true', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.SKIP_ME,
|
||||
skipMe: true
|
||||
}),
|
||||
@@ -95,7 +96,7 @@ describe('CLIENT KILL', () => {
|
||||
|
||||
it('false', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments({
|
||||
parseArgs(CLIENT_KILL, {
|
||||
filter: CLIENT_KILL_FILTERS.SKIP_ME,
|
||||
skipMe: false
|
||||
}),
|
||||
@@ -106,7 +107,7 @@ describe('CLIENT KILL', () => {
|
||||
|
||||
it('TYPE & SKIP_ME', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_KILL.transformArguments([
|
||||
parseArgs(CLIENT_KILL, [
|
||||
{
|
||||
filter: CLIENT_KILL_FILTERS.TYPE,
|
||||
type: 'master'
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { RedisArgument, NumberReply, Command } from '../RESP/types';
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { NumberReply, Command } from '../RESP/types';
|
||||
|
||||
export const CLIENT_KILL_FILTERS = {
|
||||
ADDRESS: 'ADDR',
|
||||
@@ -47,43 +48,42 @@ export interface ClientKillMaxAge extends ClientKillFilterCommon<CLIENT_KILL_FIL
|
||||
export type ClientKillFilter = ClientKillAddress | ClientKillLocalAddress | ClientKillId | ClientKillType | ClientKillUser | ClientKillSkipMe | ClientKillMaxAge;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(filters: ClientKillFilter | Array<ClientKillFilter>) {
|
||||
const args = ['CLIENT', 'KILL'];
|
||||
parseCommand(parser: CommandParser, filters: ClientKillFilter | Array<ClientKillFilter>) {
|
||||
parser.push('CLIENT', 'KILL');
|
||||
|
||||
if (Array.isArray(filters)) {
|
||||
for (const filter of filters) {
|
||||
pushFilter(args, filter);
|
||||
pushFilter(parser, filter);
|
||||
}
|
||||
} else {
|
||||
pushFilter(args, filters);
|
||||
pushFilter(parser, filters);
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => NumberReply
|
||||
} as const satisfies Command;
|
||||
|
||||
function pushFilter(args: Array<RedisArgument>, filter: ClientKillFilter): void {
|
||||
function pushFilter(parser: CommandParser, filter: ClientKillFilter): void {
|
||||
if (filter === CLIENT_KILL_FILTERS.SKIP_ME) {
|
||||
args.push('SKIPME');
|
||||
parser.push('SKIPME');
|
||||
return;
|
||||
}
|
||||
|
||||
args.push(filter.filter);
|
||||
parser.push(filter.filter);
|
||||
|
||||
switch (filter.filter) {
|
||||
case CLIENT_KILL_FILTERS.ADDRESS:
|
||||
args.push(filter.address);
|
||||
parser.push(filter.address);
|
||||
break;
|
||||
|
||||
case CLIENT_KILL_FILTERS.LOCAL_ADDRESS:
|
||||
args.push(filter.localAddress);
|
||||
parser.push(filter.localAddress);
|
||||
break;
|
||||
|
||||
case CLIENT_KILL_FILTERS.ID:
|
||||
args.push(
|
||||
parser.push(
|
||||
typeof filter.id === 'number' ?
|
||||
filter.id.toString() :
|
||||
filter.id
|
||||
@@ -91,19 +91,19 @@ function pushFilter(args: Array<RedisArgument>, filter: ClientKillFilter): void
|
||||
break;
|
||||
|
||||
case CLIENT_KILL_FILTERS.TYPE:
|
||||
args.push(filter.type);
|
||||
parser.push(filter.type);
|
||||
break;
|
||||
|
||||
case CLIENT_KILL_FILTERS.USER:
|
||||
args.push(filter.username);
|
||||
parser.push(filter.username);
|
||||
break;
|
||||
|
||||
case CLIENT_KILL_FILTERS.SKIP_ME:
|
||||
args.push(filter.skipMe ? 'yes' : 'no');
|
||||
parser.push(filter.skipMe ? 'yes' : 'no');
|
||||
break;
|
||||
|
||||
case CLIENT_KILL_FILTERS.MAXAGE:
|
||||
args.push(filter.maxAge.toString());
|
||||
parser.push(filter.maxAge.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import CLIENT_LIST from './CLIENT_LIST';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT LIST', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_LIST.transformArguments(),
|
||||
parseArgs(CLIENT_LIST),
|
||||
['CLIENT', 'LIST']
|
||||
);
|
||||
});
|
||||
|
||||
it('with TYPE', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_LIST.transformArguments({
|
||||
parseArgs(CLIENT_LIST, {
|
||||
TYPE: 'NORMAL'
|
||||
}),
|
||||
['CLIENT', 'LIST', 'TYPE', 'NORMAL']
|
||||
@@ -22,7 +23,7 @@ describe('CLIENT LIST', () => {
|
||||
|
||||
it('with ID', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_LIST.transformArguments({
|
||||
parseArgs(CLIENT_LIST, {
|
||||
ID: ['1', '2']
|
||||
}),
|
||||
['CLIENT', 'LIST', 'ID', '1', '2']
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, VerbatimStringReply, Command } from '../RESP/types';
|
||||
import { pushVariadicArguments } from './generic-transformers';
|
||||
import CLIENT_INFO, { ClientInfoReply } from './CLIENT_INFO';
|
||||
|
||||
export interface ListFilterType {
|
||||
@@ -15,21 +15,18 @@ export interface ListFilterId {
|
||||
export type ListFilter = ListFilterType | ListFilterId;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(filter?: ListFilter) {
|
||||
let args: Array<RedisArgument> = ['CLIENT', 'LIST'];
|
||||
|
||||
parseCommand(parser: CommandParser, filter?: ListFilter) {
|
||||
parser.push('CLIENT', 'LIST');
|
||||
if (filter) {
|
||||
if (filter.TYPE !== undefined) {
|
||||
args.push('TYPE', filter.TYPE);
|
||||
parser.push('TYPE', filter.TYPE);
|
||||
} else {
|
||||
args.push('ID');
|
||||
args = pushVariadicArguments(args, filter.ID);
|
||||
parser.push('ID');
|
||||
parser.pushVariadic(filter.ID);
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply(rawReply: VerbatimStringReply): Array<ClientInfoReply> {
|
||||
const split = rawReply.toString().split('\n'),
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CLIENT_NO_EVICT from './CLIENT_NO-EVICT';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT NO-EVICT', () => {
|
||||
testUtils.isVersionGreaterThanHook([7]);
|
||||
@@ -8,14 +9,14 @@ describe('CLIENT NO-EVICT', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('true', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_NO_EVICT.transformArguments(true),
|
||||
parseArgs(CLIENT_NO_EVICT, true),
|
||||
['CLIENT', 'NO-EVICT', 'ON']
|
||||
);
|
||||
});
|
||||
|
||||
it('false', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_NO_EVICT.transformArguments(false),
|
||||
parseArgs(CLIENT_NO_EVICT, false),
|
||||
['CLIENT', 'NO-EVICT', 'OFF']
|
||||
);
|
||||
});
|
||||
|
@@ -1,14 +1,15 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(value: boolean) {
|
||||
return [
|
||||
parseCommand(parser: CommandParser, value: boolean) {
|
||||
parser.push(
|
||||
'CLIENT',
|
||||
'NO-EVICT',
|
||||
value ? 'ON' : 'OFF'
|
||||
];
|
||||
);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CLIENT_NO_TOUCH from './CLIENT_NO-TOUCH';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT NO-TOUCH', () => {
|
||||
testUtils.isVersionGreaterThanHook([7, 2]);
|
||||
@@ -8,14 +9,14 @@ describe('CLIENT NO-TOUCH', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('true', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_NO_TOUCH.transformArguments(true),
|
||||
parseArgs(CLIENT_NO_TOUCH, true),
|
||||
['CLIENT', 'NO-TOUCH', 'ON']
|
||||
);
|
||||
});
|
||||
|
||||
it('false', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_NO_TOUCH.transformArguments(false),
|
||||
parseArgs(CLIENT_NO_TOUCH, false),
|
||||
['CLIENT', 'NO-TOUCH', 'OFF']
|
||||
);
|
||||
});
|
||||
|
@@ -1,14 +1,15 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(value: boolean) {
|
||||
return [
|
||||
parseCommand(parser: CommandParser, value: boolean) {
|
||||
parser.push(
|
||||
'CLIENT',
|
||||
'NO-TOUCH',
|
||||
value ? 'ON' : 'OFF'
|
||||
];
|
||||
);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,19 +1,20 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CLIENT_PAUSE from './CLIENT_PAUSE';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT PAUSE', () => {
|
||||
describe('transformArguments', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_PAUSE.transformArguments(0),
|
||||
parseArgs(CLIENT_PAUSE, 0),
|
||||
['CLIENT', 'PAUSE', '0']
|
||||
);
|
||||
});
|
||||
|
||||
it('with mode', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_PAUSE.transformArguments(0, 'ALL'),
|
||||
parseArgs(CLIENT_PAUSE, 0, 'ALL'),
|
||||
['CLIENT', 'PAUSE', '0', 'ALL']
|
||||
);
|
||||
});
|
||||
|
@@ -1,20 +1,14 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(timeout: number, mode?: 'WRITE' | 'ALL') {
|
||||
const args = [
|
||||
'CLIENT',
|
||||
'PAUSE',
|
||||
timeout.toString()
|
||||
];
|
||||
|
||||
parseCommand(parser: CommandParser, timeout: number, mode?: 'WRITE' | 'ALL') {
|
||||
parser.push('CLIENT', 'PAUSE', timeout.toString());
|
||||
if (mode) {
|
||||
args.push(mode);
|
||||
parser.push(mode);
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -2,11 +2,12 @@ import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
|
||||
import CLIENT_SETNAME from './CLIENT_SETNAME';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT SETNAME', () => {
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_SETNAME.transformArguments('name'),
|
||||
parseArgs(CLIENT_SETNAME, 'name'),
|
||||
['CLIENT', 'SETNAME', 'name']
|
||||
);
|
||||
});
|
||||
|
@@ -1,10 +1,11 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments(name: RedisArgument) {
|
||||
return ['CLIENT', 'SETNAME', name];
|
||||
parseCommand(parser: CommandParser, name: RedisArgument) {
|
||||
parser.push('CLIENT', 'SETNAME', name);
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CLIENT_TRACKING from './CLIENT_TRACKING';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT TRACKING', () => {
|
||||
testUtils.isVersionGreaterThanHook([6]);
|
||||
@@ -9,14 +10,14 @@ describe('CLIENT TRACKING', () => {
|
||||
describe('true', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true),
|
||||
parseArgs(CLIENT_TRACKING, true),
|
||||
['CLIENT', 'TRACKING', 'ON']
|
||||
);
|
||||
});
|
||||
|
||||
it('with REDIRECT', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true, {
|
||||
parseArgs(CLIENT_TRACKING, true, {
|
||||
REDIRECT: 1
|
||||
}),
|
||||
['CLIENT', 'TRACKING', 'ON', 'REDIRECT', '1']
|
||||
@@ -26,7 +27,7 @@ describe('CLIENT TRACKING', () => {
|
||||
describe('with BCAST', () => {
|
||||
it('simple', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true, {
|
||||
parseArgs(CLIENT_TRACKING, true, {
|
||||
BCAST: true
|
||||
}),
|
||||
['CLIENT', 'TRACKING', 'ON', 'BCAST']
|
||||
@@ -36,7 +37,7 @@ describe('CLIENT TRACKING', () => {
|
||||
describe('with PREFIX', () => {
|
||||
it('string', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true, {
|
||||
parseArgs(CLIENT_TRACKING, true, {
|
||||
BCAST: true,
|
||||
PREFIX: 'prefix'
|
||||
}),
|
||||
@@ -46,7 +47,7 @@ describe('CLIENT TRACKING', () => {
|
||||
|
||||
it('array', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true, {
|
||||
parseArgs(CLIENT_TRACKING, true, {
|
||||
BCAST: true,
|
||||
PREFIX: ['1', '2']
|
||||
}),
|
||||
@@ -58,7 +59,7 @@ describe('CLIENT TRACKING', () => {
|
||||
|
||||
it('with OPTIN', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true, {
|
||||
parseArgs(CLIENT_TRACKING, true, {
|
||||
OPTIN: true
|
||||
}),
|
||||
['CLIENT', 'TRACKING', 'ON', 'OPTIN']
|
||||
@@ -67,7 +68,7 @@ describe('CLIENT TRACKING', () => {
|
||||
|
||||
it('with OPTOUT', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true, {
|
||||
parseArgs(CLIENT_TRACKING, true, {
|
||||
OPTOUT: true
|
||||
}),
|
||||
['CLIENT', 'TRACKING', 'ON', 'OPTOUT']
|
||||
@@ -76,7 +77,7 @@ describe('CLIENT TRACKING', () => {
|
||||
|
||||
it('with NOLOOP', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(true, {
|
||||
parseArgs(CLIENT_TRACKING, true, {
|
||||
NOLOOP: true
|
||||
}),
|
||||
['CLIENT', 'TRACKING', 'ON', 'NOLOOP']
|
||||
@@ -86,7 +87,7 @@ describe('CLIENT TRACKING', () => {
|
||||
|
||||
it('false', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKING.transformArguments(false),
|
||||
parseArgs(CLIENT_TRACKING, false),
|
||||
['CLIENT', 'TRACKING', 'OFF']
|
||||
);
|
||||
});
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { RedisArgument, SimpleStringReply, Command } from '../RESP/types';
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { SimpleStringReply, Command } from '../RESP/types';
|
||||
import { RedisVariadicArgument } from './generic-transformers';
|
||||
|
||||
interface CommonOptions {
|
||||
@@ -26,50 +27,49 @@ export type ClientTrackingOptions = CommonOptions & (
|
||||
);
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments<M extends boolean>(
|
||||
parseCommand<M extends boolean>(
|
||||
parser: CommandParser,
|
||||
mode: M,
|
||||
options?: M extends true ? ClientTrackingOptions : never
|
||||
) {
|
||||
const args: Array<RedisArgument> = [
|
||||
parser.push(
|
||||
'CLIENT',
|
||||
'TRACKING',
|
||||
mode ? 'ON' : 'OFF'
|
||||
];
|
||||
);
|
||||
|
||||
if (mode) {
|
||||
if (options?.REDIRECT) {
|
||||
args.push(
|
||||
parser.push(
|
||||
'REDIRECT',
|
||||
options.REDIRECT.toString()
|
||||
);
|
||||
}
|
||||
|
||||
if (isBroadcast(options)) {
|
||||
args.push('BCAST');
|
||||
parser.push('BCAST');
|
||||
|
||||
if (options?.PREFIX) {
|
||||
if (Array.isArray(options.PREFIX)) {
|
||||
for (const prefix of options.PREFIX) {
|
||||
args.push('PREFIX', prefix);
|
||||
parser.push('PREFIX', prefix);
|
||||
}
|
||||
} else {
|
||||
args.push('PREFIX', options.PREFIX);
|
||||
parser.push('PREFIX', options.PREFIX);
|
||||
}
|
||||
}
|
||||
} else if (isOptIn(options)) {
|
||||
args.push('OPTIN');
|
||||
parser.push('OPTIN');
|
||||
} else if (isOptOut(options)) {
|
||||
args.push('OPTOUT');
|
||||
parser.push('OPTOUT');
|
||||
}
|
||||
|
||||
if (options?.NOLOOP) {
|
||||
args.push('NOLOOP');
|
||||
parser.push('NOLOOP');
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
},
|
||||
transformReply: undefined as unknown as () => SimpleStringReply<'OK'>
|
||||
} as const satisfies Command;
|
||||
|
@@ -1,13 +1,14 @@
|
||||
import { strict as assert } from 'node:assert';
|
||||
import testUtils, { GLOBAL } from '../test-utils';
|
||||
import CLIENT_TRACKINGINFO from './CLIENT_TRACKINGINFO';
|
||||
import { parseArgs } from './generic-transformers';
|
||||
|
||||
describe('CLIENT TRACKINGINFO', () => {
|
||||
testUtils.isVersionGreaterThanHook([6, 2]);
|
||||
|
||||
it('transformArguments', () => {
|
||||
assert.deepEqual(
|
||||
CLIENT_TRACKINGINFO.transformArguments(),
|
||||
parseArgs(CLIENT_TRACKINGINFO),
|
||||
['CLIENT', 'TRACKINGINFO']
|
||||
);
|
||||
});
|
||||
|
@@ -1,3 +1,4 @@
|
||||
import { CommandParser } from '../client/parser';
|
||||
import { TuplesToMapReply, BlobStringReply, SetReply, NumberReply, ArrayReply, UnwrapReply, Resp2Reply, Command } from '../RESP/types';
|
||||
|
||||
type TrackingInfo = TuplesToMapReply<[
|
||||
@@ -7,10 +8,10 @@ type TrackingInfo = TuplesToMapReply<[
|
||||
]>;
|
||||
|
||||
export default {
|
||||
FIRST_KEY_INDEX: undefined,
|
||||
NOT_KEYED_COMMAND: true,
|
||||
IS_READ_ONLY: true,
|
||||
transformArguments() {
|
||||
return ['CLIENT', 'TRACKINGINFO'];
|
||||
parseCommand(parser: CommandParser) {
|
||||
parser.push('CLIENT', 'TRACKINGINFO');
|
||||
},
|
||||
transformReply: {
|
||||
2: (reply: UnwrapReply<Resp2Reply<TrackingInfo>>) => ({
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user