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

some more commands, multi.exec<'typed'>

This commit is contained in:
Leibale
2023-04-24 19:50:58 -04:00
parent 39bcac6484
commit b272f18818
13 changed files with 171 additions and 132 deletions

View File

@@ -10,3 +10,4 @@
`Number` -> `Boolean`: `Number` -> `Boolean`:
- `HSETNX` (deprecated) - `HSETNX` (deprecated)
- `SCRIPT EXISTS`

View File

@@ -68,6 +68,7 @@ Some command arguments/replies have changed to align more closely to data types
- `RENAMENX`: `boolean` -> `number` [^boolean-to-number] - `RENAMENX`: `boolean` -> `number` [^boolean-to-number]
- `HSCAN`: `tuples` has been renamed to `entries` - `HSCAN`: `tuples` has been renamed to `entries`
- `PFADD`: `boolean` -> `number` [^boolean-to-number] - `PFADD`: `boolean` -> `number` [^boolean-to-number]
- `SCRIPT EXISTS`: `Array<boolean>` -> `Array<number>` [^boolean-to-number]
[^enum-to-constants]: TODO [^enum-to-constants]: TODO

View File

@@ -1,6 +1,6 @@
import COMMANDS from '../commands'; import COMMANDS from '../commands';
import RedisMultiCommand, { RedisMultiQueuedCommand } from '../multi-command'; import RedisMultiCommand, { RedisMultiQueuedCommand } from '../multi-command';
import { ReplyWithFlags, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, Flags } from '../RESP/types'; import { ReplyWithFlags, CommandReply, Command, CommandArguments, CommanderConfig, RedisFunctions, RedisModules, RedisScripts, RespVersions, TransformReply, RedisScript, RedisFunction, Flags, ReplyUnion } from '../RESP/types';
import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander'; import { attachConfig, functionArgumentsPrefix, getTransformReply } from '../commander';
type CommandSignature< type CommandSignature<
@@ -83,6 +83,11 @@ export type RedisClientMultiCommandType<
WithScripts<REPLIES, M, F, S, RESP, FLAGS> WithScripts<REPLIES, M, F, S, RESP, FLAGS>
); );
type ReplyType<
REPLIES,
T = 'generic'
> = T extends 'typed' ? REPLIES : Array<ReplyUnion>;
export type RedisClientMultiExecutor = ( export type RedisClientMultiExecutor = (
queue: Array<RedisMultiQueuedCommand>, queue: Array<RedisMultiQueuedCommand>,
selectedDB?: number, selectedDB?: number,
@@ -216,8 +221,8 @@ export default class RedisClientMultiCommand<REPLIES = []> extends RedisMultiCom
select = this.SELECT; select = this.SELECT;
async exec(execAsPipeline = false): Promise<REPLIES> { async exec<T>(execAsPipeline = false) {
if (execAsPipeline) return this.execAsPipeline(); if (execAsPipeline) return this.execAsPipeline<T>();
return this.handleExecReplies( return this.handleExecReplies(
await this.#executor( await this.#executor(
@@ -225,19 +230,19 @@ export default class RedisClientMultiCommand<REPLIES = []> extends RedisMultiCom
this.#selectedDB, this.#selectedDB,
RedisMultiCommand.generateChainId() RedisMultiCommand.generateChainId()
) )
) as REPLIES; ) as ReplyType<REPLIES, T>;
} }
EXEC = this.exec; EXEC = this.exec;
async execAsPipeline(): Promise<REPLIES> { async execAsPipeline<T>() {
if (this.queue.length === 0) return [] as REPLIES; if (this.queue.length === 0) return [] as ReplyType<REPLIES, T>;
return this.transformReplies( return this.transformReplies(
await this.#executor( await this.#executor(
this.queue, this.queue,
this.#selectedDB this.#selectedDB
) )
) as REPLIES; ) as ReplyType<REPLIES, T>;
} }
} }

View File

