You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-09 00:22:08 +03:00
ref #1653 - better types
This commit is contained in:
164
lib/client.ts
164
lib/client.ts
@@ -13,7 +13,7 @@ import { encodeCommand, extendWithDefaultCommands, extendWithModulesAndScripts,
|
|||||||
import { Pool, Options as PoolOptions, createPool } from 'generic-pool';
|
import { Pool, Options as PoolOptions, createPool } from 'generic-pool';
|
||||||
import { ClientClosedError } from './errors';
|
import { ClientClosedError } from './errors';
|
||||||
|
|
||||||
export interface RedisClientOptions<M = RedisModules, S = RedisLuaScripts> {
|
export interface RedisClientOptions<M, S> {
|
||||||
socket?: RedisSocketOptions;
|
socket?: RedisSocketOptions;
|
||||||
modules?: M;
|
modules?: M;
|
||||||
scripts?: S;
|
scripts?: S;
|
||||||
@@ -43,51 +43,25 @@ type WithScripts<S extends RedisLuaScripts> = {
|
|||||||
export type WithPlugins<M extends RedisModules, S extends RedisLuaScripts> =
|
export type WithPlugins<M extends RedisModules, S extends RedisLuaScripts> =
|
||||||
WithCommands & WithModules<M> & WithScripts<S>;
|
WithCommands & WithModules<M> & WithScripts<S>;
|
||||||
|
|
||||||
export type RedisClientType<M extends RedisModules, S extends RedisLuaScripts> =
|
export type RedisClientType<M extends RedisModules = {}, S extends RedisLuaScripts = {}> =
|
||||||
WithPlugins<M, S> & RedisClient<M, S>;
|
WithPlugins<M, S> & RedisClient<M, S>;
|
||||||
|
|
||||||
export interface ClientCommandOptions extends QueueCommandOptions {
|
export interface ClientCommandOptions extends QueueCommandOptions {
|
||||||
isolated?: boolean;
|
isolated?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class RedisClient<M extends RedisModules = RedisModules, S extends RedisLuaScripts = RedisLuaScripts> extends EventEmitter {
|
export default class RedisClient<M extends RedisModules, S extends RedisLuaScripts> extends EventEmitter {
|
||||||
static commandOptions(options: ClientCommandOptions): CommandOptions<ClientCommandOptions> {
|
static commandOptions(options: ClientCommandOptions): CommandOptions<ClientCommandOptions> {
|
||||||
return commandOptions(options);
|
return commandOptions(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async commandsExecutor(
|
static create<M extends RedisModules = {}, S extends RedisLuaScripts = {}>(options?: RedisClientOptions<M, S>): RedisClientType<M, S> {
|
||||||
this: RedisClient,
|
|
||||||
command: RedisCommand,
|
|
||||||
args: Array<unknown>
|
|
||||||
): Promise<ReturnType<typeof command['transformReply']>> {
|
|
||||||
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(command, args);
|
|
||||||
|
|
||||||
return command.transformReply(
|
|
||||||
await this.#sendCommand(redisArgs, options, command.BUFFER_MODE),
|
|
||||||
redisArgs.preserve,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async #scriptsExecutor(
|
|
||||||
this: RedisClient,
|
|
||||||
script: RedisLuaScript,
|
|
||||||
args: Array<unknown>
|
|
||||||
): Promise<typeof script['transformArguments']> {
|
|
||||||
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(script, args);
|
|
||||||
|
|
||||||
return script.transformReply(
|
|
||||||
await this.executeScript(script, redisArgs, options, script.BUFFER_MODE),
|
|
||||||
redisArgs.preserve
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static create<M extends RedisModules, S extends RedisLuaScripts>(options?: RedisClientOptions<M, S>): RedisClientType<M, S> {
|
|
||||||
const Client = (<any>extendWithModulesAndScripts({
|
const Client = (<any>extendWithModulesAndScripts({
|
||||||
BaseClass: RedisClient,
|
BaseClass: RedisClient,
|
||||||
modules: options?.modules,
|
modules: options?.modules,
|
||||||
modulesCommandsExecutor: RedisClient.commandsExecutor,
|
modulesCommandsExecutor: RedisClient.prototype.commandsExecutor,
|
||||||
scripts: options?.scripts,
|
scripts: options?.scripts,
|
||||||
scriptsExecutor: RedisClient.#scriptsExecutor
|
scriptsExecutor: RedisClient.prototype.scriptsExecutor
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (Client !== RedisClient) {
|
if (Client !== RedisClient) {
|
||||||
@@ -104,7 +78,7 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
readonly #v4: Record<string, any> = {};
|
readonly #v4: Record<string, any> = {};
|
||||||
#selectedDB = 0;
|
#selectedDB = 0;
|
||||||
|
|
||||||
get options(): RedisClientOptions<M> | null | undefined {
|
get options(): RedisClientOptions<M, S> | undefined {
|
||||||
return this.#options;
|
return this.#options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +214,72 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
await this.#socket.connect();
|
await this.#socket.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async commandsExecutor(command: RedisCommand, args: Array<unknown>): Promise<ReturnType<typeof command['transformReply']>> {
|
||||||
|
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(command, args);
|
||||||
|
|
||||||
|
return command.transformReply(
|
||||||
|
await this.#sendCommand(redisArgs, options, command.BUFFER_MODE),
|
||||||
|
redisArgs.preserve,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendCommand<T = RedisReply>(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<T> {
|
||||||
|
return this.#sendCommand(args, options, bufferMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// using `#sendCommand` cause `sendCommand` is overwritten in legacy mode
|
||||||
|
async #sendCommand<T = RedisReply>(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<T> {
|
||||||
|
if (!this.#socket.isOpen) {
|
||||||
|
throw new ClientClosedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options?.isolated) {
|
||||||
|
return this.executeIsolated(isolatedClient =>
|
||||||
|
isolatedClient.sendCommand(args, {
|
||||||
|
...options,
|
||||||
|
isolated: false
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const promise = this.#queue.addCommand<T>(args, options, bufferMode);
|
||||||
|
this.#tick();
|
||||||
|
return await promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
async scriptsExecutor(script: RedisLuaScript, args: Array<unknown>): Promise<ReturnType<typeof script['transformReply']>> {
|
||||||
|
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(script, args);
|
||||||
|
|
||||||
|
return script.transformReply(
|
||||||
|
await this.executeScript(script, redisArgs, options, script.BUFFER_MODE),
|
||||||
|
redisArgs.preserve
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async executeScript(script: RedisLuaScript, args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<ReturnType<typeof script['transformReply']>> {
|
||||||
|
try {
|
||||||
|
return await this.#sendCommand([
|
||||||
|
'EVALSHA',
|
||||||
|
script.SHA1,
|
||||||
|
script.NUMBER_OF_KEYS.toString(),
|
||||||
|
...args
|
||||||
|
], options, bufferMode);
|
||||||
|
} catch (err: any) {
|
||||||
|
if (!err?.message?.startsWith?.('NOSCRIPT')) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.#sendCommand([
|
||||||
|
'EVAL',
|
||||||
|
script.SCRIPT,
|
||||||
|
script.NUMBER_OF_KEYS.toString(),
|
||||||
|
...args
|
||||||
|
], options, bufferMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async SELECT(db: number): Promise<void>;
|
async SELECT(db: number): Promise<void>;
|
||||||
async SELECT(options: CommandOptions<ClientCommandOptions>, db: number): Promise<void>;
|
async SELECT(options: CommandOptions<ClientCommandOptions>, db: number): Promise<void>;
|
||||||
async SELECT(options?: any, db?: any): Promise<void> {
|
async SELECT(options?: any, db?: any): Promise<void> {
|
||||||
@@ -300,30 +340,6 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
|
|
||||||
quit = this.QUIT;
|
quit = this.QUIT;
|
||||||
|
|
||||||
sendCommand<T = RedisReply>(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<T> {
|
|
||||||
return this.#sendCommand(args, options, bufferMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// using `#sendCommand` cause `sendCommand` is overwritten in legacy mode
|
|
||||||
async #sendCommand<T = RedisReply>(args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<T> {
|
|
||||||
if (!this.#socket.isOpen) {
|
|
||||||
throw new ClientClosedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options?.isolated) {
|
|
||||||
return this.executeIsolated(isolatedClient =>
|
|
||||||
isolatedClient.sendCommand(args, {
|
|
||||||
...options,
|
|
||||||
isolated: false
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const promise = this.#queue.addCommand<T>(args, options, bufferMode);
|
|
||||||
this.#tick();
|
|
||||||
return await promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
#tick(): void {
|
#tick(): void {
|
||||||
if (!this.#socket.isSocketExists) {
|
if (!this.#socket.isSocketExists) {
|
||||||
return;
|
return;
|
||||||
@@ -350,26 +366,11 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
return this.#isolationPool.use(fn);
|
return this.#isolationPool.use(fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
async executeScript(script: RedisLuaScript, args: TransformArgumentsReply, options?: ClientCommandOptions, bufferMode?: boolean): Promise<ReturnType<typeof script['transformReply']>> {
|
multi(): RedisMultiCommandType<M, S> {
|
||||||
try {
|
return new (this as any).Multi(
|
||||||
return await this.#sendCommand([
|
this.#multiExecutor.bind(this),
|
||||||
'EVALSHA',
|
this.#options
|
||||||
script.SHA1,
|
);
|
||||||
script.NUMBER_OF_KEYS.toString(),
|
|
||||||
...args
|
|
||||||
], options, bufferMode);
|
|
||||||
} catch (err: any) {
|
|
||||||
if (!err?.message?.startsWith?.('NOSCRIPT')) {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return await this.#sendCommand([
|
|
||||||
'EVAL',
|
|
||||||
script.SCRIPT,
|
|
||||||
script.NUMBER_OF_KEYS.toString(),
|
|
||||||
...args
|
|
||||||
], options, bufferMode);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#multiExecutor(commands: Array<MultiQueuedCommand>, chainId?: symbol): Promise<Array<RedisReply>> {
|
#multiExecutor(commands: Array<MultiQueuedCommand>, chainId?: symbol): Promise<Array<RedisReply>> {
|
||||||
@@ -386,13 +387,6 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
multi(): RedisMultiCommandType<M, S> {
|
|
||||||
return new (this as any).Multi(
|
|
||||||
this.#multiExecutor.bind(this),
|
|
||||||
this.#options
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async* scanIterator(options?: ScanCommandOptions): AsyncIterable<string> {
|
async* scanIterator(options?: ScanCommandOptions): AsyncIterable<string> {
|
||||||
let cursor = 0;
|
let cursor = 0;
|
||||||
do {
|
do {
|
||||||
@@ -451,5 +445,5 @@ export default class RedisClient<M extends RedisModules = RedisModules, S extend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extendWithDefaultCommands(RedisClient, RedisClient.commandsExecutor);
|
extendWithDefaultCommands(RedisClient, RedisClient.prototype.commandsExecutor);
|
||||||
(RedisClient.prototype as any).Multi = RedisMultiCommand.extend();
|
(RedisClient.prototype as any).Multi = RedisMultiCommand.extend();
|
||||||
|
@@ -16,10 +16,10 @@ export interface RedisClusterOptions<M = RedisModules, S = RedisLuaScripts> {
|
|||||||
maxCommandRedirections?: number;
|
maxCommandRedirections?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RedisClusterType<M extends RedisModules, S extends RedisLuaScripts> =
|
export type RedisClusterType<M extends RedisModules = {}, S extends RedisLuaScripts = {}> =
|
||||||
WithPlugins<M, S> & RedisCluster;
|
WithPlugins<M, S> & RedisCluster<M, S>;
|
||||||
|
|
||||||
export default class RedisCluster<M extends RedisModules = RedisModules, S extends RedisLuaScripts = RedisLuaScripts> extends EventEmitter {
|
export default class RedisCluster<M extends RedisModules = {}, S extends RedisLuaScripts = {}> extends EventEmitter {
|
||||||
static #extractFirstKey(command: RedisCommand, originalArgs: Array<unknown>, redisArgs: TransformArgumentsReply): string | Buffer | 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;
|
||||||
@@ -30,54 +30,13 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
return command.FIRST_KEY_INDEX(...originalArgs);
|
return command.FIRST_KEY_INDEX(...originalArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static async commandsExecutor(
|
static create<M extends RedisModules = {}, S extends RedisLuaScripts = {}>(options?: RedisClusterOptions<M, S>): RedisClusterType<M, S> {
|
||||||
this: RedisCluster,
|
|
||||||
command: RedisCommand,
|
|
||||||
args: Array<unknown>
|
|
||||||
): Promise<ReturnType<typeof command['transformReply']>> {
|
|
||||||
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(command, args);
|
|
||||||
|
|
||||||
const reply = command.transformReply(
|
|
||||||
await this.sendCommand(
|
|
||||||
RedisCluster.#extractFirstKey(command, args, redisArgs),
|
|
||||||
command.IS_READ_ONLY,
|
|
||||||
redisArgs,
|
|
||||||
options,
|
|
||||||
command.BUFFER_MODE
|
|
||||||
),
|
|
||||||
redisArgs.preserve
|
|
||||||
);
|
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
static async #scriptsExecutor(
|
|
||||||
this: RedisCluster,
|
|
||||||
script: RedisLuaScript,
|
|
||||||
args: Array<unknown>
|
|
||||||
): Promise<typeof script['transformArguments']> {
|
|
||||||
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(script, args);
|
|
||||||
|
|
||||||
const reply = script.transformReply(
|
|
||||||
await this.executeScript(
|
|
||||||
script,
|
|
||||||
args,
|
|
||||||
redisArgs,
|
|
||||||
options
|
|
||||||
),
|
|
||||||
redisArgs.preserve
|
|
||||||
);
|
|
||||||
|
|
||||||
return reply;
|
|
||||||
}
|
|
||||||
|
|
||||||
static create<M extends RedisModules, S extends RedisLuaScripts>(options?: RedisClusterOptions<M, S>): RedisClusterType<M, S> {
|
|
||||||
return new (<any>extendWithModulesAndScripts({
|
return new (<any>extendWithModulesAndScripts({
|
||||||
BaseClass: RedisCluster,
|
BaseClass: RedisCluster,
|
||||||
modules: options?.modules,
|
modules: options?.modules,
|
||||||
modulesCommandsExecutor: RedisCluster.commandsExecutor,
|
modulesCommandsExecutor: RedisCluster.prototype.commandsExecutor,
|
||||||
scripts: options?.scripts,
|
scripts: options?.scripts,
|
||||||
scriptsExecutor: RedisCluster.#scriptsExecutor
|
scriptsExecutor: RedisCluster.prototype.scriptsExecutor
|
||||||
}))(options);
|
}))(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +60,23 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
return this.#slots.connect();
|
return this.#slots.connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async commandsExecutor(command: RedisCommand, args: Array<unknown>): Promise<ReturnType<typeof command['transformReply']>> {
|
||||||
|
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(command, args);
|
||||||
|
|
||||||
|
const reply = command.transformReply(
|
||||||
|
await this.sendCommand(
|
||||||
|
RedisCluster.#extractFirstKey(command, args, redisArgs),
|
||||||
|
command.IS_READ_ONLY,
|
||||||
|
redisArgs,
|
||||||
|
options,
|
||||||
|
command.BUFFER_MODE
|
||||||
|
),
|
||||||
|
redisArgs.preserve
|
||||||
|
);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
async sendCommand<C extends RedisCommand>(
|
async sendCommand<C extends RedisCommand>(
|
||||||
firstKey: string | Buffer | undefined,
|
firstKey: string | Buffer | undefined,
|
||||||
isReadonly: boolean | undefined,
|
isReadonly: boolean | undefined,
|
||||||
@@ -125,6 +101,22 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async scriptsExecutor(script: RedisLuaScript, args: Array<unknown>): Promise<ReturnType<typeof script['transformReply']>> {
|
||||||
|
const { args: redisArgs, options } = transformCommandArguments<ClientCommandOptions>(script, args);
|
||||||
|
|
||||||
|
const reply = script.transformReply(
|
||||||
|
await this.executeScript(
|
||||||
|
script,
|
||||||
|
args,
|
||||||
|
redisArgs,
|
||||||
|
options
|
||||||
|
),
|
||||||
|
redisArgs.preserve
|
||||||
|
);
|
||||||
|
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
async executeScript(
|
async executeScript(
|
||||||
script: RedisLuaScript,
|
script: RedisLuaScript,
|
||||||
originalArgs: Array<unknown>,
|
originalArgs: Array<unknown>,
|
||||||
@@ -208,5 +200,4 @@ export default class RedisCluster<M extends RedisModules = RedisModules, S exten
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extendWithDefaultCommands(RedisCluster, RedisCluster.commandsExecutor);
|
extendWithDefaultCommands(RedisCluster, RedisCluster.prototype.commandsExecutor);
|
||||||
|
|
||||||
|
@@ -8,7 +8,7 @@ describe('GEOSEARCHSTORE', () => {
|
|||||||
describe('transformArguments', () => {
|
describe('transformArguments', () => {
|
||||||
it('simple', () => {
|
it('simple', () => {
|
||||||
assert.deepEqual(
|
assert.deepEqual(
|
||||||
transformArguments('destination', 'source', 'member', {
|
transformArguments('destination', '/home/leibale/Workspace/node-redis/lib/commands/GEOSEARCHSTORE.spec.tssource', 'member', {
|
||||||
radius: 1,
|
radius: 1,
|
||||||
unit: 'm'
|
unit: 'm'
|
||||||
}, {
|
}, {
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { TransformArgumentsReply } from '.';
|
||||||
import { transformEXAT, transformPXAT, transformReplyStringNull } from './generic-transformers';
|
import { transformEXAT, transformPXAT, transformReplyStringNull } from './generic-transformers';
|
||||||
|
|
||||||
export const FIRST_KEY_INDEX = 1;
|
export const FIRST_KEY_INDEX = 1;
|
||||||
@@ -14,7 +15,7 @@ type GetExModes = {
|
|||||||
PERSIST: true;
|
PERSIST: true;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function transformArguments(key: string, mode: GetExModes) {
|
export function transformArguments(key: string, mode: GetExModes): TransformArgumentsReply {
|
||||||
const args = ['GETEX', key];
|
const args = ['GETEX', key];
|
||||||
|
|
||||||
if ('EX' in mode) {
|
if ('EX' in mode) {
|
||||||
|
@@ -753,7 +753,10 @@ export interface RedisCommands {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface RedisModule {
|
export interface RedisModule {
|
||||||
[key: string]: RedisCommand;
|
[command: string]: RedisCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RedisModules = Record<string, RedisModule>;
|
export interface RedisModules {
|
||||||
|
[module: string]: RedisModule;
|
||||||
|
}
|
||||||
|
// export type RedisModules = Record<string, RedisModule>;
|
||||||
|
@@ -13,10 +13,10 @@ export interface SHA1 {
|
|||||||
export type RedisLuaScript = RedisLuaScriptConfig & SHA1;
|
export type RedisLuaScript = RedisLuaScriptConfig & SHA1;
|
||||||
|
|
||||||
export interface RedisLuaScripts {
|
export interface RedisLuaScripts {
|
||||||
[key: string]: RedisLuaScript;
|
[script: string]: RedisLuaScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function defineScript<S extends RedisLuaScriptConfig>(script: S): S & SHA1 {
|
export function defineScript(script: RedisLuaScriptConfig): typeof script & SHA1 {
|
||||||
return {
|
return {
|
||||||
...script,
|
...script,
|
||||||
SHA1: scriptSha1(script.SCRIPT)
|
SHA1: scriptSha1(script.SCRIPT)
|
||||||
|
@@ -21,7 +21,8 @@ type WithScripts<M extends RedisModules, S extends RedisLuaScripts> = {
|
|||||||
[P in keyof S]: RedisMultiCommandSignature<S[P], M, S>
|
[P in keyof S]: RedisMultiCommandSignature<S[P], M, S>
|
||||||
};
|
};
|
||||||
|
|
||||||
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<M, S> & WithCommands<M, S> & WithModules<M, S> & WithScripts<M, S>;
|
||||||
|
|
||||||
export interface MultiQueuedCommand {
|
export interface MultiQueuedCommand {
|
||||||
args: TransformArgumentsReply;
|
args: TransformArgumentsReply;
|
||||||
@@ -31,60 +32,20 @@ export interface MultiQueuedCommand {
|
|||||||
|
|
||||||
export type RedisMultiExecutor = (queue: Array<MultiQueuedCommand>, chainId?: symbol) => Promise<Array<RedisReply>>;
|
export type RedisMultiExecutor = (queue: Array<MultiQueuedCommand>, chainId?: symbol) => Promise<Array<RedisReply>>;
|
||||||
|
|
||||||
export default class RedisMultiCommand<M extends RedisModules = RedisModules, S extends RedisLuaScripts = RedisLuaScripts> {
|
export default class RedisMultiCommand<M extends RedisModules, S extends RedisLuaScripts> {
|
||||||
static commandsExecutor(this: RedisMultiCommand, command: RedisCommand, args: Array<unknown>): RedisMultiCommand {
|
|
||||||
return this.addCommand(
|
|
||||||
command.transformArguments(...args),
|
|
||||||
command.transformReply
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static #scriptsExecutor(
|
|
||||||
this: RedisMultiCommand,
|
|
||||||
script: RedisLuaScript,
|
|
||||||
args: Array<unknown>
|
|
||||||
): RedisMultiCommand {
|
|
||||||
const transformedArguments: TransformArgumentsReply = [];
|
|
||||||
if (this.#scriptsInUse.has(script.SHA1)) {
|
|
||||||
transformedArguments.push(
|
|
||||||
'EVALSHA',
|
|
||||||
script.SHA1
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.#scriptsInUse.add(script.SHA1);
|
|
||||||
transformedArguments.push(
|
|
||||||
'EVAL',
|
|
||||||
script.SCRIPT
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
transformedArguments.push(script.NUMBER_OF_KEYS.toString());
|
|
||||||
|
|
||||||
const scriptArguments = script.transformArguments(...args);
|
|
||||||
transformedArguments.push(...scriptArguments);
|
|
||||||
if (scriptArguments.preserve) {
|
|
||||||
transformedArguments.preserve = scriptArguments.preserve;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.addCommand(
|
|
||||||
transformedArguments,
|
|
||||||
script.transformReply
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
static extend<M extends RedisModules, S extends RedisLuaScripts>(
|
static extend<M extends RedisModules, S extends RedisLuaScripts>(
|
||||||
clientOptions?: RedisClientOptions<M, S>
|
clientOptions?: RedisClientOptions<M, S>
|
||||||
): new (...args: ConstructorParameters<typeof RedisMultiCommand>) => RedisMultiCommandType<M, S> {
|
): new (...args: ConstructorParameters<typeof RedisMultiCommand>) => RedisMultiCommandType<M, S> {
|
||||||
return <any>extendWithModulesAndScripts({
|
return <any>extendWithModulesAndScripts({
|
||||||
BaseClass: RedisMultiCommand,
|
BaseClass: RedisMultiCommand,
|
||||||
modules: clientOptions?.modules,
|
modules: clientOptions?.modules,
|
||||||
modulesCommandsExecutor: RedisMultiCommand.commandsExecutor,
|
modulesCommandsExecutor: RedisMultiCommand.prototype.commandsExecutor,
|
||||||
scripts: clientOptions?.scripts,
|
scripts: clientOptions?.scripts,
|
||||||
scriptsExecutor: RedisMultiCommand.#scriptsExecutor
|
scriptsExecutor: RedisMultiCommand.prototype.scriptsExecutor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static create<M extends RedisModules, S extends RedisLuaScripts>(
|
static create<M extends RedisModules = {}, S extends RedisLuaScripts = {}>(
|
||||||
executor: RedisMultiExecutor,
|
executor: RedisMultiExecutor,
|
||||||
clientOptions?: RedisClientOptions<M, S>
|
clientOptions?: RedisClientOptions<M, S>
|
||||||
): RedisMultiCommandType<M, S> {
|
): RedisMultiCommandType<M, S> {
|
||||||
@@ -153,6 +114,42 @@ export default class RedisMultiCommand<M extends RedisModules = RedisModules, S
|
|||||||
(this as any)[name] = (...args: Array<unknown>): void => (this as any).addCommand(name, args);
|
(this as any)[name] = (...args: Array<unknown>): void => (this as any).addCommand(name, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
commandsExecutor(command: RedisCommand, args: Array<unknown>): this {
|
||||||
|
return this.addCommand(
|
||||||
|
command.transformArguments(...args),
|
||||||
|
command.transformReply
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptsExecutor(script: RedisLuaScript, args: Array<unknown>): this {
|
||||||
|
const transformedArguments: TransformArgumentsReply = [];
|
||||||
|
if (this.#scriptsInUse.has(script.SHA1)) {
|
||||||
|
transformedArguments.push(
|
||||||
|
'EVALSHA',
|
||||||
|
script.SHA1
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.#scriptsInUse.add(script.SHA1);
|
||||||
|
transformedArguments.push(
|
||||||
|
'EVAL',
|
||||||
|
script.SCRIPT
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
transformedArguments.push(script.NUMBER_OF_KEYS.toString());
|
||||||
|
|
||||||
|
const scriptArguments = script.transformArguments(...args);
|
||||||
|
transformedArguments.push(...scriptArguments);
|
||||||
|
if (scriptArguments.preserve) {
|
||||||
|
transformedArguments.preserve = scriptArguments.preserve;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.addCommand(
|
||||||
|
transformedArguments,
|
||||||
|
script.transformReply
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
addCommand(args: TransformArgumentsReply, transformReply?: RedisCommand['transformReply']): this {
|
addCommand(args: TransformArgumentsReply, transformReply?: RedisCommand['transformReply']): this {
|
||||||
this.#queue.push({
|
this.#queue.push({
|
||||||
args,
|
args,
|
||||||
@@ -205,4 +202,4 @@ export default class RedisMultiCommand<M extends RedisModules = RedisModules, S
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extendWithDefaultCommands(RedisMultiCommand, RedisMultiCommand.commandsExecutor);
|
extendWithDefaultCommands(RedisMultiCommand, RedisMultiCommand.prototype.commandsExecutor);
|
||||||
|
@@ -112,7 +112,7 @@ async function spawnGlobalRedisServer(args?: Array<string>): Promise<number> {
|
|||||||
const SLOTS = 16384;
|
const SLOTS = 16384;
|
||||||
|
|
||||||
interface SpawnRedisClusterNodeResult extends SpawnRedisServerResult {
|
interface SpawnRedisClusterNodeResult extends SpawnRedisServerResult {
|
||||||
client: RedisClientType<RedisModules, RedisLuaScripts>
|
client: RedisClientType
|
||||||
}
|
}
|
||||||
|
|
||||||
async function spawnRedisClusterNode(
|
async function spawnRedisClusterNode(
|
||||||
@@ -281,7 +281,7 @@ export function describeHandleMinimumRedisVersion(minimumVersion: PartialRedisVe
|
|||||||
export function itWithClient(
|
export function itWithClient(
|
||||||
type: TestRedisServers,
|
type: TestRedisServers,
|
||||||
title: string,
|
title: string,
|
||||||
fn: (client: RedisClientType<RedisModules, RedisLuaScripts>) => Promise<void>,
|
fn: (client: RedisClientType) => Promise<void>,
|
||||||
options?: RedisTestOptions
|
options?: RedisTestOptions
|
||||||
): void {
|
): void {
|
||||||
it(title, async function () {
|
it(title, async function () {
|
||||||
@@ -306,7 +306,7 @@ export function itWithClient(
|
|||||||
export function itWithCluster(
|
export function itWithCluster(
|
||||||
type: TestRedisClusters,
|
type: TestRedisClusters,
|
||||||
title: string,
|
title: string,
|
||||||
fn: (cluster: RedisClusterType<RedisModules, RedisLuaScripts>) => Promise<void>,
|
fn: (cluster: RedisClusterType) => Promise<void>,
|
||||||
options?: RedisTestOptions
|
options?: RedisTestOptions
|
||||||
): void {
|
): void {
|
||||||
it(title, async function () {
|
it(title, async function () {
|
||||||
@@ -328,7 +328,7 @@ export function itWithCluster(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function itWithDedicatedCluster(title: string, fn: (cluster: RedisClusterType<RedisModules, RedisLuaScripts>) => Promise<void>): void {
|
export function itWithDedicatedCluster(title: string, fn: (cluster: RedisClusterType) => Promise<void>): void {
|
||||||
it(title, async function () {
|
it(title, async function () {
|
||||||
this.timeout(10000);
|
this.timeout(10000);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user