From ab153a8edaacfb70fc89dfe834899de0ecf7f60d Mon Sep 17 00:00:00 2001 From: Leibale Date: Thu, 6 Jul 2023 10:38:30 -0400 Subject: [PATCH] wip --- .../lib/commands/COMMAND_GETKEYSANDFLAGS.ts | 40 +++++++-------- .../client/lib/commands/FUNCTION_LOAD.spec.ts | 2 +- .../client/lib/commands/MEMORY_STATS.spec.ts | 4 +- packages/client/lib/commands/MEMORY_STATS.ts | 1 + .../lib/commands/XINFO_CONSUMERS.spec.ts | 6 ++- .../client/lib/commands/XINFO_GROUPS.spec.ts | 6 ++- .../client/lib/commands/XINFO_STREAM.spec.ts | 8 +-- packages/client/lib/commands/XINFO_STREAM.ts | 51 +++++++++---------- .../lib/commands/XPENDING_RANGE.spec.ts | 3 +- packages/client/lib/commands/index.ts | 36 +++++++++++++ 10 files changed, 97 insertions(+), 60 deletions(-) diff --git a/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts b/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts index d1232d1999..a3581237f4 100644 --- a/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts +++ b/packages/client/lib/commands/COMMAND_GETKEYSANDFLAGS.ts @@ -1,24 +1,20 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, SetReply, Command } from '../RESP/types'; -// export const IS_READ_ONLY = true; +export type CommandGetKeysAndFlagsRawReply = ArrayReply +]>>; -// export function transformArguments(args: Array): RedisCommandArguments { -// return ['COMMAND', 'GETKEYSANDFLAGS', ...args]; -// } - -// type KeysAndFlagsRawReply = Array<[ -// RedisCommandArgument, -// RedisCommandArguments -// ]>; - -// type KeysAndFlagsReply = Array<{ -// key: RedisCommandArgument; -// flags: RedisCommandArguments; -// }>; - -// export function transformReply(reply: KeysAndFlagsRawReply): KeysAndFlagsReply { -// return reply.map(([key, flags]) => ({ -// key, -// flags -// })); -// } +export default { + FIRST_KEY_INDEX: undefined, + IS_READ_ONLY: true, + transformArguments(args: Array) { + return ['COMMAND', 'GETKEYSANDFLAGS', ...args]; + }, + transformReply(reply: CommandGetKeysAndFlagsRawReply) { + return reply.map(([key, flags]) => ({ + key, + flags + })); + } +} as const satisfies Command; diff --git a/packages/client/lib/commands/FUNCTION_LOAD.spec.ts b/packages/client/lib/commands/FUNCTION_LOAD.spec.ts index fbda163067..61246c4523 100644 --- a/packages/client/lib/commands/FUNCTION_LOAD.spec.ts +++ b/packages/client/lib/commands/FUNCTION_LOAD.spec.ts @@ -9,7 +9,7 @@ export const MATH_FUNCTION = { engine: 'LUA', code: `#!LUA name=math - redis.register_function{ + redis.register_function { function_name = "square", callback = function(keys, args) return args[1] * args[1] end, flags = { "no-writes" } diff --git a/packages/client/lib/commands/MEMORY_STATS.spec.ts b/packages/client/lib/commands/MEMORY_STATS.spec.ts index 28caa208b8..d210514d7f 100644 --- a/packages/client/lib/commands/MEMORY_STATS.spec.ts +++ b/packages/client/lib/commands/MEMORY_STATS.spec.ts @@ -18,7 +18,9 @@ describe('MEMORY STATS', () => { assert.equal(typeof memoryStats['replication.backlog'], 'number'); assert.equal(typeof memoryStats['clients.slaves'], 'number'); assert.equal(typeof memoryStats['clients.normal'], 'number'); - assert.equal(typeof memoryStats['cluster.links'], 'number'); + if (testUtils.isVersionGreaterThan([7])) { + assert.equal(typeof memoryStats['cluster.links'], 'number'); + } assert.equal(typeof memoryStats['aof.buffer'], 'number'); assert.equal(typeof memoryStats['lua.caches'], 'number'); assert.equal(typeof memoryStats['functions.caches'], 'number'); diff --git a/packages/client/lib/commands/MEMORY_STATS.ts b/packages/client/lib/commands/MEMORY_STATS.ts index 2d798ccd2c..b15db7fb8f 100644 --- a/packages/client/lib/commands/MEMORY_STATS.ts +++ b/packages/client/lib/commands/MEMORY_STATS.ts @@ -7,6 +7,7 @@ export type MemoryStatsReply = TuplesToMapReply<[ [BlobStringReply<'replication.backlog'>, NumberReply], [BlobStringReply<'clients.slaves'>, NumberReply], [BlobStringReply<'clients.normal'>, NumberReply], + /** added in 7.0 */ [BlobStringReply<'cluster.links'>, NumberReply], [BlobStringReply<'aof.buffer'>, NumberReply], [BlobStringReply<'lua.caches'>, NumberReply], diff --git a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts index e57ed72d8e..ddfba6f27a 100644 --- a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts +++ b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts @@ -15,7 +15,11 @@ describe('XINFO CONSUMERS', () => { client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }), - client.xGroupCreateConsumer('key', 'group', 'consumer'), + // using `XREADGROUP` and not `XGROUP CREATECONSUMER` because the latter was introduced in Redis 6.2 + client.xReadGroup('group', 'consumer', { + key: 'key', + id: '0-0' + }), client.xInfoConsumers('key', 'group') ]); diff --git a/packages/client/lib/commands/XINFO_GROUPS.spec.ts b/packages/client/lib/commands/XINFO_GROUPS.spec.ts index 7ac02972d6..20dfb14804 100644 --- a/packages/client/lib/commands/XINFO_GROUPS.spec.ts +++ b/packages/client/lib/commands/XINFO_GROUPS.spec.ts @@ -25,8 +25,10 @@ describe('XINFO GROUPS', () => { consumers: 0, pending: 0, 'last-delivered-id': '0-0', - 'entries-read': null, - lag: 0 + ...testUtils.isVersionGreaterThan([7, 0]) && { + 'entries-read': null, + lag: 0 + } }] ); }, { diff --git a/packages/client/lib/commands/XINFO_STREAM.spec.ts b/packages/client/lib/commands/XINFO_STREAM.spec.ts index 99370fb97f..630d25c396 100644 --- a/packages/client/lib/commands/XINFO_STREAM.spec.ts +++ b/packages/client/lib/commands/XINFO_STREAM.spec.ts @@ -23,9 +23,11 @@ describe('XINFO STREAM', () => { 'radix-tree-keys': 0, 'radix-tree-nodes': 1, 'last-generated-id': '0-0', - 'max-deleted-entry-id': '0-0', - 'entries-added': 0, - 'recorded-first-entry-id': '0-0', + ...testUtils.isVersionGreaterThan([7, 0]) && { + 'max-deleted-entry-id': '0-0', + 'entries-added': 0, + 'recorded-first-entry-id': '0-0', + }, groups: 1, 'first-entry': null, 'last-entry': null diff --git a/packages/client/lib/commands/XINFO_STREAM.ts b/packages/client/lib/commands/XINFO_STREAM.ts index 00b6b0aa4e..93416ae40a 100644 --- a/packages/client/lib/commands/XINFO_STREAM.ts +++ b/packages/client/lib/commands/XINFO_STREAM.ts @@ -1,26 +1,16 @@ import { TuplesToMapReply, BlobStringReply, NumberReply, NullReply, Resp2Reply, Command, RespType, RESP_TYPES, RedisArgument } from '../RESP/types'; import { StreamMessageRawReply, transformStreamMessageReply } from './generic-transformers'; -export type XInfoStreamRawReply = TuplesToMapReply<[ - [BlobStringReply<'length'>, NumberReply], - [BlobStringReply<'radix-tree-keys'>, NumberReply], - [BlobStringReply<'radix-tree-nodes'>, NumberReply], - [BlobStringReply<'last-generated-id'>, BlobStringReply], - [BlobStringReply<'max-deleted-entry-id'>, BlobStringReply], - [BlobStringReply<'entries-added'>, NumberReply], - [BlobStringReply<'recorded-first-entry-id'>, BlobStringReply], - [BlobStringReply<'groups'>, NumberReply], - [BlobStringReply<'first-entry'>, StreamMessageRawReply | NullReply], - [BlobStringReply<'last-entry'>, StreamMessageRawReply | NullReply] -]>; - export type XInfoStreamReply = TuplesToMapReply<[ [BlobStringReply<'length'>, NumberReply], [BlobStringReply<'radix-tree-keys'>, NumberReply], [BlobStringReply<'radix-tree-nodes'>, NumberReply], [BlobStringReply<'last-generated-id'>, BlobStringReply], + /** added in 7.2 */ [BlobStringReply<'max-deleted-entry-id'>, BlobStringReply], + /** added in 7.2 */ [BlobStringReply<'entries-added'>, NumberReply], + /** added in 7.2 */ [BlobStringReply<'recorded-first-entry-id'>, BlobStringReply], [BlobStringReply<'groups'>, NumberReply], [BlobStringReply<'first-entry'>, ReturnType | NullReply], @@ -34,22 +24,27 @@ export default { return ['XINFO', 'STREAM', key]; }, transformReply: { - 2(reply: Resp2Reply) { - return { - length: reply[1], - 'radix-tree-keys': reply[3], - 'radix-tree-nodes': reply[5], - 'last-generated-id': reply[7], - 'max-deleted-entry-id': reply[9], - 'entries-added': reply[11], - 'recorded-first-entry-id': reply[13], - groups: reply[15], - 'first-entry': transformEntry(reply[17]), - 'last-entry': transformEntry(reply[19]) - }; + // TODO: is there a "type safe" way to do it? + 2(reply: any) { + const parsedReply: Partial = {}; + + for (let i = 0; i < reply.length; i += 2) { + switch (reply[i]) { + case 'first-entry': + case 'last-entry': + parsedReply[reply[i] as ('first-entry' | 'last-entry')] = transformEntry(reply[i + 1]) as any; + break; + + default: + parsedReply[reply[i] as keyof typeof parsedReply] = reply[i + 1]; + break; + } + } + + return parsedReply as XInfoStreamReply['DEFAULT']; }, - 3(reply: any) { // TODO: is there a "type safe" way to do it? - if (reply instanceof Map) { + 3(reply: any) { + if (reply instanceof Map) { reply.set( 'first-entry', transformEntry(reply.get('first-entry')) diff --git a/packages/client/lib/commands/XPENDING_RANGE.spec.ts b/packages/client/lib/commands/XPENDING_RANGE.spec.ts index ef25b9840c..7fd2ae0b42 100644 --- a/packages/client/lib/commands/XPENDING_RANGE.spec.ts +++ b/packages/client/lib/commands/XPENDING_RANGE.spec.ts @@ -41,11 +41,10 @@ describe('XPENDING RANGE', () => { }); testUtils.testAll('xPendingRange', async client => { - const [, , id, , reply] = await Promise.all([ + const [, , id, reply] = await Promise.all([ client.xGroupCreate('key', 'group', '$', { MKSTREAM: true }), - client.xGroupCreateConsumer('key', 'group', 'consumer'), client.xAdd('key', '*', { field: 'value' }), client.xReadGroup('group', 'consumer', { key: 'key', diff --git a/packages/client/lib/commands/index.ts b/packages/client/lib/commands/index.ts index cc98529c59..efba9ad94a 100644 --- a/packages/client/lib/commands/index.ts +++ b/packages/client/lib/commands/index.ts @@ -66,6 +66,12 @@ import CLUSTER_SAVECONFIG from './CLUSTER_SAVECONFIG'; import CLUSTER_SET_CONFIG_EPOCH from './CLUSTER_SET-CONFIG-EPOCH'; import CLUSTER_SETSLOT from './CLUSTER_SETSLOT'; import CLUSTER_SLOTS from './CLUSTER_SLOTS'; +import COMMAND_COUNT from './COMMAND_COUNT'; +import COMMAND_GETKEYS from './COMMAND_GETKEYS'; +import COMMAND_GETKEYSANDFLAGS from './COMMAND_GETKEYSANDFLAGS'; +// import COMMAND_INFO from './COMMAND_INFO'; +// import COMMAND_LIST from './COMMAND_LIST'; +// import COMMAND from './COMMAND'; import CONFIG_GET from './CONFIG_GET'; import CONFIG_RESETASTAT from './CONFIG_RESETSTAT'; import CONFIG_REWRITE from './CONFIG_REWRITE'; @@ -388,6 +394,12 @@ type CLUSTER_SAVECONFIG = typeof import('./CLUSTER_SAVECONFIG').default; type CLUSTER_SET_CONFIG_EPOCH = typeof import('./CLUSTER_SET-CONFIG-EPOCH').default; type CLUSTER_SETSLOT = typeof import('./CLUSTER_SETSLOT').default; type CLUSTER_SLOTS = typeof import('./CLUSTER_SLOTS').default; +type COMMAND_COUNT = typeof import('./COMMAND_COUNT').default; +type COMMAND_GETKEYS = typeof import('./COMMAND_GETKEYS').default; +type COMMAND_GETKEYSANDFLAGS = typeof import('./COMMAND_GETKEYSANDFLAGS').default; +// type COMMAND_INFO = typeof import('./COMMAND_INFO').default; +// type COMMAND_LIST = typeof import('./COMMAND_LIST').default; +// type COMMAND = typeof import('./COMMAND').default; type CONFIG_GET = typeof import('./CONFIG_GET').default; type CONFIG_RESETASTAT = typeof import('./CONFIG_RESETSTAT').default; type CONFIG_REWRITE = typeof import('./CONFIG_REWRITE').default; @@ -778,6 +790,18 @@ type Commands = { clusterSetSlot: CLUSTER_SETSLOT; CLUSTER_SLOTS: CLUSTER_SLOTS; clusterSlots: CLUSTER_SLOTS; + COMMAND_COUNT: COMMAND_COUNT; + commandCount: COMMAND_COUNT; + COMMAND_GETKEYS: COMMAND_GETKEYS; + commandGetKeys: COMMAND_GETKEYS; + COMMAND_GETKEYSANDFLAGS: COMMAND_GETKEYSANDFLAGS; + commandGetKeysAndFlags: COMMAND_GETKEYSANDFLAGS; + // COMMAND_INFO: COMMAND_INFO; + // commandInfo: COMMAND_INFO; + // COMMAND_LIST: COMMAND_LIST; + // commandList: COMMAND_LIST; + // COMMAND: COMMAND; + // command: COMMAND; CONFIG_GET: CONFIG_GET; configGet: CONFIG_GET; CONFIG_RESETASTAT: CONFIG_RESETASTAT; @@ -1423,6 +1447,18 @@ export default { clusterSetSlot: CLUSTER_SETSLOT, CLUSTER_SLOTS, clusterSlots: CLUSTER_SLOTS, + COMMAND_COUNT, + commandCount: COMMAND_COUNT, + COMMAND_GETKEYS, + commandGetKeys: COMMAND_GETKEYS, + COMMAND_GETKEYSANDFLAGS, + commandGetKeysAndFlags: COMMAND_GETKEYSANDFLAGS, + // COMMAND_INFO, + // commandInfo: COMMAND_INFO, + // COMMAND_LIST, + // commandList: COMMAND_LIST, + // COMMAND, + // command: COMMAND, CONFIG_GET, configGet: CONFIG_GET, CONFIG_RESETASTAT,