@@ -1,87 +1,87 @@
// import { RedisCommandArguments } from '.'; // // import { RedisCommandArguments } from '.';
// export function transformArguments(): RedisCommandArguments { // // export function transformArguments(): RedisCommandArguments {
// // return ['FUNCTION', 'STATS'];
// // }
// // type FunctionStatsRawReply = [
// // 'running_script',
// // null | [
// // 'name',
// // string,
// // 'command',
// // string,
// // 'duration_ms',
// // number
// // ],
// // 'engines',
// // Array<any> // "flat tuples" (there is no way to type that)
// // // ...[string, [
// // // 'libraries_count',
// // // number,
// // // 'functions_count',
// // // number
// // // ]]
// // ];
// // interface FunctionStatsReply {
// // runningScript: null | {
// // name: string;
// // command: string;
// // durationMs: number;
// // };
// // engines: Record<string, {
// // librariesCount: number;
// // functionsCount: number;
// // }>;
// // }
// // export function transformReply(reply: FunctionStatsRawReply): FunctionStatsReply {
// // const engines = Object.create(null);
// // for (let i = 0; i < reply[3].length; i++) {
// // engines[reply[3][i]] = {
// // librariesCount: reply[3][++i][1],
// // functionsCount: reply[3][i][3]
// // };
// // }
// // return {
// // runningScript: reply[1] === null ? null : {
// // name: reply[1][1],
// // command: reply[1][3],
// // durationMs: reply[1][5]
// // },
// // engines
// // };
// // }
// // #!LUA name=math \n redis.register_function{ function_name = "square", callback = function(keys, args) return args[1] * args[1] end, flags = { "no-writes" } }
// import { Command, TuplesToMapReply, BlobStringReply, NullReply, NumberReply, MapReply } from '../RESP/types';
// type FunctionStatsReply = TuplesToMapReply<[
// [BlobStringReply<'running_script'>, NullReply | TuplesToMapReply<[
// [BlobStringReply<'name'>, BlobStringReply],
// [BlobStringReply<'command'>, BlobStringReply],
// [BlobStringReply<'duration_ms'>, NumberReply]
// ]>],
// [BlobStringReply<'engines'>, MapReply<BlobStringReply, TuplesToMapReply<[
// [BlobStringReply<'libraries_count'>, NumberReply],
// [BlobStringReply<'functions_count'>, NumberReply]
// ]>>]
// ]>;
// export default {
// IS_READ_ONLY: true,
// FIRST_KEY_INDEX: undefined,
// transformArguments() {
// return ['FUNCTION', 'STATS']; // return ['FUNCTION', 'STATS'];
// } // },
// transformReply: {
// 2: (reply) => {
// type FunctionStatsRawReply = [ // },
// 'running_script', // 3: undefined as unknown as () =>
// null | [ // }
// 'name', // } as const satisfies Command;
// string,
// 'command',
// string,
// 'duration_ms',
// number
// ],
// 'engines',
// Array<any> // "flat tuples" (there is no way to type that)
// // ...[string, [
// // 'libraries_count',
// // number,
// // 'functions_count',
// // number
// // ]]
// ];
// interface FunctionStatsReply {
// runningScript: null | {
// name: string;
// command: string;
// durationMs: number;
// };
// engines: Record<string, {
// librariesCount: number;
// functionsCount: number;
// }>;
// }
// export function transformReply(reply: FunctionStatsRawReply): FunctionStatsReply {
// const engines = Object.create(null);
// for (let i = 0; i < reply[3].length; i++) {
// engines[reply[3][i]] = {
// librariesCount: reply[3][++i][1],
// functionsCount: reply[3][i][3]
// };
// }
// return {
// runningScript: reply[1] === null ? null : {
// name: reply[1][1],
// command: reply[1][3],
// durationMs: reply[1][5]
// },
// engines
// };
// }
// #!LUA name=math \n redis.register_function{ function_name = "square", callback = function(keys, args) return args[1] * args[1] end, flags = { "no-writes" } }
import { Command, TuplesToMapReply, BlobStringReply, NullReply, NumberReply, MapReply } from '../RESP/types';
type FunctionStatsReply = TuplesToMapReply<[
[BlobStringReply<'running_script'>, NullReply | TuplesToMapReply<[
[BlobStringReply<'name'>, BlobStringReply],
[BlobStringReply<'command'>, BlobStringReply],
[BlobStringReply<'duration_ms'>, NumberReply]
]>],
[BlobStringReply<'engines'>, MapReply<BlobStringReply, TuplesToMapReply<[
[BlobStringReply<'libraries_count'>, NumberReply],
[BlobStringReply<'functions_count'>, NumberReply]
]>>]
]>;
export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments() {
return ['FUNCTION', 'STATS'];
},
transformReply: {
2: (reply) => {
},
3: undefined as unknown as () =>
}
} as const satisfies Command;

View File

@@ -1,5 +1,10 @@
export function transformArguments(): Array<string> { import { SimpleStringReply, Command } from '../RESP/types';
return ['RESTORE-ASKING'];
}
export declare function transformReply(): string; export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments() {
return ['RESTORE-ASKING'];
},
transformReply: undefined as unknown as () => SimpleStringReply
} as const satisfies Command;

View File

