You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-09 00:22:08 +03:00
fix #1650 - add support for Buffer in some commands, add GET_BUFFER command
This commit is contained in:
@@ -195,6 +195,13 @@ describe('Client', () => {
|
|||||||
assert.equal(await client.sendCommand(['PING']), 'PONG');
|
assert.equal(await client.sendCommand(['PING']), 'PONG');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
itWithClient(TestRedisServers.OPEN, 'bufferMode', async client => {
|
||||||
|
assert.deepEqual(
|
||||||
|
await client.sendCommand(['PING'], undefined, true),
|
||||||
|
Buffer.from('PONG')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
describe('AbortController', () => {
|
describe('AbortController', () => {
|
||||||
before(function () {
|
before(function () {
|
||||||
if (!global.AbortController) {
|
if (!global.AbortController) {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import RedisSocket, { RedisSocketOptions } from './socket';
|
import RedisSocket, { RedisSocketOptions } from './socket';
|
||||||
import RedisCommandsQueue, { PubSubListener, PubSubSubscribeCommands, PubSubUnsubscribeCommands, QueueCommandOptions } from './commands-queue';
|
import RedisCommandsQueue, { PubSubListener, PubSubSubscribeCommands, PubSubUnsubscribeCommands, QueueCommandOptions } from './commands-queue';
|
||||||
import COMMANDS from './commands';
|
import COMMANDS, { TransformArgumentsReply } from './commands';
|
||||||
import { RedisCommand, RedisModules, RedisReply } from './commands';
|
import { RedisCommand, RedisModules, RedisReply } from './commands';
|
||||||
import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command';
|
import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
@@ -62,12 +62,10 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
): Promise<ReturnType<typeof command['transformReply']>> {
|
): Promise<ReturnType<typeof command['transformReply']>> {
|
||||||
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(command, args);
|
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(command, args);
|
||||||
|
|
||||||
const reply = command.transformReply(
|
return command.transformReply(
|
||||||
await this.#sendCommand(redisArgs, options),
|
await this.#sendCommand(redisArgs, options, command.BUFFER_MODE),
|
||||||
redisArgs.preserve
|
redisArgs.preserve,
|
||||||
);
|
);
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #scriptsExecutor(
|
static async #scriptsExecutor(
|
||||||
@@ -77,12 +75,10 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
): Promise<typeof script['transformArguments']> {
|
): Promise<typeof script['transformArguments']> {
|
||||||
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(script, args);
|
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(script, args);
|
||||||
|
|
||||||
const reply = script.transformReply(
|
return script.transformReply(
|
||||||
await this.executeScript(script, redisArgs, options),
|
await this.executeScript(script, redisArgs, options, script.BUFFER_MODE),
|
||||||
redisArgs.preserve
|
redisArgs.preserve
|
||||||
);
|
);
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static create<M extends RedisModules, S extends RedisLuaScripts>(options?: RedisClientOptions<M, S>): RedisClientType<M, S> {
|
static create<M extends RedisModules, S extends RedisLuaScripts>(options?: RedisClientOptions<M, S>): RedisClientType<M, S> {
|
||||||
@@ -182,10 +178,7 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
}
|
}
|
||||||
|
|
||||||
#initiateQueue(): RedisCommandsQueue {
|
#initiateQueue(): RedisCommandsQueue {
|
||||||
return new RedisCommandsQueue(
|
return new RedisCommandsQueue(this.#options?.commandsQueueMaxLength);
|
||||||
this.#options?.commandsQueueMaxLength,
|
|
||||||
encodedCommands => this.#socket.write(encodedCommands)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#legacyMode(): void {
|
#legacyMode(): void {
|
||||||
@@ -299,7 +292,7 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
|
|
||||||
QUIT(): Promise<void> {
|
QUIT(): Promise<void> {
|
||||||
return this.#socket.quit(() => {
|
return this.#socket.quit(() => {
|
||||||
const promise = this.#queue.addEncodedCommand(encodeCommand(['QUIT']));
|
const promise = this.#queue.addCommand(['QUIT']);
|
||||||
this.#tick();
|
this.#tick();
|
||||||
return promise;
|
return promise;
|
||||||
});
|
});
|
||||||
@@ -307,46 +300,64 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
|
|
||||||
quit = this.QUIT;
|
quit = this.QUIT;
|
||||||
|
|
||||||
sendCommand<T = unknown>(args: Array<string>, options?: ClientCommandOptions): Promise<T> {
|
sendCommand<T = RedisReply>(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<T> {
|
||||||
return this.#sendCommand(args, options);
|
return this.#sendCommand(args, options, bufferMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// using `#sendCommand` cause `sendCommand` is overwritten in legacy mode
|
// using `#sendCommand` cause `sendCommand` is overwritten in legacy mode
|
||||||
#sendCommand<T = RedisReply>(args: Array<string>, options?: ClientCommandOptions): Promise<T> {
|
async #sendCommand<T = RedisReply>(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<T> {
|
||||||
return this.sendEncodedCommand(encodeCommand(args), options);
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendEncodedCommand<T = RedisReply>(encodedCommand: string, options?: ClientCommandOptions): Promise<T> {
|
|
||||||
if (!this.#socket.isOpen) {
|
if (!this.#socket.isOpen) {
|
||||||
throw new ClientClosedError();
|
throw new ClientClosedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options?.isolated) {
|
if (options?.isolated) {
|
||||||
return this.executeIsolated(isolatedClient =>
|
return this.executeIsolated(isolatedClient =>
|
||||||
isolatedClient.sendEncodedCommand(encodedCommand, {
|
isolatedClient.sendCommand(args, {
|
||||||
...options,
|
...options,
|
||||||
isolated: false
|
isolated: false
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const promise = this.#queue.addEncodedCommand<T>(encodedCommand, options);
|
const promise = this.#queue.addCommand<T>(args, options, bufferMode);
|
||||||
this.#tick();
|
this.#tick();
|
||||||
return await promise;
|
return await promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#tick(): void {
|
||||||
|
if (!this.#socket.isSocketExists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.#socket.cork();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const args = this.#queue.getCommandToSend();
|
||||||
|
if (args === undefined) break;
|
||||||
|
|
||||||
|
let writeResult;
|
||||||
|
for (const toWrite of encodeCommand(args)) {
|
||||||
|
writeResult = this.#socket.write(toWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!writeResult) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
executeIsolated<T>(fn: (client: RedisClientType<M, S>) => T | Promise<T>): Promise<T> {
|
executeIsolated<T>(fn: (client: RedisClientType<M, S>) => T | Promise<T>): Promise<T> {
|
||||||
return this.#isolationPool.use(fn);
|
return this.#isolationPool.use(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeScript(script: RedisLuaScript, args: Array<string>, options?: ClientCommandOptions): Promise<ReturnType<typeof script['transformReply']>> {
|
async executeScript(script: RedisLuaScript, args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<ReturnType<typeof script['transformReply']>> {
|
||||||
try {
|
try {
|
||||||
return await this.#sendCommand([
|
return await this.#sendCommand([
|
||||||
'EVALSHA',
|
'EVALSHA',
|
||||||
script.SHA1,
|
script.SHA1,
|
||||||
script.NUMBER_OF_KEYS.toString(),
|
script.NUMBER_OF_KEYS.toString(),
|
||||||
...args
|
...args
|
||||||
], options);
|
], options, bufferMode);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
if (!err?.message?.startsWith?.('NOSCRIPT')) {
|
if (!err?.message?.startsWith?.('NOSCRIPT')) {
|
||||||
throw err;
|
throw err;
|
||||||
@@ -357,14 +368,14 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
script.SCRIPT,
|
script.SCRIPT,
|
||||||
script.NUMBER_OF_KEYS.toString(),
|
script.NUMBER_OF_KEYS.toString(),
|
||||||
...args
|
...args
|
||||||
], options);
|
], options, bufferMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#multiExecutor(commands: Array<MultiQueuedCommand>, chainId?: symbol): Promise<Array<RedisReply>> {
|
#multiExecutor(commands: Array<MultiQueuedCommand>, chainId?: symbol): Promise<Array<RedisReply>> {
|
||||||
const promise = Promise.all(
|
const promise = Promise.all(
|
||||||
commands.map(({encodedCommand}) => {
|
commands.map(({ args }) => {
|
||||||
return this.#queue.addEncodedCommand(encodedCommand, RedisClient.commandOptions({
|
return this.#queue.addCommand(args, RedisClient.commandOptions({
|
||||||
chainId
|
chainId
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
@@ -438,31 +449,6 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
await this.#isolationPool.drain();
|
await this.#isolationPool.drain();
|
||||||
await this.#isolationPool.clear();
|
await this.#isolationPool.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
#isTickQueued = false;
|
|
||||||
|
|
||||||
#tick(): void {
|
|
||||||
const {chunkRecommendedSize} = this.#socket;
|
|
||||||
if (!chunkRecommendedSize) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.#isTickQueued && this.#queue.waitingToBeSentCommandsLength < chunkRecommendedSize) {
|
|
||||||
queueMicrotask(() => this.#tick());
|
|
||||||
this.#isTickQueued = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isBuffering = this.#queue.executeChunk(chunkRecommendedSize);
|
|
||||||
if (isBuffering === true) {
|
|
||||||
this.#socket.once('drain', () => this.#tick());
|
|
||||||
} else if (isBuffering === false) {
|
|
||||||
this.#tick();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#isTickQueued = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extendWithDefaultCommands(RedisClient, RedisClient.commandsExecutor);
|
extendWithDefaultCommands(RedisClient, RedisClient.commandsExecutor);
|
||||||
|
@@ -172,7 +172,7 @@ export default class RedisClusterSlots<M extends RedisModules, S extends RedisLu
|
|||||||
return value.client;
|
return value.client;
|
||||||
}
|
}
|
||||||
|
|
||||||
getClient(firstKey?: string, isReadonly?: boolean): RedisClientType<M, S> {
|
getClient(firstKey?: string | Buffer, isReadonly?: boolean): RedisClientType<M, S> {
|
||||||
if (!firstKey) {
|
if (!firstKey) {
|
||||||
return this.#getRandomClient();
|
return this.#getRandomClient();
|
||||||
}
|
}
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { RedisCommand, RedisModules } from './commands';
|
import { RedisCommand, RedisModules, TransformArgumentsReply } from './commands';
|
||||||
import RedisClient, { ClientCommandOptions, RedisClientType, WithPlugins } from './client';
|
import RedisClient, { ClientCommandOptions, RedisClientType, WithPlugins } from './client';
|
||||||
import { RedisSocketOptions } from './socket';
|
import { RedisSocketOptions } from './socket';
|
||||||
import RedisClusterSlots, { ClusterNode } from './cluster-slots';
|
import RedisClusterSlots, { ClusterNode } from './cluster-slots';
|
||||||
@@ -6,6 +6,7 @@ import { RedisLuaScript, RedisLuaScripts } from './lua-script';
|
|||||||
import { extendWithModulesAndScripts, extendWithDefaultCommands, transformCommandArguments } from './commander';
|
import { extendWithModulesAndScripts, extendWithDefaultCommands, transformCommandArguments } from './commander';
|
||||||
import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command';
|
import RedisMultiCommand, { MultiQueuedCommand, RedisMultiCommandType } from './multi-command';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
|
import cluster from 'cluster';
|
||||||
|
|
||||||
export interface RedisClusterOptions<M = RedisModules, S = RedisLuaScripts> {
|
export interface RedisClusterOptions<M = RedisModules, S = RedisLuaScripts> {
|
||||||
rootNodes: Array<RedisSocketOptions>;
|
rootNodes: Array<RedisSocketOptions>;
|
||||||
@@ -19,7 +20,7 @@ export type RedisClusterType<M extends RedisModules, S extends RedisLuaScripts>
|
|||||||
WithPlugins<M, S> & RedisCluster;
|
WithPlugins<M, S> & RedisCluster;
|
||||||
|
|
||||||
export default class RedisCluster<M extends RedisModules = RedisModules, S extends RedisLuaScripts = RedisLuaScripts> extends EventEmitter {
|
export default class RedisCluster<M extends RedisModules = RedisModules, S extends RedisLuaScripts = RedisLuaScripts> extends EventEmitter {
|
||||||
static #extractFirstKey(command: RedisCommand, originalArgs: Array<unknown>, redisArgs: Array<string>): string | undefined {
|
static #extractFirstKey(command: RedisCommand, originalArgs: Array<unknown>, redisArgs: TransformArgumentsReply): string | Buffer | undefined {
|
||||||
if (command.FIRST_KEY_INDEX === undefined) {
|
if (command.FIRST_KEY_INDEX === undefined) {
|
||||||
return undefined;
|
return undefined;
|
||||||
} else if (typeof command.FIRST_KEY_INDEX === 'number') {
|
} else if (typeof command.FIRST_KEY_INDEX === 'number') {
|
||||||
@@ -41,7 +42,8 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
RedisCluster.#extractFirstKey(command, args, redisArgs),
|
RedisCluster.#extractFirstKey(command, args, redisArgs),
|
||||||
command.IS_READ_ONLY,
|
command.IS_READ_ONLY,
|
||||||
redisArgs,
|
redisArgs,
|
||||||
options
|
options,
|
||||||
|
command.BUFFER_MODE
|
||||||
),
|
),
|
||||||
redisArgs.preserve
|
redisArgs.preserve
|
||||||
);
|
);
|
||||||
@@ -100,22 +102,23 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
}
|
}
|
||||||
|
|
||||||
async sendCommand<C extends RedisCommand>(
|
async sendCommand<C extends RedisCommand>(
|
||||||
firstKey: string | undefined,
|
firstKey: string | Buffer | undefined,
|
||||||
isReadonly: boolean | undefined,
|
isReadonly: boolean | undefined,
|
||||||
args: Array<string>,
|
args: TransformArgumentsReply,
|
||||||
options?: ClientCommandOptions,
|
options?: ClientCommandOptions,
|
||||||
|
bufferMode?: boolean,
|
||||||
redirections = 0
|
redirections = 0
|
||||||
): Promise<ReturnType<C['transformReply']>> {
|
): Promise<ReturnType<C['transformReply']>> {
|
||||||
const client = this.#slots.getClient(firstKey, isReadonly);
|
const client = this.#slots.getClient(firstKey, isReadonly);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await client.sendCommand(args, options);
|
return await client.sendCommand(args, options, bufferMode);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const shouldRetry = await this.#handleCommandError(err, client, redirections);
|
const shouldRetry = await this.#handleCommandError(err, client, redirections);
|
||||||
if (shouldRetry === true) {
|
if (shouldRetry === true) {
|
||||||
return this.sendCommand(firstKey, isReadonly, args, options, redirections + 1);
|
return this.sendCommand(firstKey, isReadonly, args, options, bufferMode, redirections + 1);
|
||||||
} else if (shouldRetry) {
|
} else if (shouldRetry) {
|
||||||
return shouldRetry.sendCommand(args, options);
|
return shouldRetry.sendCommand(args, options, bufferMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
@@ -125,7 +128,7 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
async executeScript(
|
async executeScript(
|
||||||
script: RedisLuaScript,
|
script: RedisLuaScript,
|
||||||
originalArgs: Array<unknown>,
|
originalArgs: Array<unknown>,
|
||||||
redisArgs: Array<string>,
|
redisArgs: TransformArgumentsReply,
|
||||||
options?: ClientCommandOptions,
|
options?: ClientCommandOptions,
|
||||||
redirections = 0
|
redirections = 0
|
||||||
): Promise<ReturnType<typeof script['transformReply']>> {
|
): Promise<ReturnType<typeof script['transformReply']>> {
|
||||||
@@ -135,13 +138,13 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await client.executeScript(script, redisArgs, options);
|
return await client.executeScript(script, redisArgs, options, script.BUFFER_MODE);
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
const shouldRetry = await this.#handleCommandError(err, client, redirections);
|
const shouldRetry = await this.#handleCommandError(err, client, redirections);
|
||||||
if (shouldRetry === true) {
|
if (shouldRetry === true) {
|
||||||
return this.executeScript(script, originalArgs, redisArgs, options, redirections + 1);
|
return this.executeScript(script, originalArgs, redisArgs, options, redirections + 1);
|
||||||
} else if (shouldRetry) {
|
} else if (shouldRetry) {
|
||||||
return shouldRetry.executeScript(script, redisArgs, options);
|
return shouldRetry.executeScript(script, redisArgs, options, script.BUFFER_MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw err;
|
throw err;
|
||||||
@@ -181,8 +184,8 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
const client = this.#slots.getClient(routing);
|
const client = this.#slots.getClient(routing);
|
||||||
|
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
commands.map(({encodedCommand}) => {
|
commands.map(({ args }) => {
|
||||||
return client.sendEncodedCommand(encodedCommand, RedisClient.commandOptions({
|
return client.sendCommand(args, RedisClient.commandOptions({
|
||||||
chainId
|
chainId
|
||||||
}));
|
}));
|
||||||
})
|
})
|
||||||
|
@@ -2,27 +2,43 @@ import { strict as assert } from 'assert';
|
|||||||
import { describe } from 'mocha';
|
import { describe } from 'mocha';
|
||||||
import { encodeCommand } from './commander';
|
import { encodeCommand } from './commander';
|
||||||
|
|
||||||
|
function encodeCommandToString(...args: Parameters<typeof encodeCommand>): string {
|
||||||
|
const arr = [];
|
||||||
|
for (const item of encodeCommand(...args)) {
|
||||||
|
arr.push(item.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return arr.join('');
|
||||||
|
}
|
||||||
|
|
||||||
describe('Commander', () => {
|
describe('Commander', () => {
|
||||||
describe('encodeCommand (see #1628)', () => {
|
describe('encodeCommand (see #1628)', () => {
|
||||||
it('1 byte', () => {
|
it('1 byte', () => {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
encodeCommand(['a', 'z']),
|
encodeCommandToString(['a', 'z']),
|
||||||
'*2\r\n$1\r\na\r\n$1\r\nz\r\n'
|
'*2\r\n$1\r\na\r\n$1\r\nz\r\n'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('2 bytes', () => {
|
it('2 bytes', () => {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
encodeCommand(['א', 'ת']),
|
encodeCommandToString(['א', 'ת']),
|
||||||
'*2\r\n$2\r\nא\r\n$2\r\nת\r\n'
|
'*2\r\n$2\r\nא\r\n$2\r\nת\r\n'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('4 bytes', () => {
|
it('4 bytes', () => {
|
||||||
assert.equal(
|
assert.equal(
|
||||||
encodeCommand(['🐣', '🐤']),
|
encodeCommandToString(['🐣', '🐤']),
|
||||||
'*2\r\n$4\r\n🐣\r\n$4\r\n🐤\r\n'
|
'*2\r\n$4\r\n🐣\r\n$4\r\n🐤\r\n'
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('with a buffer', () => {
|
||||||
|
assert.equal(
|
||||||
|
encodeCommandToString([Buffer.from('string')]),
|
||||||
|
'*1\r\n$6\r\nstring\r\n'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
import COMMANDS, { RedisCommand, RedisModules, TransformArgumentsReply } from './commands';
|
import COMMANDS, { RedisCommand, RedisModules, TransformArgumentsReply } from './commands';
|
||||||
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
|
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
|
||||||
import { CommandOptions, isCommandOptions } from './command-options';
|
import { CommandOptions, isCommandOptions } from './command-options';
|
||||||
|
import { off } from 'process';
|
||||||
|
|
||||||
type Instantiable<T = any> = new(...args: Array<any>) => T;
|
type Instantiable<T = any> = new(...args: Array<any>) => T;
|
||||||
|
|
||||||
@@ -94,16 +95,15 @@ export function transformCommandArguments<T = unknown>(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function encodeCommand(args: Array<string>): string {
|
const DELIMITER = '\r\n';
|
||||||
const encoded = [
|
|
||||||
`*${args.length}`,
|
|
||||||
`$${Buffer.byteLength(args[0]).toString()}`,
|
|
||||||
args[0]
|
|
||||||
];
|
|
||||||
|
|
||||||
for (let i = 1; i < args.length; i++) {
|
export function* encodeCommand(args: TransformArgumentsReply): IterableIterator<string | Buffer> {
|
||||||
encoded.push(`$${Buffer.byteLength(args[i]).toString()}`, args[i]);
|
yield `*${args.length}${DELIMITER}`;
|
||||||
|
|
||||||
|
for (const arg of args) {
|
||||||
|
const byteLength = typeof arg === 'string' ? Buffer.byteLength(arg): arg.length;
|
||||||
|
yield `$${byteLength.toString()}${DELIMITER}`;
|
||||||
|
yield arg;
|
||||||
|
yield DELIMITER;
|
||||||
}
|
}
|
||||||
|
|
||||||
return encoded.join('\r\n') + '\r\n';
|
|
||||||
}
|
}
|
||||||
|
@@ -2,17 +2,15 @@ import LinkedList from 'yallist';
|
|||||||
import RedisParser from 'redis-parser';
|
import RedisParser from 'redis-parser';
|
||||||
import { AbortError } from './errors';
|
import { AbortError } from './errors';
|
||||||
import { RedisReply } from './commands';
|
import { RedisReply } from './commands';
|
||||||
import { encodeCommand } from './commander';
|
|
||||||
|
|
||||||
export interface QueueCommandOptions {
|
export interface QueueCommandOptions {
|
||||||
asap?: boolean;
|
asap?: boolean;
|
||||||
signal?: any; // TODO: `AbortSignal` type is incorrect
|
|
||||||
chainId?: symbol;
|
chainId?: symbol;
|
||||||
|
signal?: any; // TODO: `AbortSignal` type is incorrect
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CommandWaitingToBeSent extends CommandWaitingForReply {
|
interface CommandWaitingToBeSent extends CommandWaitingForReply {
|
||||||
encodedCommand: string;
|
args: Array<string | Buffer>;
|
||||||
byteLength: number;
|
|
||||||
chainId?: symbol;
|
chainId?: symbol;
|
||||||
abort?: {
|
abort?: {
|
||||||
signal: any; // TODO: `AbortSignal` type is incorrect
|
signal: any; // TODO: `AbortSignal` type is incorrect
|
||||||
@@ -24,10 +22,9 @@ interface CommandWaitingForReply {
|
|||||||
resolve(reply?: any): void;
|
resolve(reply?: any): void;
|
||||||
reject(err: Error): void;
|
reject(err: Error): void;
|
||||||
channelsCounter?: number;
|
channelsCounter?: number;
|
||||||
|
bufferMode?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandsQueueExecutor = (encodedCommands: string) => boolean | undefined;
|
|
||||||
|
|
||||||
export enum PubSubSubscribeCommands {
|
export enum PubSubSubscribeCommands {
|
||||||
SUBSCRIBE = 'SUBSCRIBE',
|
SUBSCRIBE = 'SUBSCRIBE',
|
||||||
PSUBSCRIBE = 'PSUBSCRIBE'
|
PSUBSCRIBE = 'PSUBSCRIBE'
|
||||||
@@ -57,16 +54,8 @@ export default class RedisCommandsQueue {
|
|||||||
|
|
||||||
readonly #maxLength: number | null | undefined;
|
readonly #maxLength: number | null | undefined;
|
||||||
|
|
||||||
readonly #executor: CommandsQueueExecutor;
|
|
||||||
|
|
||||||
readonly #waitingToBeSent = new LinkedList<CommandWaitingToBeSent>();
|
readonly #waitingToBeSent = new LinkedList<CommandWaitingToBeSent>();
|
||||||
|
|
||||||
#waitingToBeSentCommandsLength = 0;
|
|
||||||
|
|
||||||
get waitingToBeSentCommandsLength() {
|
|
||||||
return this.#waitingToBeSentCommandsLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
readonly #waitingForReply = new LinkedList<CommandWaitingForReply>();
|
readonly #waitingForReply = new LinkedList<CommandWaitingForReply>();
|
||||||
|
|
||||||
readonly #pubSubState = {
|
readonly #pubSubState = {
|
||||||
@@ -114,12 +103,11 @@ export default class RedisCommandsQueue {
|
|||||||
|
|
||||||
#chainInExecution: symbol | undefined;
|
#chainInExecution: symbol | undefined;
|
||||||
|
|
||||||
constructor(maxLength: number | null | undefined, executor: CommandsQueueExecutor) {
|
constructor(maxLength: number | null | undefined) {
|
||||||
this.#maxLength = maxLength;
|
this.#maxLength = maxLength;
|
||||||
this.#executor = executor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addEncodedCommand<T = RedisReply>(encodedCommand: string, options?: QueueCommandOptions): Promise<T> {
|
addCommand<T = RedisReply>(args: Array<string | Buffer>, options?: QueueCommandOptions, bufferMode?: boolean): Promise<T> {
|
||||||
if (this.#pubSubState.subscribing || this.#pubSubState.subscribed) {
|
if (this.#pubSubState.subscribing || this.#pubSubState.subscribed) {
|
||||||
return Promise.reject(new Error('Cannot send commands in PubSub mode'));
|
return Promise.reject(new Error('Cannot send commands in PubSub mode'));
|
||||||
} else if (this.#maxLength && this.#waitingToBeSent.length + this.#waitingForReply.length >= this.#maxLength) {
|
} else if (this.#maxLength && this.#waitingToBeSent.length + this.#waitingForReply.length >= this.#maxLength) {
|
||||||
@@ -130,11 +118,11 @@ export default class RedisCommandsQueue {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const node = new LinkedList.Node<CommandWaitingToBeSent>({
|
const node = new LinkedList.Node<CommandWaitingToBeSent>({
|
||||||
encodedCommand,
|
args,
|
||||||
byteLength: Buffer.byteLength(encodedCommand),
|
|
||||||
chainId: options?.chainId,
|
chainId: options?.chainId,
|
||||||
|
bufferMode,
|
||||||
resolve,
|
resolve,
|
||||||
reject
|
reject,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (options?.signal) {
|
if (options?.signal) {
|
||||||
@@ -157,8 +145,6 @@ export default class RedisCommandsQueue {
|
|||||||
} else {
|
} else {
|
||||||
this.#waitingToBeSent.pushNode(node);
|
this.#waitingToBeSent.pushNode(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#waitingToBeSentCommandsLength += node.value.byteLength;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,11 +219,8 @@ export default class RedisCommandsQueue {
|
|||||||
|
|
||||||
this.#pubSubState[inProgressKey] += channelsCounter;
|
this.#pubSubState[inProgressKey] += channelsCounter;
|
||||||
|
|
||||||
const encodedCommand = encodeCommand(commandArgs),
|
|
||||||
byteLength = Buffer.byteLength(encodedCommand);
|
|
||||||
this.#waitingToBeSent.push({
|
this.#waitingToBeSent.push({
|
||||||
encodedCommand,
|
args: commandArgs,
|
||||||
byteLength,
|
|
||||||
channelsCounter,
|
channelsCounter,
|
||||||
resolve: () => {
|
resolve: () => {
|
||||||
this.#pubSubState[inProgressKey] -= channelsCounter;
|
this.#pubSubState[inProgressKey] -= channelsCounter;
|
||||||
@@ -249,7 +232,6 @@ export default class RedisCommandsQueue {
|
|||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.#waitingToBeSentCommandsLength += byteLength;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -267,47 +249,25 @@ export default class RedisCommandsQueue {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
executeChunk(recommendedSize: number): boolean | undefined {
|
getCommandToSend(): Array<string | Buffer> | undefined {
|
||||||
if (!this.#waitingToBeSent.length) return;
|
const toSend = this.#waitingToBeSent.shift();
|
||||||
|
|
||||||
const encoded: Array<string> = [];
|
|
||||||
let size = 0,
|
|
||||||
lastCommandChainId: symbol | undefined;
|
|
||||||
for (const command of this.#waitingToBeSent) {
|
|
||||||
encoded.push(command.encodedCommand);
|
|
||||||
size += command.byteLength;
|
|
||||||
if (size > recommendedSize) {
|
|
||||||
lastCommandChainId = command.chainId;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lastCommandChainId && encoded.length === this.#waitingToBeSent.length) {
|
|
||||||
lastCommandChainId = this.#waitingToBeSent.tail!.value.chainId;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastCommandChainId ??= this.#waitingToBeSent.tail?.value.chainId;
|
|
||||||
|
|
||||||
this.#executor(encoded.join(''));
|
|
||||||
|
|
||||||
for (let i = 0; i < encoded.length; i++) {
|
|
||||||
const waitingToBeSent = this.#waitingToBeSent.shift()!;
|
|
||||||
if (waitingToBeSent.abort) {
|
|
||||||
waitingToBeSent.abort.signal.removeEventListener('abort', waitingToBeSent.abort.listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (toSend) {
|
||||||
this.#waitingForReply.push({
|
this.#waitingForReply.push({
|
||||||
resolve: waitingToBeSent.resolve,
|
resolve: toSend.resolve,
|
||||||
reject: waitingToBeSent.reject,
|
reject: toSend.reject,
|
||||||
channelsCounter: waitingToBeSent.channelsCounter
|
channelsCounter: toSend.channelsCounter,
|
||||||
|
bufferMode: toSend.bufferMode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.#chainInExecution = lastCommandChainId;
|
this.#chainInExecution = toSend?.chainId;
|
||||||
this.#waitingToBeSentCommandsLength -= size;
|
|
||||||
|
return toSend?.args;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseResponse(data: Buffer): void {
|
parseResponse(data: Buffer): void {
|
||||||
|
this.#parser.setReturnBuffers(!!this.#waitingForReply.head?.value.bufferMode);
|
||||||
this.#parser.execute(data);
|
this.#parser.execute(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export function transformArguments(username: string | Array<string>): Array<string> {
|
export function transformArguments(username: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['ACL', 'DELUSER'], username);
|
return pushVerdictArguments(['ACL', 'DELUSER'], username);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
|
||||||
|
|
||||||
export function transformArguments(username: string, rule: string | Array<string>): Array<string> {
|
export function transformArguments(username: string, rule: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['ACL', 'SETUSER', username], rule);
|
return pushVerdictArguments(['ACL', 'SETUSER', username], rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 2;
|
export const FIRST_KEY_INDEX = 2;
|
||||||
|
|
||||||
type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT';
|
type BitOperations = 'AND' | 'OR' | 'XOR' | 'NOT';
|
||||||
|
|
||||||
export function transformArguments(operation: BitOperations, destKey: string, key: string | Array<string>): Array<string> {
|
export function transformArguments(operation: BitOperations, destKey: string, key: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['BITOP', operation, destKey], key);
|
return pushVerdictArguments(['BITOP', operation, destKey], key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments } from './generic-transformers';
|
import { pushVerdictArguments } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(keys: string | Array<string>, timeout: number): Array<string> {
|
export function transformArguments(keys: string | Buffer | Array<string | Buffer>, timeout: number): TransformArgumentsReply {
|
||||||
const args = pushVerdictArguments(['BLPOP'], keys);
|
const args = pushVerdictArguments(['BLPOP'], keys);
|
||||||
|
|
||||||
args.push(timeout.toString());
|
args.push(timeout.toString());
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments } from './generic-transformers';
|
import { pushVerdictArguments } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string | Array<string>, timeout: number): Array<string> {
|
export function transformArguments(key: string | Array<string>, timeout: number): TransformArgumentsReply {
|
||||||
const args = pushVerdictArguments(['BRPOP'], key);
|
const args = pushVerdictArguments(['BRPOP'], key);
|
||||||
|
|
||||||
args.push(timeout.toString());
|
args.push(timeout.toString());
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string | Array<string>, timeout: number): Array<string> {
|
export function transformArguments(key: string | Array<string>, timeout: number): TransformArgumentsReply {
|
||||||
const args = pushVerdictArguments(['BZPOPMAX'], key);
|
const args = pushVerdictArguments(['BZPOPMAX'], key);
|
||||||
|
|
||||||
args.push(timeout.toString());
|
args.push(timeout.toString());
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumberInfinity, ZMember } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string | Array<string>, timeout: number): Array<string> {
|
export function transformArguments(key: string | Array<string>, timeout: number): TransformArgumentsReply {
|
||||||
const args = pushVerdictArguments(['BZPOPMIN'], key);
|
const args = pushVerdictArguments(['BZPOPMIN'], key);
|
||||||
|
|
||||||
args.push(timeout.toString());
|
args.push(timeout.toString());
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export function transformArguments(keys: string | Array<string>): Array<string> {
|
export function transformArguments(keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['DEL'], keys);
|
return pushVerdictArguments(['DEL'], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(keys: string | Array<string>): Array<string> {
|
export function transformArguments(keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['EXISTS'], keys);
|
return pushVerdictArguments(['EXISTS'], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(key: string, member: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, member: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['GEOHASH', key], member);
|
return pushVerdictArguments(['GEOHASH', key], member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments } from './generic-transformers';
|
import { pushVerdictArguments } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(key: string, member: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, member: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['GEOPOS', key], member);
|
return pushVerdictArguments(['GEOPOS', key], member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { transformReplyString } from './generic-transformers';
|
import { transformReplyString } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(key: string): Array<string> {
|
export function transformArguments(key: string | Buffer): TransformArgumentsReply {
|
||||||
return ['GET', key];
|
return ['GET', key];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
lib/commands/GET_BUFFER.spec.ts
Normal file
22
lib/commands/GET_BUFFER.spec.ts
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { strict as assert } from 'assert';
|
||||||
|
import { TestRedisServers, itWithClient, TestRedisClusters, itWithCluster } from '../test-utils';
|
||||||
|
|
||||||
|
describe('GET_BUFFER', () => {
|
||||||
|
itWithClient(TestRedisServers.OPEN, 'client.getBuffer', async client => {
|
||||||
|
const buffer = Buffer.from('string');
|
||||||
|
await client.set('key', buffer);
|
||||||
|
assert.deepEqual(
|
||||||
|
buffer,
|
||||||
|
await client.getBuffer('key')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
itWithCluster(TestRedisClusters.OPEN, 'cluster.getBuffer', async cluster => {
|
||||||
|
const buffer = Buffer.from('string');
|
||||||
|
await cluster.set('key', buffer);
|
||||||
|
assert.deepEqual(
|
||||||
|
buffer,
|
||||||
|
await cluster.getBuffer('key')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
7
lib/commands/GET_BUFFER.ts
Normal file
7
lib/commands/GET_BUFFER.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { transformReplyBuffer } from './generic-transformers';
|
||||||
|
|
||||||
|
export { FIRST_KEY_INDEX, IS_READ_ONLY, transformArguments } from './GET';
|
||||||
|
|
||||||
|
export const BUFFER_MODE = true;
|
||||||
|
|
||||||
|
export const transformReply = transformReplyBuffer;
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, field: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, field: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['HDEL', key], field);
|
return pushVerdictArguments(['HDEL', key], field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(key: string, fields: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, fields: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['HMGET', key], fields);
|
return pushVerdictArguments(['HMGET', key], fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, elements: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, elements: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['LPUSH', key], elements);}
|
return pushVerdictArguments(['LPUSH', key], elements);}
|
||||||
|
|
||||||
export const transformReply = transformReplyNumber;
|
export const transformReply = transformReplyNumber;
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, element: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, element: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['LPUSHX', key], element);
|
return pushVerdictArguments(['LPUSHX', key], element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyBoolean } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, element: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, element: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['PFADD', key], element);
|
return pushVerdictArguments(['PFADD', key], element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string | Array<string>): Array<string> {
|
export function transformArguments(key: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['PFCOUNT'], key);
|
return pushVerdictArguments(['PFCOUNT'], key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(destination: string, source: string | Array<string>): Array<string> {
|
export function transformArguments(destination: string, source: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['PFMERGE', destination], source);
|
return pushVerdictArguments(['PFMERGE', destination], source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, element: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, element: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['RPUSH', key], element);
|
return pushVerdictArguments(['RPUSH', key], element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, element: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, element: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['RPUSHX', key], element);
|
return pushVerdictArguments(['RPUSHX', key], element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, members: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, members: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SADD', key], members);
|
return pushVerdictArguments(['SADD', key], members);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyBooleanArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyBooleanArray } from './generic-transformers';
|
||||||
|
|
||||||
export function transformArguments(sha1: string | Array<string>): Array<string> {
|
export function transformArguments(sha1: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SCRIPT', 'EXISTS'], sha1);
|
return pushVerdictArguments(['SCRIPT', 'EXISTS'], sha1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(keys: string | Array<string>): Array<string> {
|
export function transformArguments(keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SDIFF'], keys);
|
return pushVerdictArguments(['SDIFF'], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(destination: string, keys: string | Array<string>): Array<string> {
|
export function transformArguments(destination: string, keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SDIFFSTORE', destination], keys);
|
return pushVerdictArguments(['SDIFFSTORE', destination], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
interface EX {
|
interface EX {
|
||||||
@@ -38,7 +40,7 @@ interface SetCommonOptions {
|
|||||||
|
|
||||||
type SetOptions = SetTTL & SetGuards & (SetCommonOptions | {});
|
type SetOptions = SetTTL & SetGuards & (SetCommonOptions | {});
|
||||||
|
|
||||||
export function transformArguments(key: string, value: string, options?: SetOptions): Array<string> {
|
export function transformArguments(key: string | Buffer, value: string | Buffer, options?: SetOptions): TransformArgumentsReply {
|
||||||
const args = ['SET', key, value];
|
const args = ['SET', key, value];
|
||||||
|
|
||||||
if (!options) {
|
if (!options) {
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { transformReplyString } from './generic-transformers';
|
import { transformReplyString } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, seconds: number, value: string): Array<string> {
|
export function transformArguments(key: string | Buffer, seconds: number, value: string): TransformArgumentsReply {
|
||||||
return [
|
return [
|
||||||
'SETEX',
|
'SETEX',
|
||||||
key,
|
key,
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(keys: string | Array<string>): Array<string> {
|
export function transformArguments(keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SINTER'], keys);
|
return pushVerdictArguments(['SINTER'], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(destination: string, keys: string | Array<string>): Array<string> {
|
export function transformArguments(destination: string, keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SINTERSTORE', destination], keys);
|
return pushVerdictArguments(['SINTERSTORE', destination], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, members: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, members: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SREM', key], members);
|
return pushVerdictArguments(['SREM', key], members);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(keys: string | Array<string>): Array<string> {
|
export function transformArguments(keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SUNION'], keys);
|
return pushVerdictArguments(['SUNION'], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(destination: string, keys: string | Array<string>): Array<string> {
|
export function transformArguments(destination: string, keys: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['SUNIONSTORE', destination], keys);
|
return pushVerdictArguments(['SUNIONSTORE', destination], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string | Array<string>): Array<string> {
|
export function transformArguments(key: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['TOUCH'], key);
|
return pushVerdictArguments(['TOUCH'], key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string | Array<string>): Array<string> {
|
export function transformArguments(key: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['UNLINK'], key);
|
return pushVerdictArguments(['UNLINK'], key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyString } from './generic-transformers';
|
||||||
|
|
||||||
export function transformArguments(key: string | Array<string>): Array<string> {
|
export function transformArguments(key: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['WATCH'], key);
|
return pushVerdictArguments(['WATCH'], key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, group: string, id: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, group: string, id: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['XACK', key, group], id);
|
return pushVerdictArguments(['XACK', key, group], id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, id: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, id: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['XDEL', key], id);
|
return pushVerdictArguments(['XDEL', key], id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 2;
|
export const FIRST_KEY_INDEX = 2;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(keys: Array<string> | string): Array<string> {
|
export function transformArguments(keys: Array<string> | string): TransformArgumentsReply {
|
||||||
return pushVerdictArgument(['ZDIFF'], keys);
|
return pushVerdictArgument(['ZDIFF'], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(destination: string, keys: Array<string> | string): Array<string> {
|
export function transformArguments(destination: string, keys: Array<string> | string): TransformArgumentsReply {
|
||||||
return pushVerdictArgument(['ZDIFFSTORE', destination], keys);
|
return pushVerdictArgument(['ZDIFFSTORE', destination], keys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { transformReplySortedSetWithScores } from './generic-transformers';
|
import { transformReplySortedSetWithScores } from './generic-transformers';
|
||||||
import { transformArguments as transformZDiffArguments } from './ZDIFF';
|
import { transformArguments as transformZDiffArguments } from './ZDIFF';
|
||||||
|
|
||||||
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZDIFF';
|
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZDIFF';
|
||||||
|
|
||||||
export function transformArguments(...args: Parameters<typeof transformZDiffArguments>): Array<string> {
|
export function transformArguments(...args: Parameters<typeof transformZDiffArguments>): TransformArgumentsReply {
|
||||||
return [
|
return [
|
||||||
...transformZDiffArguments(...args),
|
...transformZDiffArguments(...args),
|
||||||
'WITHSCORES'
|
'WITHSCORES'
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 2;
|
export const FIRST_KEY_INDEX = 2;
|
||||||
@@ -9,7 +10,7 @@ interface ZInterOptions {
|
|||||||
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformArguments(keys: Array<string> | string, options?: ZInterOptions): Array<string> {
|
export function transformArguments(keys: Array<string> | string, options?: ZInterOptions): TransformArgumentsReply {
|
||||||
const args = pushVerdictArgument(['ZINTER'], keys);
|
const args = pushVerdictArgument(['ZINTER'], keys);
|
||||||
|
|
||||||
if (options?.WEIGHTS) {
|
if (options?.WEIGHTS) {
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
@@ -7,7 +8,7 @@ interface ZInterStoreOptions {
|
|||||||
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformArguments(destination: string, keys: Array<string> | string, options?: ZInterStoreOptions): Array<string> {
|
export function transformArguments(destination: string, keys: Array<string> | string, options?: ZInterStoreOptions): TransformArgumentsReply {
|
||||||
const args = pushVerdictArgument(['ZINTERSTORE', destination], keys);
|
const args = pushVerdictArgument(['ZINTERSTORE', destination], keys);
|
||||||
|
|
||||||
if (options?.WEIGHTS) {
|
if (options?.WEIGHTS) {
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { transformReplySortedSetWithScores } from './generic-transformers';
|
import { transformReplySortedSetWithScores } from './generic-transformers';
|
||||||
import { transformArguments as transformZInterArguments } from './ZINTER';
|
import { transformArguments as transformZInterArguments } from './ZINTER';
|
||||||
|
|
||||||
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZINTER';
|
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZINTER';
|
||||||
|
|
||||||
export function transformArguments(...args: Parameters<typeof transformZInterArguments>): Array<string> {
|
export function transformArguments(...args: Parameters<typeof transformZInterArguments>): TransformArgumentsReply {
|
||||||
return [
|
return [
|
||||||
...transformZInterArguments(...args),
|
...transformZInterArguments(...args),
|
||||||
'WITHSCORES'
|
'WITHSCORES'
|
||||||
|
@@ -1,10 +1,11 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumberInfinityNullArray } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumberInfinityNullArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export const IS_READ_ONLY = true;
|
export const IS_READ_ONLY = true;
|
||||||
|
|
||||||
export function transformArguments(key: string, member: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, member: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['ZMSCORE', key], member);
|
return pushVerdictArguments(['ZMSCORE', key], member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArguments, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
|
|
||||||
export function transformArguments(key: string, member: string | Array<string>): Array<string> {
|
export function transformArguments(key: string, member: string | Array<string>): TransformArgumentsReply {
|
||||||
return pushVerdictArguments(['ZREM', key], member);
|
return pushVerdictArguments(['ZREM', key], member);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
|
import { pushVerdictArgument, transformReplyStringArray } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 2;
|
export const FIRST_KEY_INDEX = 2;
|
||||||
@@ -9,7 +10,7 @@ interface ZUnionOptions {
|
|||||||
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformArguments(keys: Array<string> | string, options?: ZUnionOptions): Array<string> {
|
export function transformArguments(keys: Array<string> | string, options?: ZUnionOptions): TransformArgumentsReply {
|
||||||
const args = pushVerdictArgument(['ZUNION'], keys);
|
const args = pushVerdictArgument(['ZUNION'], keys);
|
||||||
|
|
||||||
if (options?.WEIGHTS) {
|
if (options?.WEIGHTS) {
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
|
import { pushVerdictArgument, transformReplyNumber } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
@@ -7,7 +8,7 @@ interface ZUnionOptions {
|
|||||||
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
AGGREGATE?: 'SUM' | 'MIN' | 'MAX';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function transformArguments(destination: string, keys: Array<string> | string, options?: ZUnionOptions): Array<string> {
|
export function transformArguments(destination: string, keys: Array<string> | string, options?: ZUnionOptions): TransformArgumentsReply {
|
||||||
const args = pushVerdictArgument(['ZUNIONSTORE', destination], keys);
|
const args = pushVerdictArgument(['ZUNIONSTORE', destination], keys);
|
||||||
|
|
||||||
if (options?.WEIGHTS) {
|
if (options?.WEIGHTS) {
|
||||||
|
@@ -1,9 +1,10 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { transformReplySortedSetWithScores } from './generic-transformers';
|
import { transformReplySortedSetWithScores } from './generic-transformers';
|
||||||
import { transformArguments as transformZUnionArguments } from './ZUNION';
|
import { transformArguments as transformZUnionArguments } from './ZUNION';
|
||||||
|
|
||||||
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZUNION';
|
export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZUNION';
|
||||||
|
|
||||||
export function transformArguments(...args: Parameters<typeof transformZUnionArguments>): Array<string> {
|
export function transformArguments(...args: Parameters<typeof transformZUnionArguments>): TransformArgumentsReply {
|
||||||
return [
|
return [
|
||||||
...transformZUnionArguments(...args),
|
...transformZUnionArguments(...args),
|
||||||
'WITHSCORES'
|
'WITHSCORES'
|
||||||
|
@@ -20,6 +20,10 @@ export function transformReplyString(reply: string): string {
|
|||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function transformReplyBuffer(reply: Buffer): Buffer {
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
export function transformReplyStringNull(reply: string | null): string | null {
|
export function transformReplyStringNull(reply: string | null): string | null {
|
||||||
return reply;
|
return reply;
|
||||||
}
|
}
|
||||||
@@ -352,11 +356,11 @@ export function pushStringTuplesArguments(args: Array<string>, tuples: StringTup
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pushVerdictArguments(args: TransformArgumentsReply, value: string | Array<string>): TransformArgumentsReply {
|
export function pushVerdictArguments(args: TransformArgumentsReply, value: string | Buffer | Array<string | Buffer>): TransformArgumentsReply {
|
||||||
if (typeof value === 'string') {
|
if (Array.isArray(value)) {
|
||||||
args.push(value);
|
|
||||||
} else {
|
|
||||||
args.push(...value);
|
args.push(...value);
|
||||||
|
} else {
|
||||||
|
args.push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return args;
|
return args;
|
||||||
|
@@ -61,6 +61,7 @@ import * as GEOPOS from './GEOPOS';
|
|||||||
import * as GEOSEARCH_WITH from './GEOSEARCH_WITH';
|
import * as GEOSEARCH_WITH from './GEOSEARCH_WITH';
|
||||||
import * as GEOSEARCH from './GEOSEARCH';
|
import * as GEOSEARCH from './GEOSEARCH';
|
||||||
import * as GEOSEARCHSTORE from './GEOSEARCHSTORE';
|
import * as GEOSEARCHSTORE from './GEOSEARCHSTORE';
|
||||||
|
import * as GET_BUFFER from './GET_BUFFER';
|
||||||
import * as GET from './GET';
|
import * as GET from './GET';
|
||||||
import * as GETBIT from './GETBIT';
|
import * as GETBIT from './GETBIT';
|
||||||
import * as GETDEL from './GETDEL';
|
import * as GETDEL from './GETDEL';
|
||||||
@@ -370,6 +371,8 @@ export default {
|
|||||||
geoSearch: GEOSEARCH,
|
geoSearch: GEOSEARCH,
|
||||||
GEOSEARCHSTORE,
|
GEOSEARCHSTORE,
|
||||||
geoSearchStore: GEOSEARCHSTORE,
|
geoSearchStore: GEOSEARCHSTORE,
|
||||||
|
GET_BUFFER,
|
||||||
|
getBuffer: GET_BUFFER,
|
||||||
GET,
|
GET,
|
||||||
get: GET,
|
get: GET,
|
||||||
GETBIT,
|
GETBIT,
|
||||||
@@ -733,15 +736,16 @@ export default {
|
|||||||
zUnionStore: ZUNIONSTORE
|
zUnionStore: ZUNIONSTORE
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RedisReply = string | number | Array<RedisReply> | null | undefined;
|
export type RedisReply = string | number | Buffer | Array<RedisReply> | null | undefined;
|
||||||
|
|
||||||
export type TransformArgumentsReply = Array<string> & { preserve?: unknown };
|
export type TransformArgumentsReply = Array<string | Buffer> & { preserve?: unknown };
|
||||||
|
|
||||||
export interface RedisCommand {
|
export interface RedisCommand {
|
||||||
FIRST_KEY_INDEX?: number | ((...args: Array<any>) => string);
|
FIRST_KEY_INDEX?: number | ((...args: Array<any>) => string);
|
||||||
IS_READ_ONLY?: boolean;
|
IS_READ_ONLY?: boolean;
|
||||||
transformArguments(...args: Array<any>): TransformArgumentsReply;
|
transformArguments(...args: Array<any>): TransformArgumentsReply;
|
||||||
transformReply(reply: RedisReply, preserved: unknown): any;
|
BUFFER_MODE?: boolean;
|
||||||
|
transformReply(reply: RedisReply, preserved?: unknown): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RedisCommands {
|
export interface RedisCommands {
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { strict as assert } from 'assert';
|
import { strict as assert } from 'assert';
|
||||||
import RedisMultiCommand from './multi-command';
|
import RedisMultiCommand from './multi-command';
|
||||||
import { encodeCommand } from './commander';
|
|
||||||
import { WatchError } from './errors';
|
import { WatchError } from './errors';
|
||||||
import { spy } from 'sinon';
|
import { spy } from 'sinon';
|
||||||
import { SQUARE_SCRIPT } from './client.spec';
|
import { SQUARE_SCRIPT } from './client.spec';
|
||||||
@@ -10,11 +9,11 @@ describe('Multi Command', () => {
|
|||||||
it('simple', async () => {
|
it('simple', async () => {
|
||||||
const multi = RedisMultiCommand.create((queue, symbol) => {
|
const multi = RedisMultiCommand.create((queue, symbol) => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
queue.map(({encodedCommand}) => encodedCommand),
|
queue.map(({ args }) => args),
|
||||||
[
|
[
|
||||||
encodeCommand(['MULTI']),
|
['MULTI'],
|
||||||
encodeCommand(['PING']),
|
['PING'],
|
||||||
encodeCommand(['EXEC']),
|
['EXEC'],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -55,8 +54,8 @@ describe('Multi Command', () => {
|
|||||||
it('execAsPipeline', async () => {
|
it('execAsPipeline', async () => {
|
||||||
const multi = RedisMultiCommand.create(queue => {
|
const multi = RedisMultiCommand.create(queue => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
queue.map(({encodedCommand}) => encodedCommand),
|
queue.map(({ args }) => args),
|
||||||
[encodeCommand(['PING'])]
|
[['PING']]
|
||||||
);
|
);
|
||||||
|
|
||||||
return Promise.resolve(['PONG']);
|
return Promise.resolve(['PONG']);
|
||||||
@@ -75,8 +74,8 @@ describe('Multi Command', () => {
|
|||||||
it('simple', async () => {
|
it('simple', async () => {
|
||||||
const multi = RedisMultiCommand.create(queue => {
|
const multi = RedisMultiCommand.create(queue => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
queue.map(({encodedCommand}) => encodedCommand),
|
queue.map(({ args }) => args),
|
||||||
[encodeCommand(['PING'])]
|
[['PING']]
|
||||||
);
|
);
|
||||||
|
|
||||||
return Promise.resolve(['PONG']);
|
return Promise.resolve(['PONG']);
|
||||||
@@ -111,10 +110,10 @@ describe('Multi Command', () => {
|
|||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
await new MultiWithScript(queue => {
|
await new MultiWithScript(queue => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
queue.map(({encodedCommand}) => encodedCommand),
|
queue.map(({ args }) => args),
|
||||||
[
|
[
|
||||||
encodeCommand(['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '2']),
|
['EVAL', SQUARE_SCRIPT.SCRIPT, '0', '2'],
|
||||||
encodeCommand(['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '3']),
|
['EVALSHA', SQUARE_SCRIPT.SHA1, '0', '3'],
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@@ -2,7 +2,7 @@ import COMMANDS, { TransformArgumentsReply } from './commands';
|
|||||||
import { RedisCommand, RedisModules, RedisReply } from './commands';
|
import { RedisCommand, RedisModules, RedisReply } from './commands';
|
||||||
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
|
import { RedisLuaScript, RedisLuaScripts } from './lua-script';
|
||||||
import { RedisClientOptions } from './client';
|
import { RedisClientOptions } from './client';
|
||||||
import { extendWithModulesAndScripts, extendWithDefaultCommands, encodeCommand } from './commander';
|
import { extendWithModulesAndScripts, extendWithDefaultCommands } from './commander';
|
||||||
import { WatchError } from './errors';
|
import { WatchError } from './errors';
|
||||||
|
|
||||||
type RedisMultiCommandSignature<C extends RedisCommand, M extends RedisModules, S extends RedisLuaScripts> = (...args: Parameters<C['transformArguments']>) => RedisMultiCommandType<M, S>;
|
type RedisMultiCommandSignature<C extends RedisCommand, M extends RedisModules, S extends RedisLuaScripts> = (...args: Parameters<C['transformArguments']>) => RedisMultiCommandType<M, S>;
|
||||||
@@ -24,7 +24,7 @@ type WithScripts<M extends RedisModules, S extends RedisLuaScripts> = {
|
|||||||
export type RedisMultiCommandType<M extends RedisModules, S extends RedisLuaScripts> = RedisMultiCommand & WithCommands<M, S> & WithModules<M, S> & WithScripts<M, S>;
|
export type RedisMultiCommandType<M extends RedisModules, S extends RedisLuaScripts> = RedisMultiCommand & WithCommands<M, S> & WithModules<M, S> & WithScripts<M, S>;
|
||||||
|
|
||||||
export interface MultiQueuedCommand {
|
export interface MultiQueuedCommand {
|
||||||
encodedCommand: string;
|
args: TransformArgumentsReply;
|
||||||
preservedArguments?: unknown;
|
preservedArguments?: unknown;
|
||||||
transformReply?: RedisCommand['transformReply'];
|
transformReply?: RedisCommand['transformReply'];
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,9 @@ export default class RedisMultiCommand<M extends RedisModules = RedisModules, S
|
|||||||
|
|
||||||
const scriptArguments = script.transformArguments(...args);
|
const scriptArguments = script.transformArguments(...args);
|
||||||
transformedArguments.push(...scriptArguments);
|
transformedArguments.push(...scriptArguments);
|
||||||
|
if (scriptArguments.preserve) {
|
||||||
transformedArguments.preserve = scriptArguments.preserve;
|
transformedArguments.preserve = scriptArguments.preserve;
|
||||||
|
}
|
||||||
|
|
||||||
return this.addCommand(
|
return this.addCommand(
|
||||||
transformedArguments,
|
transformedArguments,
|
||||||
@@ -119,7 +121,7 @@ export default class RedisMultiCommand<M extends RedisModules = RedisModules, S
|
|||||||
this.#v4.addCommand = this.addCommand.bind(this);
|
this.#v4.addCommand = this.addCommand.bind(this);
|
||||||
(this as any).addCommand = (...args: Array<unknown>): this => {
|
(this as any).addCommand = (...args: Array<unknown>): this => {
|
||||||
this.#queue.push({
|
this.#queue.push({
|
||||||
encodedCommand: encodeCommand(args.flat() as Array<string>)
|
args: args.flat() as Array<string>
|
||||||
});
|
});
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@@ -153,7 +155,7 @@ export default class RedisMultiCommand<M extends RedisModules = RedisModules, S
|
|||||||
|
|
||||||
addCommand(args: TransformArgumentsReply, transformReply?: RedisCommand['transformReply']): this {
|
addCommand(args: TransformArgumentsReply, transformReply?: RedisCommand['transformReply']): this {
|
||||||
this.#queue.push({
|
this.#queue.push({
|
||||||
encodedCommand: encodeCommand(args),
|
args,
|
||||||
preservedArguments: args.preserve,
|
preservedArguments: args.preserve,
|
||||||
transformReply
|
transformReply
|
||||||
});
|
});
|
||||||
@@ -170,13 +172,9 @@ export default class RedisMultiCommand<M extends RedisModules = RedisModules, S
|
|||||||
|
|
||||||
const queue = this.#queue.splice(0),
|
const queue = this.#queue.splice(0),
|
||||||
rawReplies = await this.#executor([
|
rawReplies = await this.#executor([
|
||||||
{
|
{ args: ['MULTI'] },
|
||||||
encodedCommand: encodeCommand(['MULTI'])
|
|
||||||
},
|
|
||||||
...queue,
|
...queue,
|
||||||
{
|
{ args: ['EXEC'] }
|
||||||
encodedCommand: encodeCommand(['EXEC'])
|
|
||||||
}
|
|
||||||
], Symbol('[RedisMultiCommand] Chain ID')),
|
], Symbol('[RedisMultiCommand] Chain ID')),
|
||||||
execReply = rawReplies[rawReplies.length - 1] as (null | Array<RedisReply>);
|
execReply = rawReplies[rawReplies.length - 1] as (null | Array<RedisReply>);
|
||||||
|
|
||||||
|
@@ -91,10 +91,8 @@ export default class RedisSocket extends EventEmitter {
|
|||||||
return this.#isOpen;
|
return this.#isOpen;
|
||||||
}
|
}
|
||||||
|
|
||||||
get chunkRecommendedSize(): number {
|
get isSocketExists(): boolean {
|
||||||
if (!this.#socket) return 0;
|
return !!this.#socket;
|
||||||
|
|
||||||
return this.#socket.writableHighWaterMark - this.#socket.writableLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(initiator?: RedisSocketInitiator, options?: RedisSocketOptions) {
|
constructor(initiator?: RedisSocketInitiator, options?: RedisSocketOptions) {
|
||||||
@@ -214,12 +212,12 @@ export default class RedisSocket extends EventEmitter {
|
|||||||
.catch(err => this.emit('error', err));
|
.catch(err => this.emit('error', err));
|
||||||
}
|
}
|
||||||
|
|
||||||
write(encodedCommands: string): boolean {
|
write(toWrite: string | Buffer): boolean {
|
||||||
if (!this.#socket) {
|
if (!this.#socket) {
|
||||||
throw new ClientClosedError();
|
throw new ClientClosedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.#socket.write(encodedCommands);
|
return this.#socket.write(toWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
async disconnect(ignoreIsOpen = false): Promise<void> {
|
async disconnect(ignoreIsOpen = false): Promise<void> {
|
||||||
@@ -251,4 +249,22 @@ export default class RedisSocket extends EventEmitter {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#isCorked = false;
|
||||||
|
|
||||||
|
cork(): void {
|
||||||
|
if (!this.#socket) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.#isCorked) {
|
||||||
|
this.#socket.cork();
|
||||||
|
this.#isCorked = true;
|
||||||
|
|
||||||
|
queueMicrotask(() => {
|
||||||
|
this.#socket?.uncork();
|
||||||
|
this.#isCorked = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
2
lib/ts-declarations/cluster-key-slot.d.ts
vendored
2
lib/ts-declarations/cluster-key-slot.d.ts
vendored
@@ -1,3 +1,3 @@
|
|||||||
declare module 'cluster-key-slot' {
|
declare module 'cluster-key-slot' {
|
||||||
export default function calculateSlot(key: string): number;
|
export default function calculateSlot(key: string | Buffer): number;
|
||||||
}
|
}
|
||||||
|
2
lib/ts-declarations/redis-parser.d.ts
vendored
2
lib/ts-declarations/redis-parser.d.ts
vendored
@@ -8,6 +8,8 @@ declare module 'redis-parser' {
|
|||||||
export default class RedisParser {
|
export default class RedisParser {
|
||||||
constructor(callbacks: RedisParserCallbacks);
|
constructor(callbacks: RedisParserCallbacks);
|
||||||
|
|
||||||
|
setReturnBuffers(returnBuffers?: boolean): void;
|
||||||
|
|
||||||
execute(buffer: Buffer): void;
|
execute(buffer: Buffer): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user