@@ -1,7 +1,10 @@
import { RedisCommandArgument } from '.'; import { SimpleStringReply, Command } from '../RESP/types';
export function transformArguments(): Array<string> { export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments() {
return ['SAVE']; return ['SAVE'];
} },
transformReply: undefined as unknown as () => SimpleStringReply
export declare function transformReply(): RedisCommandArgument; } as const satisfies Command;

View File

@@ -1,5 +1,10 @@
export function transformArguments(mode: 'YES' | 'SYNC' | 'NO'): Array<string> { import { SimpleStringReply, Command } from '../RESP/types';
return ['SCRIPT', 'DEBUG', mode];
}
export declare function transformReply(): string; export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments(mode: 'YES' | 'SYNC' | 'NO') {
return ['SCRIPT', 'DEBUG', mode];
},
transformReply: undefined as unknown as () => SimpleStringReply
} as const satisfies Command;

View File

@@ -1,8 +1,11 @@
import { RedisCommandArguments } from '.'; import { RedisArgument, ArrayReply, NumberReply, Command } from '../RESP/types';
import { pushVariadicArguments } from './generic-transformers'; import { pushVariadicArguments } from './generic-transformers';
export function transformArguments(sha1: string | Array<string>): RedisCommandArguments { export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments(sha1: RedisArgument | Array<RedisArgument>) {
return pushVariadicArguments(['SCRIPT', 'EXISTS'], sha1); return pushVariadicArguments(['SCRIPT', 'EXISTS'], sha1);
} },
transformReply: undefined as unknown as () => ArrayReply<NumberReply>
export { transformBooleanArrayReply as transformReply } from './generic-transformers'; } as const satisfies Command;

View File

@@ -1,11 +1,16 @@
export function transformArguments(mode?: 'ASYNC' | 'SYNC'): Array<string> { import { SimpleStringReply, Command } from '../RESP/types';
export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments(mode?: 'ASYNC' | 'SYNC') {
const args = ['SCRIPT', 'FLUSH']; const args = ['SCRIPT', 'FLUSH'];
if (mode) { if (mode) {
args.push(mode); args.push(mode);
} }
return args; return args;
} },
transformReply: undefined as unknown as () => SimpleStringReply
export declare function transformReply(): string; } as const satisfies Command;

View File

@@ -1,5 +1,10 @@
export function transformArguments(): Array<string> { import { SimpleStringReply, Command } from '../RESP/types';
return ['SCRIPT', 'KILL'];
}
export declare function transformReply(): string; export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments() {
return ['SCRIPT', 'KILL'];
},
transformReply: undefined as unknown as () => SimpleStringReply
} as const satisfies Command;

View File

@@ -1,5 +1,10 @@
export function transformArguments(script: string): Array<string> { import { BlobStringReply, Command, RedisArgument } from '../RESP/types';
return ['SCRIPT', 'LOAD', script];
}
export declare function transformReply(): string; export default {
IS_READ_ONLY: true,
FIRST_KEY_INDEX: undefined,
transformArguments(script: RedisArgument) {
return ['SCRIPT', 'LOAD', script];
},
transformReply: undefined as unknown as () => BlobStringReply
} as const satisfies Command;

View File

@@ -1,6 +1,6 @@
import { RedisArgument, SimpleStringReply, BlobStringReply, NullReply, Command } from '../RESP/types'; import { RedisArgument, SimpleStringReply, BlobStringReply, NullReply, Command } from '../RESP/types';
interface SetOptions { export interface SetOptions {
expiration?: { expiration?: {
type: 'EX' | 'PX' | 'EXAT' | 'PXAT'; type: 'EX' | 'PX' | 'EXAT' | 'PXAT';
value: number; value: number;

View File

@@ -1,14 +1,15 @@
import { RedisCommandArgument, RedisCommandArguments } from '.'; import { RedisArgument, NumberReply, Command } from '../RESP/types';
import { BitValue } from './generic-transformers'; import { BitValue } from './generic-transformers';
export const FIRST_KEY_INDEX = 1; export default {
IS_READ_ONLY: false,
export function transformArguments( FIRST_KEY_INDEX: 1,
key: RedisCommandArgument, transformArguments(
key: RedisArgument,
offset: number, offset: number,
value: BitValue value: BitValue
): RedisCommandArguments { ) {
return ['SETBIT', key, offset.toString(), value.toString()]; return ['SETBIT', key, offset.toString(), value.toString()];
} },
transformReply: undefined as unknown as () => NumberReply<BitValue>
export declare function transformReply(): BitValue; } as const satisfies Command;