diff --git a/docs/scan-iterators.md b/docs/scan-iterators.md index cfb7545e58..f8e317fcef 100644 --- a/docs/scan-iterators.md +++ b/docs/scan-iterators.md @@ -22,6 +22,7 @@ You can override the default options by providing a configuration object: ```typescript client.scanIterator({ + cursor: 0, // 0 by default TYPE: 'string', // `SCAN` only MATCH: 'patter*', COUNT: 100 diff --git a/docs/todo.md b/docs/todo.md index 157a7c8eaf..c6abedcf41 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1,21 +1,6 @@ -# Client - - Does `close`/`destory` actually close the connection from the Redis POV? Works with OSS, but what about Redis Enterprie? Docs: - [v4 to v5](./v4-to-v5.md) - Legacy mode - [Command Options](./command-options.md) - [RESP](./RESP.md) - -# Server - -- `HEXISTS`: accepts one field only, should be the same as `EXISTS` - -`String` -> `Double`: -- `INCRBYFLOAT` -- `HINCRBYFLOAT` -- `GEODIST` - -`Number` -> `Boolean`: -- `HSETNX` (deprecated) -- `SCRIPT EXISTS` diff --git a/docs/v4-to-v5.md b/docs/v4-to-v5.md index 5d4e2956a2..91d88c066e 100644 --- a/docs/v4-to-v5.md +++ b/docs/v4-to-v5.md @@ -169,6 +169,11 @@ Some command arguments/replies have changed to align more closely to data types - `CLUSTER LINKS`: `createTime` -> `create-time`, `sendBufferAllocated` -> `send-buffer-allocated`, `sendBufferUsed` -> `send-buffer-used` [^map-keys] - `TIME`: `Date` -> `[unixTimestamp: string, microseconds: string]` - `ZMPOP`: `{ elements: Array<{ member: string; score: number; }>; }` -> `{ members: Array<{ value: string; score: number; }>; }` to match other sorted set commands (e.g. `ZRANGE`, `ZSCAN`) +- `XGROUP_CREATECONSUMER`: [^boolean-to-number] +- `XGROUP_DESTROY`: [^boolean-to-number] +- `XINFO GROUPS`: `lastDeliveredId` -> `last-delivered-id` [^map-keys] +- `XINFO STREAM`: `radixTreeKeys` -> `radix-tree-keys`, `radixTreeNodes` -> `radix-tree-nodes`, `lastGeneratedId` -> `last-generated-id`, `maxDeletedEntryId` -> `max-deleted-entry-id`, `entriesAdded` -> `entries-added`, `recordedFirstEntryId` -> `recorded-first-entry-id`, `firstEntry` -> `first-entry`, `lastEntry` -> `last-entry` +- `XAUTOCLAIM`, `XCLAIM`, `XRANGE`, `XREVRANGE`: `Array<{ name: string; messages: Array<{ id: string; message: Record }>; }>` -> `Record }>>` [^enum-to-constants]: TODO diff --git a/packages/client/lib/RESP/types.ts b/packages/client/lib/RESP/types.ts index 4816f39d5a..53f4d8a742 100644 --- a/packages/client/lib/RESP/types.ts +++ b/packages/client/lib/RESP/types.ts @@ -6,7 +6,7 @@ export type RESP_TYPES = typeof RESP_TYPES; export type RespTypes = RESP_TYPES[keyof RESP_TYPES]; -type RespType< +export type RespType< RESP_TYPE extends RespTypes, DEFAULT, TYPES = never, @@ -114,7 +114,7 @@ type MapKeyValue = [key: BlobStringReply, value: unknown]; type MapTuples = Array; export type TuplesToMapReply = RespType< - RESP_TYPES['MAP'], + RESP_TYPES['MAP'], { [P in T[number] as P[0] extends BlobStringReply ? S : never]: P[1]; }, diff --git a/packages/client/lib/commands/BITPOS.ts b/packages/client/lib/commands/BITPOS.ts index 5f8a1031a4..5d6276dffc 100644 --- a/packages/client/lib/commands/BITPOS.ts +++ b/packages/client/lib/commands/BITPOS.ts @@ -13,11 +13,11 @@ export default { ) { const args = ['BITPOS', key, bit.toString()]; - if (typeof start === 'number') { + if (start !== undefined) { args.push(start.toString()); } - if (typeof end === 'number') { + if (end !== undefined) { args.push(end.toString()); } diff --git a/packages/client/lib/commands/LASTSAVE.spec.ts b/packages/client/lib/commands/LASTSAVE.spec.ts index db282374a9..224ad364d9 100644 --- a/packages/client/lib/commands/LASTSAVE.spec.ts +++ b/packages/client/lib/commands/LASTSAVE.spec.ts @@ -11,6 +11,9 @@ describe('LASTSAVE', () => { }); testUtils.testWithClient('client.lastSave', async client => { - assert.ok(typeof await client.lastSave() === 'number'); + assert.equal( + typeof await client.lastSave(), + 'number' + ); }, GLOBAL.SERVERS.OPEN); }); diff --git a/packages/client/lib/commands/LPOS_COUNT.ts b/packages/client/lib/commands/LPOS_COUNT.ts index 91bf602f39..1b057cff1f 100644 --- a/packages/client/lib/commands/LPOS_COUNT.ts +++ b/packages/client/lib/commands/LPOS_COUNT.ts @@ -12,13 +12,13 @@ export default { ) { const args = ['LPOS', key, element]; - if (typeof options?.RANK === 'number') { + if (options?.RANK !== undefined) { args.push('RANK', options.RANK.toString()); } args.push('COUNT', count.toString()); - if (typeof options?.MAXLEN === 'number') { + if (options?.MAXLEN !== undefined) { args.push('MAXLEN', options.MAXLEN.toString()); } diff --git a/packages/client/lib/commands/SADD.ts b/packages/client/lib/commands/SADD.ts index d3f164e7af..2ff5e9263c 100644 --- a/packages/client/lib/commands/SADD.ts +++ b/packages/client/lib/commands/SADD.ts @@ -1,12 +1,9 @@ import { RedisArgument, NumberReply, Command } from '../RESP/types'; -import { pushVariadicArguments } from './generic-transformers'; +import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers'; export default { FIRST_KEY_INDEX: 1, - transformArguments( - key: RedisArgument, - members: Array | RedisArgument - ) { + transformArguments(key: RedisArgument, members: RedisVariadicArgument) { return pushVariadicArguments(['SADD', key], members); }, transformReply: undefined as unknown as () => NumberReply diff --git a/packages/client/lib/commands/SDIFF.ts b/packages/client/lib/commands/SDIFF.ts index 895a48da26..918cbf7fa1 100644 --- a/packages/client/lib/commands/SDIFF.ts +++ b/packages/client/lib/commands/SDIFF.ts @@ -1,12 +1,10 @@ -import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; -import { pushVariadicArguments } from './generic-transformers'; +import { ArrayReply, BlobStringReply, Command } from '../RESP/types'; +import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers'; export default { FIRST_KEY_INDEX: 1, IS_READ_ONLY: true, - transformArguments( - keys: Array | RedisArgument - ) { + transformArguments(keys: RedisVariadicArgument) { return pushVariadicArguments(['SDIFF'], keys); }, transformReply: undefined as unknown as () => ArrayReply diff --git a/packages/client/lib/commands/SDIFFSTORE.ts b/packages/client/lib/commands/SDIFFSTORE.ts index 526469d69b..15f0ccb499 100644 --- a/packages/client/lib/commands/SDIFFSTORE.ts +++ b/packages/client/lib/commands/SDIFFSTORE.ts @@ -1,12 +1,9 @@ import { RedisArgument, NumberReply, Command } from '../RESP/types'; -import { pushVariadicArguments } from './generic-transformers'; +import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers'; export default { FIRST_KEY_INDEX: 1, - transformArguments( - destination: RedisArgument, - keys: Array | RedisArgument - ) { + transformArguments(destination: RedisArgument, keys: RedisVariadicArgument) { return pushVariadicArguments(['SDIFFSTORE', destination], keys); }, transformReply: undefined as unknown as () => NumberReply diff --git a/packages/client/lib/commands/SINTER.ts b/packages/client/lib/commands/SINTER.ts index d5c0fbc98d..f3f27de2e3 100644 --- a/packages/client/lib/commands/SINTER.ts +++ b/packages/client/lib/commands/SINTER.ts @@ -1,12 +1,10 @@ -import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; -import { pushVariadicArguments } from './generic-transformers'; +import { ArrayReply, BlobStringReply, Command } from '../RESP/types'; +import { RedisVariadicArgument, pushVariadicArguments } from './generic-transformers'; export default { FIRST_KEY_INDEX: 1, IS_READ_ONLY: true, - transformArguments( - keys: Array | RedisArgument - ) { + transformArguments(keys: RedisVariadicArgument) { return pushVariadicArguments(['SINTER'], keys); }, transformReply: undefined as unknown as () => ArrayReply diff --git a/packages/client/lib/commands/SINTERCARD.ts b/packages/client/lib/commands/SINTERCARD.ts index 41d4626249..626bc1048c 100644 --- a/packages/client/lib/commands/SINTERCARD.ts +++ b/packages/client/lib/commands/SINTERCARD.ts @@ -1,5 +1,5 @@ -import { RedisArgument, NumberReply, Command } from '../RESP/types'; -import { pushVariadicArgument } from './generic-transformers'; +import { NumberReply, Command } from '../RESP/types'; +import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers'; export interface SInterCardOptions { LIMIT?: number; @@ -9,7 +9,7 @@ export default { FIRST_KEY_INDEX: 2, IS_READ_ONLY: true, transformArguments( - keys: Array | RedisArgument, + keys: RedisVariadicArgument, options?: SInterCardOptions | number // `number` for backwards compatibility ) { const args = pushVariadicArgument(['SINTERCARD'], keys); diff --git a/packages/client/lib/commands/XACK.spec.ts b/packages/client/lib/commands/XACK.spec.ts index dd44debe2a..35eed37089 100644 --- a/packages/client/lib/commands/XACK.spec.ts +++ b/packages/client/lib/commands/XACK.spec.ts @@ -6,22 +6,22 @@ describe('XACK', () => { describe('transformArguments', () => { it('string', () => { assert.deepEqual( - XACK.transformArguments('key', 'group', '1-0'), - ['XACK', 'key', 'group', '1-0'] + XACK.transformArguments('key', 'group', '0-0'), + ['XACK', 'key', 'group', '0-0'] ); }); it('array', () => { assert.deepEqual( - XACK.transformArguments('key', 'group', ['1-0', '2-0']), - ['XACK', 'key', 'group', '1-0', '2-0'] + XACK.transformArguments('key', 'group', ['0-0', '1-0']), + ['XACK', 'key', 'group', '0-0', '1-0'] ); }); }); testUtils.testAll('xAck', async client => { assert.equal( - await client.xAck('key', 'group', '1-0'), + await client.xAck('key', 'group', '0-0'), 0 ); }, { diff --git a/packages/client/lib/commands/XAUTOCLAIM.ts b/packages/client/lib/commands/XAUTOCLAIM.ts index c32c3baf8d..b7a04734a3 100644 --- a/packages/client/lib/commands/XAUTOCLAIM.ts +++ b/packages/client/lib/commands/XAUTOCLAIM.ts @@ -1,39 +1,47 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; -// import { StreamMessagesReply, transformStreamMessagesReply } from './generic-transformers'; +import { RedisArgument, TuplesReply, BlobStringReply, ArrayReply, Command } from '../RESP/types'; +import { StreamMessagesRawReply, transformStreamMessagesReply } from './generic-transformers'; -// export const FIRST_KEY_INDEX = 1; +export interface XAutoClaimOptions { + COUNT?: number; +} -// export interface XAutoClaimOptions { -// COUNT?: number; -// } +export type XAutoClaimRawReply = TuplesReply<[ + nextId: BlobStringReply, + messages: StreamMessagesRawReply, + deletedMessages: ArrayReply +]>; -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument, -// consumer: RedisCommandArgument, -// minIdleTime: number, -// start: string, -// options?: XAutoClaimOptions -// ): RedisCommandArguments { -// const args = ['XAUTOCLAIM', key, group, consumer, minIdleTime.toString(), start]; +export default { + FIRST_KEY_INDEX: 1, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + group: RedisArgument, + consumer: RedisArgument, + minIdleTime: number, + start: RedisArgument, + options?: XAutoClaimOptions + ) { + const args = [ + 'XAUTOCLAIM', + key, + group, + consumer, + minIdleTime.toString(), + start + ]; -// if (options?.COUNT) { -// args.push('COUNT', options.COUNT.toString()); -// } + if (options?.COUNT) { + args.push('COUNT', options.COUNT.toString()); + } -// return args; -// } - -// type XAutoClaimRawReply = [RedisCommandArgument, Array]; - -// interface XAutoClaimReply { -// nextId: RedisCommandArgument; -// messages: StreamMessagesReply; -// } - -// export function transformReply(reply: XAutoClaimRawReply): XAutoClaimReply { -// return { -// nextId: reply[0], -// messages: transformStreamMessagesReply(reply[1]) -// }; -// } + return args; + }, + transformReply(reply: XAutoClaimRawReply) { + return { + nextId: reply[0], + messages: transformStreamMessagesReply(reply[1]), + deletedMessages: reply[2] + }; + } +} as const satisfies Command; diff --git a/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts b/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts index 3f6374d985..2dc0961bc2 100644 --- a/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts +++ b/packages/client/lib/commands/XAUTOCLAIM_JUSTID.ts @@ -1,25 +1,25 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; -// import { transformArguments as transformXAutoClaimArguments } from './XAUTOCLAIM'; +import { TuplesReply, BlobStringReply, ArrayReply, Command } from '../RESP/types'; +import XAUTOCLAIM from './XAUTOCLAIM'; -// export { FIRST_KEY_INDEX } from './XAUTOCLAIM'; +type XAutoClaimJustIdRawReply = TuplesReply<[ + nextId: BlobStringReply, + messages: ArrayReply, + deletedMessages: ArrayReply +]>; -// export function transformArguments(...args: Parameters): RedisCommandArguments { -// return [ -// ...transformXAutoClaimArguments(...args), -// 'JUSTID' -// ]; -// } - -// type XAutoClaimJustIdRawReply = [RedisCommandArgument, Array]; - -// interface XAutoClaimJustIdReply { -// nextId: RedisCommandArgument; -// messages: Array; -// } - -// export function transformReply(reply: XAutoClaimJustIdRawReply): XAutoClaimJustIdReply { -// return { -// nextId: reply[0], -// messages: reply[1] -// }; -// } +export default { + FIRST_KEY_INDEX: XAUTOCLAIM.FIRST_KEY_INDEX, + IS_READ_ONLY: XAUTOCLAIM.IS_READ_ONLY, + transformArguments(...args: Parameters) { + const redisArgs = XAUTOCLAIM.transformArguments(...args); + redisArgs.push('JUSTID'); + return redisArgs; + }, + transformReply(reply: XAutoClaimJustIdRawReply) { + return { + nextId: reply[0], + messages: reply[1], + deletedMessages: reply[2] + }; + } +} as const satisfies Command; diff --git a/packages/client/lib/commands/XCLAIM.spec.ts b/packages/client/lib/commands/XCLAIM.spec.ts index a9f6879cfa..ffe2deeaae 100644 --- a/packages/client/lib/commands/XCLAIM.spec.ts +++ b/packages/client/lib/commands/XCLAIM.spec.ts @@ -1,90 +1,106 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XCLAIM'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XCLAIM from './XCLAIM'; -// describe('XCLAIM', () => { -// describe('transformArguments', () => { -// it('single id (string)', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0'), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0'] -// ); -// }); +describe('XCLAIM', () => { + describe('transformArguments', () => { + it('single id (string)', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0'), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0'] + ); + }); -// it('multiple ids (array)', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, ['0-0', '1-0']), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', '1-0'] -// ); -// }); + it('multiple ids (array)', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, ['0-0', '1-0']), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', '1-0'] + ); + }); -// it('with IDLE', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0', { -// IDLE: 1 -// }), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1'] -// ); -// }); + it('with IDLE', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', { + IDLE: 1 + }), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1'] + ); + }); + + describe('with TIME', () => { + it('number', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', { + TIME: 1 + }), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', '1'] + ); + }); + + it('Date', () => { + const d = new Date(); + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', { + TIME: d + }), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', d.getTime().toString()] + ); + }); + }); -// it('with TIME (number)', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0', { -// TIME: 1 -// }), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', '1'] -// ); -// }); + it('with RETRYCOUNT', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', { + RETRYCOUNT: 1 + }), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'RETRYCOUNT', '1'] + ); + }); -// it('with TIME (date)', () => { -// const d = new Date(); -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0', { -// TIME: d -// }), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'TIME', d.getTime().toString()] -// ); -// }); + it('with FORCE', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', { + FORCE: true + }), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'FORCE'] + ); + }); -// it('with RETRYCOUNT', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0', { -// RETRYCOUNT: 1 -// }), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'RETRYCOUNT', '1'] -// ); -// }); + it('with LASTID', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', { + LASTID: '0-0' + }), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'LASTID', '0-0'] + ); + }); -// it('with FORCE', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0', { -// FORCE: true -// }), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'FORCE'] -// ); -// }); + it('with IDLE, TIME, RETRYCOUNT, FORCE, LASTID', () => { + assert.deepEqual( + XCLAIM.transformArguments('key', 'group', 'consumer', 1, '0-0', { + IDLE: 1, + TIME: 1, + RETRYCOUNT: 1, + FORCE: true, + LASTID: '0-0' + }), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1', 'TIME', '1', 'RETRYCOUNT', '1', 'FORCE', 'LASTID', '0-0'] + ); + }); + }); -// it('with IDLE, TIME, RETRYCOUNT, FORCE, JUSTID', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0', { -// IDLE: 1, -// TIME: 1, -// RETRYCOUNT: 1, -// FORCE: true -// }), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'IDLE', '1', 'TIME', '1', 'RETRYCOUNT', '1', 'FORCE'] -// ); -// }); -// }); + // TODO: test with messages + testUtils.testAll('xClaim', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xClaim('key', 'group', 'consumer', 1, '0-0') + ]); -// testUtils.testWithClient('client.xClaim', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); - -// assert.deepEqual( -// await client.xClaim('key', 'group', 'consumer', 1, '0-0'), -// [] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.deepEqual(reply, []); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XCLAIM.ts b/packages/client/lib/commands/XCLAIM.ts index 6c1328441a..2c04123976 100644 --- a/packages/client/lib/commands/XCLAIM.ts +++ b/packages/client/lib/commands/XCLAIM.ts @@ -1,48 +1,54 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; -// import { pushVariadicArguments } from './generic-transformers'; +import { RedisArgument, Command } from '../RESP/types'; +import { RedisVariadicArgument, pushVariadicArguments, transformStreamMessagesReply } from './generic-transformers'; -// export const FIRST_KEY_INDEX = 1; +export interface XClaimOptions { + IDLE?: number; + TIME?: number | Date; + RETRYCOUNT?: number; + FORCE?: boolean; + LASTID?: RedisArgument; +} -// export interface XClaimOptions { -// IDLE?: number; -// TIME?: number | Date; -// RETRYCOUNT?: number; -// FORCE?: true; -// } +export default { + FIRST_KEY_INDEX: 1, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + group: RedisArgument, + consumer: RedisArgument, + minIdleTime: number, + id: RedisVariadicArgument, + options?: XClaimOptions + ) { + const args = pushVariadicArguments( + ['XCLAIM', key, group, consumer, minIdleTime.toString()], + id + ); -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument, -// consumer: RedisCommandArgument, -// minIdleTime: number, -// id: RedisCommandArgument | Array, -// options?: XClaimOptions -// ): RedisCommandArguments { -// const args = pushVariadicArguments( -// ['XCLAIM', key, group, consumer, minIdleTime.toString()], -// id -// ); + if (options?.IDLE !== undefined) { + args.push('IDLE', options.IDLE.toString()); + } -// if (options?.IDLE) { -// args.push('IDLE', options.IDLE.toString()); -// } + if (options?.TIME !== undefined) { + args.push( + 'TIME', + (options.TIME instanceof Date ? options.TIME.getTime() : options.TIME).toString() + ); + } -// if (options?.TIME) { -// args.push( -// 'TIME', -// (typeof options.TIME === 'number' ? options.TIME : options.TIME.getTime()).toString() -// ); -// } + if (options?.RETRYCOUNT !== undefined) { + args.push('RETRYCOUNT', options.RETRYCOUNT.toString()); + } -// if (options?.RETRYCOUNT) { -// args.push('RETRYCOUNT', options.RETRYCOUNT.toString()); -// } + if (options?.FORCE) { + args.push('FORCE'); + } -// if (options?.FORCE) { -// args.push('FORCE'); -// } + if (options?.LASTID !== undefined) { + args.push('LASTID', options.LASTID); + } -// return args; -// } - -// export { transformStreamMessagesReply as transformReply } from './generic-transformers'; + return args; + }, + transformReply: transformStreamMessagesReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts b/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts index 88fe59084b..3110293e85 100644 --- a/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts +++ b/packages/client/lib/commands/XCLAIM_JUSTID.spec.ts @@ -1,23 +1,24 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XCLAIM_JUSTID'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XCLAIM_JUSTID from './XCLAIM_JUSTID'; -// describe('XCLAIM JUSTID', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer', 1, '0-0'), -// ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'JUSTID'] -// ); -// }); +describe('XCLAIM JUSTID', () => { + it('transformArguments', () => { + assert.deepEqual( + XCLAIM_JUSTID.transformArguments('key', 'group', 'consumer', 1, '0-0'), + ['XCLAIM', 'key', 'group', 'consumer', '1', '0-0', 'JUSTID'] + ); + }); -// testUtils.testWithClient('client.xClaimJustId', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); + // TODO: test with messages + testUtils.testWithClient('client.xClaimJustId', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xClaimJustId('key', 'group', 'consumer', 1, '0-0') + ]); -// assert.deepEqual( -// await client.xClaimJustId('key', 'group', 'consumer', 1, '0-0'), -// [] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.deepEqual(reply, []); + }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/client/lib/commands/XCLAIM_JUSTID.ts b/packages/client/lib/commands/XCLAIM_JUSTID.ts index 7c011e692f..6200c9106e 100644 --- a/packages/client/lib/commands/XCLAIM_JUSTID.ts +++ b/packages/client/lib/commands/XCLAIM_JUSTID.ts @@ -1,13 +1,13 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; -// import { transformArguments as transformXClaimArguments } from './XCLAIM'; +import { ArrayReply, BlobStringReply, Command } from '../RESP/types'; +import XCLAIM from './XCLAIM'; -// export { FIRST_KEY_INDEX } from './XCLAIM'; - -// export function transformArguments(...args: Parameters): RedisCommandArguments { -// return [ -// ...transformXClaimArguments(...args), -// 'JUSTID' -// ]; -// } - -// export declare function transformReply(): Array; +export default { + FIRST_KEY_INDEX: XCLAIM.FIRST_KEY_INDEX, + IS_READ_ONLY: XCLAIM.IS_READ_ONLY, + transformArguments(...args: Parameters) { + const redisArgs = XCLAIM.transformArguments(...args); + redisArgs.push('JUSTID'); + return redisArgs; + }, + transformReply: undefined as unknown as () => ArrayReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/XGROUP_CREATE.spec.ts b/packages/client/lib/commands/XGROUP_CREATE.spec.ts index 831db73e68..3428f05251 100644 --- a/packages/client/lib/commands/XGROUP_CREATE.spec.ts +++ b/packages/client/lib/commands/XGROUP_CREATE.spec.ts @@ -1,32 +1,44 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XGROUP_CREATE'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import { transformArguments } from './XGROUP_CREATE'; -// describe('XGROUP CREATE', () => { -// describe('transformArguments', () => { -// it('simple', () => { -// assert.deepEqual( -// transformArguments('key', 'group', '$'), -// ['XGROUP', 'CREATE', 'key', 'group', '$'] -// ); -// }); +describe('XGROUP CREATE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + transformArguments('key', 'group', '$'), + ['XGROUP', 'CREATE', 'key', 'group', '$'] + ); + }); -// it('with MKSTREAM', () => { -// assert.deepEqual( -// transformArguments('key', 'group', '$', { -// MKSTREAM: true -// }), -// ['XGROUP', 'CREATE', 'key', 'group', '$', 'MKSTREAM'] -// ); -// }); -// }); + it('with MKSTREAM', () => { + assert.deepEqual( + transformArguments('key', 'group', '$', { + MKSTREAM: true + }), + ['XGROUP', 'CREATE', 'key', 'group', '$', 'MKSTREAM'] + ); + }); -// testUtils.testWithClient('client.xGroupCreate', async client => { -// assert.equal( -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }), -// 'OK' -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + it('with ENTRIESREAD', () => { + assert.deepEqual( + transformArguments('key', 'group', '$', { + ENTRIESREAD: 1 + }), + ['XGROUP', 'CREATE', 'key', 'group', '$', 'ENTRIESREAD', '1'] + ); + }); + }); + + testUtils.testAll('xGroupCreate', async client => { + assert.equal( + await client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + 'OK' + ); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.SERVERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XGROUP_CREATE.ts b/packages/client/lib/commands/XGROUP_CREATE.ts index def2bf39eb..a04fcbeb04 100644 --- a/packages/client/lib/commands/XGROUP_CREATE.ts +++ b/packages/client/lib/commands/XGROUP_CREATE.ts @@ -1,24 +1,34 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; -// export const FIRST_KEY_INDEX = 2; +export interface XGroupCreateOptions { + MKSTREAM?: boolean; + /** + * added in 7.0 + */ + ENTRIESREAD?: number; +} -// interface XGroupCreateOptions { -// MKSTREAM?: true; -// } +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + group: RedisArgument, + id: RedisArgument, + options?: XGroupCreateOptions + ) { + const args = ['XGROUP', 'CREATE', key, group, id]; -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument, -// id: RedisCommandArgument, -// options?: XGroupCreateOptions -// ): RedisCommandArguments { -// const args = ['XGROUP', 'CREATE', key, group, id]; + if (options?.MKSTREAM) { + args.push('MKSTREAM'); + } -// if (options?.MKSTREAM) { -// args.push('MKSTREAM'); -// } + if (options?.ENTRIESREAD) { + args.push('ENTRIESREAD', options.ENTRIESREAD.toString()); + } -// return args; -// } + return args; + }, + transformReply: undefined as unknown as () => SimpleStringReply<'OK'> +} as const satisfies Command; -// export declare function transformReply(): RedisCommandArgument; diff --git a/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts b/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts index 1338b8837a..e959462c22 100644 --- a/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts +++ b/packages/client/lib/commands/XGROUP_CREATECONSUMER.spec.ts @@ -1,25 +1,28 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XGROUP_CREATECONSUMER'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XGROUP_CREATECONSUMER from './XGROUP_CREATECONSUMER'; -// describe('XGROUP CREATECONSUMER', () => { -// testUtils.isVersionGreaterThanHook([6, 2]); +describe('XGROUP CREATECONSUMER', () => { + testUtils.isVersionGreaterThanHook([6, 2]); -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer'), -// ['XGROUP', 'CREATECONSUMER', 'key', 'group', 'consumer'] -// ); -// }); + it('transformArguments', () => { + assert.deepEqual( + XGROUP_CREATECONSUMER.transformArguments('key', 'group', 'consumer'), + ['XGROUP', 'CREATECONSUMER', 'key', 'group', 'consumer'] + ); + }); -// testUtils.testWithClient('client.xGroupCreateConsumer', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); + testUtils.testAll('xGroupCreateConsumer', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xGroupCreateConsumer('key', 'group', 'consumer') + ]); -// assert.equal( -// await client.xGroupCreateConsumer('key', 'group', 'consumer'), -// true -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.equal(reply, 1); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts b/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts index 8fb9ad2ad3..8fd21ca60d 100644 --- a/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts +++ b/packages/client/lib/commands/XGROUP_CREATECONSUMER.ts @@ -1,13 +1,14 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, Command, NumberReply } from '../RESP/types'; -// export const FIRST_KEY_INDEX = 2; - -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument, -// consumer: RedisCommandArgument -// ): RedisCommandArguments { -// return ['XGROUP', 'CREATECONSUMER', key, group, consumer]; -// } - -// export { transformBooleanReply as transformReply } from './generic-transformers'; +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + group: RedisArgument, + consumer: RedisArgument + ) { + return ['XGROUP', 'CREATECONSUMER', key, group, consumer]; + }, + transformReply: undefined as unknown as () => NumberReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts b/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts index c1704b5619..7ec59f90c7 100644 --- a/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts +++ b/packages/client/lib/commands/XGROUP_DELCONSUMER.spec.ts @@ -1,23 +1,26 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XGROUP_DELCONSUMER'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XGROUP_DELCONSUMER from './XGROUP_DELCONSUMER'; -// describe('XGROUP DELCONSUMER', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key', 'group', 'consumer'), -// ['XGROUP', 'DELCONSUMER', 'key', 'group', 'consumer'] -// ); -// }); +describe('XGROUP DELCONSUMER', () => { + it('transformArguments', () => { + assert.deepEqual( + XGROUP_DELCONSUMER.transformArguments('key', 'group', 'consumer'), + ['XGROUP', 'DELCONSUMER', 'key', 'group', 'consumer'] + ); + }); -// testUtils.testWithClient('client.xGroupDelConsumer', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); + testUtils.testAll('xGroupDelConsumer', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xGroupDelConsumer('key', 'group', 'consumer') + ]); -// assert.equal( -// await client.xGroupDelConsumer('key', 'group', 'consumer'), -// 0 -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.equal(reply, 0); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XGROUP_DELCONSUMER.ts b/packages/client/lib/commands/XGROUP_DELCONSUMER.ts index ad54beaf9d..bb10174e1c 100644 --- a/packages/client/lib/commands/XGROUP_DELCONSUMER.ts +++ b/packages/client/lib/commands/XGROUP_DELCONSUMER.ts @@ -11,3 +11,18 @@ // } // export declare function transformReply(): number; + +import { RedisArgument, NumberReply, Command } from '../RESP/types'; + +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + group: RedisArgument, + consumer: RedisArgument + ) { + return ['XGROUP', 'DELCONSUMER', key, group, consumer]; + }, + transformReply: undefined as unknown as () => NumberReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/XGROUP_DESTROY.spec.ts b/packages/client/lib/commands/XGROUP_DESTROY.spec.ts index 3e729337ae..4d7bd9ad2e 100644 --- a/packages/client/lib/commands/XGROUP_DESTROY.spec.ts +++ b/packages/client/lib/commands/XGROUP_DESTROY.spec.ts @@ -1,23 +1,26 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XGROUP_DESTROY'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XGROUP_DESTROY from './XGROUP_DESTROY'; -// describe('XGROUP DESTROY', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key', 'group'), -// ['XGROUP', 'DESTROY', 'key', 'group'] -// ); -// }); +describe('XGROUP DESTROY', () => { + it('transformArguments', () => { + assert.deepEqual( + XGROUP_DESTROY.transformArguments('key', 'group'), + ['XGROUP', 'DESTROY', 'key', 'group'] + ); + }); -// testUtils.testWithClient('client.xGroupDestroy', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); + testUtils.testAll('xGroupDestroy', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xGroupDestroy('key', 'group') + ]); -// assert.equal( -// await client.xGroupDestroy('key', 'group'), -// true -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.equal(reply, 1); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XGROUP_DESTROY.ts b/packages/client/lib/commands/XGROUP_DESTROY.ts index 077afba4dc..6c14d9ae2b 100644 --- a/packages/client/lib/commands/XGROUP_DESTROY.ts +++ b/packages/client/lib/commands/XGROUP_DESTROY.ts @@ -1,12 +1,13 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, NumberReply, Command } from '../RESP/types'; -// export const FIRST_KEY_INDEX = 2; - -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument -// ): RedisCommandArguments { -// return ['XGROUP', 'DESTROY', key, group]; -// } - -// export { transformBooleanReply as transformReply } from './generic-transformers'; +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + group: RedisArgument + ) { + return ['XGROUP', 'DESTROY', key, group]; + }, + transformReply: undefined as unknown as () => NumberReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/XGROUP_SETID.spec.ts b/packages/client/lib/commands/XGROUP_SETID.spec.ts index 6f05802ab0..e0d920627c 100644 --- a/packages/client/lib/commands/XGROUP_SETID.spec.ts +++ b/packages/client/lib/commands/XGROUP_SETID.spec.ts @@ -1,23 +1,26 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XGROUP_SETID'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XGROUP_SETID from './XGROUP_SETID'; -// describe('XGROUP SETID', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key', 'group', '0'), -// ['XGROUP', 'SETID', 'key', 'group', '0'] -// ); -// }); +describe('XGROUP SETID', () => { + it('transformArguments', () => { + assert.deepEqual( + XGROUP_SETID.transformArguments('key', 'group', '0'), + ['XGROUP', 'SETID', 'key', 'group', '0'] + ); + }); -// testUtils.testWithClient('client.xGroupSetId', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); + testUtils.testAll('xGroupSetId', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xGroupSetId('key', 'group', '0') + ]); -// assert.equal( -// await client.xGroupSetId('key', 'group', '0'), -// 'OK' -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.equal(reply, 'OK'); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XGROUP_SETID.ts b/packages/client/lib/commands/XGROUP_SETID.ts index 65e1e257fb..a23b414433 100644 --- a/packages/client/lib/commands/XGROUP_SETID.ts +++ b/packages/client/lib/commands/XGROUP_SETID.ts @@ -1,13 +1,26 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; -// export const FIRST_KEY_INDEX = 2; +export interface XGroupSetIdOptions { + /** added in 7.0 */ + ENTRIESREAD?: number; +} -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument, -// id: RedisCommandArgument -// ): RedisCommandArguments { -// return ['XGROUP', 'SETID', key, group, id]; -// } +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + group: RedisArgument, + id: RedisArgument, + options?: XGroupSetIdOptions + ) { + const args = ['XGROUP', 'SETID', key, group, id]; -// export declare function transformReply(): RedisCommandArgument; + if (options?.ENTRIESREAD) { + args.push('ENTRIESREAD', options.ENTRIESREAD.toString()); + } + + return args; + }, + transformReply: undefined as unknown as () => SimpleStringReply<'OK'> +} as const satisfies Command; diff --git a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts index 64f926dec1..e57ed72d8e 100644 --- a/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts +++ b/packages/client/lib/commands/XINFO_CONSUMERS.spec.ts @@ -1,43 +1,34 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments, transformReply } from './XINFO_CONSUMERS'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XINFO_CONSUMERS from './XINFO_CONSUMERS'; -// describe('XINFO CONSUMERS', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key', 'group'), -// ['XINFO', 'CONSUMERS', 'key', 'group'] -// ); -// }); +describe('XINFO CONSUMERS', () => { + it('transformArguments', () => { + assert.deepEqual( + XINFO_CONSUMERS.transformArguments('key', 'group'), + ['XINFO', 'CONSUMERS', 'key', 'group'] + ); + }); -// it('transformReply', () => { -// assert.deepEqual( -// transformReply([ -// ['name', 'Alice', 'pending', 1, 'idle', 9104628, 'inactive', 9281221], -// ['name', 'Bob', 'pending', 1, 'idle', 83841983, 'inactive', 7213871] -// ]), -// [{ -// name: 'Alice', -// pending: 1, -// idle: 9104628, -// inactive: 9281221, -// }, { -// name: 'Bob', -// pending: 1, -// idle: 83841983, -// inactive: 7213871, -// }] -// ); -// }); + testUtils.testAll('xInfoConsumers', async client => { + const [, , reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xGroupCreateConsumer('key', 'group', 'consumer'), + client.xInfoConsumers('key', 'group') + ]); -// testUtils.testWithClient('client.xInfoConsumers', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); - -// assert.deepEqual( -// await client.xInfoConsumers('key', 'group'), -// [] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + for (const consumer of reply) { + assert.equal(typeof consumer.name, 'string'); + assert.equal(typeof consumer.pending, 'number'); + assert.equal(typeof consumer.idle, 'number'); + if (testUtils.isVersionGreaterThan([7, 2])) { + assert.equal(typeof consumer.inactive, 'number'); + } + } + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XINFO_CONSUMERS.ts b/packages/client/lib/commands/XINFO_CONSUMERS.ts index c6b3b99f18..81da67d161 100644 --- a/packages/client/lib/commands/XINFO_CONSUMERS.ts +++ b/packages/client/lib/commands/XINFO_CONSUMERS.ts @@ -1,28 +1,31 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, Resp2Reply, Command } from '../RESP/types'; -// export const FIRST_KEY_INDEX = 2; +export type XInfoConsumersReply = ArrayReply, BlobStringReply], + [BlobStringReply<'pending'>, NumberReply], + [BlobStringReply<'idle'>, NumberReply], + /** added in 7.2 */ + [BlobStringReply<'inactive'>, NumberReply] +]>>; -// export const IS_READ_ONLY = true; - -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument -// ): RedisCommandArguments { -// return ['XINFO', 'CONSUMERS', key, group]; -// } - -// type XInfoConsumersReply = Array<{ -// name: RedisCommandArgument; -// pending: number; -// idle: number; -// inactive: number; -// }>; - -// export function transformReply(rawReply: Array): XInfoConsumersReply { -// return rawReply.map(consumer => ({ -// name: consumer[1], -// pending: consumer[3], -// idle: consumer[5], -// inactive: consumer[7] -// })); -// } +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: true, + transformArguments( + key: RedisArgument, + group: RedisArgument + ) { + return ['XINFO', 'CONSUMERS', key, group]; + }, + transformReply: { + 2: (reply: Resp2Reply) => { + return reply.map(consumer => ({ + name: consumer[1], + pending: consumer[3], + idle: consumer[5], + inactive: consumer[7] + })); + }, + 3: undefined as unknown as () => XInfoConsumersReply + } +} as const satisfies Command; diff --git a/packages/client/lib/commands/XINFO_GROUPS.spec.ts b/packages/client/lib/commands/XINFO_GROUPS.spec.ts index 7380251db6..7ac02972d6 100644 --- a/packages/client/lib/commands/XINFO_GROUPS.spec.ts +++ b/packages/client/lib/commands/XINFO_GROUPS.spec.ts @@ -1,48 +1,36 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments, transformReply } from './XINFO_GROUPS'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XINFO_GROUPS from './XINFO_GROUPS'; -// describe('XINFO GROUPS', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key'), -// ['XINFO', 'GROUPS', 'key'] -// ); -// }); +describe('XINFO GROUPS', () => { + it('transformArguments', () => { + assert.deepEqual( + XINFO_GROUPS.transformArguments('key'), + ['XINFO', 'GROUPS', 'key'] + ); + }); -// it('transformReply', () => { -// assert.deepEqual( -// transformReply([ -// ['name', 'mygroup', 'consumers', 2, 'pending', 2, 'last-delivered-id', '1588152489012-0'], -// ['name', 'some-other-group', 'consumers', 1, 'pending', 0, 'last-delivered-id', '1588152498034-0'] -// ]), -// [{ -// name: 'mygroup', -// consumers: 2, -// pending: 2, -// lastDeliveredId: '1588152489012-0' -// }, { -// name: 'some-other-group', -// consumers: 1, -// pending: 0, -// lastDeliveredId: '1588152498034-0' -// }] -// ); -// }); - -// testUtils.testWithClient('client.xInfoGroups', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); - -// assert.deepEqual( -// await client.xInfoGroups('key'), -// [{ -// name: 'group', -// consumers: 0, -// pending: 0, -// lastDeliveredId: '0-0' -// }] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + testUtils.testAll('xInfoGroups', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xInfoGroups('key') + ]); + + assert.deepEqual( + reply, + [{ + name: 'group', + consumers: 0, + pending: 0, + 'last-delivered-id': '0-0', + 'entries-read': null, + lag: 0 + }] + ); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XINFO_GROUPS.ts b/packages/client/lib/commands/XINFO_GROUPS.ts index 4dac9eed85..e2e566d0e2 100644 --- a/packages/client/lib/commands/XINFO_GROUPS.ts +++ b/packages/client/lib/commands/XINFO_GROUPS.ts @@ -1,25 +1,33 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, ArrayReply, TuplesToMapReply, BlobStringReply, NumberReply, Resp2Reply, Command, NullReply } from '../RESP/types'; -// export const FIRST_KEY_INDEX = 2; +export type XInfoGroupsReply = ArrayReply, BlobStringReply], + [BlobStringReply<'consumers'>, NumberReply], + [BlobStringReply<'pending'>, NumberReply], + [BlobStringReply<'last-delivered-id'>, NumberReply], + /** added in 7.0 */ + [BlobStringReply<'entries-read'>, NumberReply | NullReply], + /** added in 7.0 */ + [BlobStringReply<'lag'>, NumberReply], +]>>; -// export const IS_READ_ONLY = true; - -// export function transformArguments(key: RedisCommandArgument): RedisCommandArguments { -// return ['XINFO', 'GROUPS', key]; -// } - -// type XInfoGroupsReply = Array<{ -// name: RedisCommandArgument; -// consumers: number; -// pending: number; -// lastDeliveredId: RedisCommandArgument; -// }>; - -// export function transformReply(rawReply: Array): XInfoGroupsReply { -// return rawReply.map(group => ({ -// name: group[1], -// consumers: group[3], -// pending: group[5], -// lastDeliveredId: group[7] -// })); -// } +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: true, + transformArguments(key: RedisArgument) { + return ['XINFO', 'GROUPS', key]; + }, + transformReply: { + 2: (reply: Resp2Reply) => { + return reply.map(group => ({ + name: group[1], + consumers: group[3], + pending: group[5], + 'last-delivered-id': group[7], + 'entries-read': group[9], + lag: group[11] + })); + }, + 3: undefined as unknown as () => XInfoGroupsReply + } +} as const satisfies Command; diff --git a/packages/client/lib/commands/XINFO_STREAM.spec.ts b/packages/client/lib/commands/XINFO_STREAM.spec.ts index a73c460708..0c13f27c41 100644 --- a/packages/client/lib/commands/XINFO_STREAM.spec.ts +++ b/packages/client/lib/commands/XINFO_STREAM.spec.ts @@ -1,72 +1,34 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments, transformReply } from './XINFO_STREAM'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XINFO_STREAM from './XINFO_STREAM'; -// describe('XINFO STREAM', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key'), -// ['XINFO', 'STREAM', 'key'] -// ); -// }); +describe('XINFO STREAM', () => { + it('transformArguments', () => { + assert.deepEqual( + XINFO_STREAM.transformArguments('key'), + ['XINFO', 'STREAM', 'key'] + ); + }); -// it('transformReply', () => { -// assert.deepEqual( -// transformReply([ -// 'length', 2, -// 'radix-tree-keys', 1, -// 'radix-tree-nodes', 2, -// 'last-generated-id', '1538385846314-0', -// 'groups', 2, -// 'first-entry', ['1538385820729-0', ['foo', 'bar']], -// 'last-entry', ['1538385846314-0', ['field', 'value']] -// ]), -// { -// length: 2, -// radixTreeKeys: 1, -// radixTreeNodes: 2, -// groups: 2, -// lastGeneratedId: '1538385846314-0', -// firstEntry: { -// id: '1538385820729-0', -// message: Object.create(null, { -// foo: { -// value: 'bar', -// configurable: true, -// enumerable: true -// } -// }) -// }, -// lastEntry: { -// id: '1538385846314-0', -// message: Object.create(null, { -// field: { -// value: 'value', -// configurable: true, -// enumerable: true -// } -// }) -// } -// } -// ); -// }); + testUtils.testAll('xInfoStream', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xInfoStream('key') + ]); -// testUtils.testWithClient('client.xInfoStream', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); - -// assert.deepEqual( -// await client.xInfoStream('key'), -// { -// length: 0, -// radixTreeKeys: 0, -// radixTreeNodes: 1, -// groups: 1, -// lastGeneratedId: '0-0', -// firstEntry: null, -// lastEntry: null -// } -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.deepEqual(reply, { + length: 0, + radixTreeKeys: 0, + radixTreeNodes: 1, + groups: 1, + lastGeneratedId: '0-0', + firstEntry: null, + lastEntry: null + }); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XINFO_STREAM.ts b/packages/client/lib/commands/XINFO_STREAM.ts index 32fb83fe0a..2dde1ea1a4 100644 --- a/packages/client/lib/commands/XINFO_STREAM.ts +++ b/packages/client/lib/commands/XINFO_STREAM.ts @@ -62,3 +62,80 @@ // return parsedReply as XInfoStreamReply; // } + +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], + [BlobStringReply<'max-deleted-entry-id'>, BlobStringReply], + [BlobStringReply<'entries-added'>, NumberReply], + [BlobStringReply<'recorded-first-entry-id'>, BlobStringReply], + [BlobStringReply<'groups'>, NumberReply], + [BlobStringReply<'first-entry'>, ReturnType | NullReply], + [BlobStringReply<'last-entry'>, ReturnType | NullReply] +]>; + +export default { + FIRST_KEY_INDEX: 2, + IS_READ_ONLY: true, + transformArguments(key: RedisArgument) { + 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]) + }; + }, + 3(reply: any) { // TODO: is there a "type safe" way to do it? + if (reply instanceof Map) { + reply.set( + 'first-entry', + transformEntry(reply.get('first-entry')) + ); + reply.set( + 'last-entry', + transformEntry(reply.get('last-entry')) + ); + } else if (reply instanceof Array) { + reply[17] = transformEntry(reply[17]); + reply[19] = transformEntry(reply[19]); + } else { + reply['first-entry'] = transformEntry(reply['first-entry']); + reply['last-entry'] = transformEntry(reply['last-entry']); + } + + return reply as XInfoStreamReply; + } + } +} as const satisfies Command; + +function transformEntry(entry: StreamMessageRawReply | NullReply) { + return entry === null ? null : transformStreamMessageReply(entry); +} diff --git a/packages/client/lib/commands/XPENDING.spec.ts b/packages/client/lib/commands/XPENDING.spec.ts index bfa36d01e3..993245a5d8 100644 --- a/packages/client/lib/commands/XPENDING.spec.ts +++ b/packages/client/lib/commands/XPENDING.spec.ts @@ -1,62 +1,60 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XPENDING'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XPENDING from './XPENDING'; -// describe('XPENDING', () => { -// describe('transformArguments', () => { -// it('transformArguments', () => { -// assert.deepEqual( -// transformArguments('key', 'group'), -// ['XPENDING', 'key', 'group'] -// ); -// }); -// }); +describe('XPENDING', () => { + describe('transformArguments', () => { + it('transformArguments', () => { + assert.deepEqual( + XPENDING.transformArguments('key', 'group'), + ['XPENDING', 'key', 'group'] + ); + }); + }); -// describe('client.xPending', () => { -// testUtils.testWithClient('simple', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); + describe('client.xPending', () => { + testUtils.testWithClient('simple', async client => { + const [, reply] = await Promise.all([ + client.xGroupCreate('key', 'group', '$', { + MKSTREAM: true + }), + client.xPending('key', 'group') + ]); -// assert.deepEqual( -// await client.xPending('key', 'group'), -// { -// pending: 0, -// firstId: null, -// lastId: null, -// consumers: null -// } -// ); -// }, GLOBAL.SERVERS.OPEN); + assert.deepEqual(reply, { + pending: 0, + firstId: null, + lastId: null, + consumers: null + }); + }, GLOBAL.SERVERS.OPEN); -// testUtils.testWithClient('with consumers', async client => { -// const [,, id] = 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', -// id: '>' -// }) -// ]); + testUtils.testWithClient('with consumers', async client => { + 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', + id: '>' + }), + client.xPending('key', 'group') + ]); -// assert.deepEqual( -// await client.xPending('key', 'group'), -// { -// pending: 1, -// firstId: id, -// lastId: id, -// consumers: [{ -// name: 'consumer', -// deliveriesCounter: 1 -// }] -// } -// ); -// }, { -// ...GLOBAL.SERVERS.OPEN, -// minimumDockerVersion: [6, 2] -// }); -// }); -// }); + assert.deepEqual(reply, { + pending: 1, + firstId: id, + lastId: id, + consumers: [{ + name: 'consumer', + deliveriesCounter: 1 + }] + }); + }, { + ...GLOBAL.SERVERS.OPEN, + minimumDockerVersion: [6, 2] + }); + }); +}); diff --git a/packages/client/lib/commands/XPENDING.ts b/packages/client/lib/commands/XPENDING.ts index 215295afd2..efe07ceefb 100644 --- a/packages/client/lib/commands/XPENDING.ts +++ b/packages/client/lib/commands/XPENDING.ts @@ -1,44 +1,30 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, BlobStringReply, NullReply, TuplesReply, NumberReply, Command, ArrayReply } from '../RESP/types'; -// export const FIRST_KEY_INDEX = 1; +type XPendingRawReply = TuplesReply<[ + pending: NumberReply, + firstId: BlobStringReply | NullReply, + lastId: BlobStringReply | NullReply, + consumers: ArrayReply> | NullReply +]>; -// export const IS_READ_ONLY = true; - -// export function transformArguments( -// key: RedisCommandArgument, -// group: RedisCommandArgument -// ): RedisCommandArguments { -// return ['XPENDING', key, group]; -// } - -// type XPendingRawReply = [ -// pending: number, -// firstId: RedisCommandArgument | null, -// lastId: RedisCommandArgument | null, -// consumers: Array<[ -// name: RedisCommandArgument, -// deliveriesCounter: RedisCommandArgument -// ]> | null -// ]; - -// interface XPendingReply { -// pending: number; -// firstId: RedisCommandArgument | null; -// lastId: RedisCommandArgument | null; -// consumers: Array<{ -// name: RedisCommandArgument; -// deliveriesCounter: number; -// }> | null; -// } - -// export function transformReply(reply: XPendingRawReply): XPendingReply { -// return { -// pending: reply[0], -// firstId: reply[1], -// lastId: reply[2], -// consumers: reply[3] === null ? null : reply[3].map(([name, deliveriesCounter]) => ({ -// name, -// deliveriesCounter: Number(deliveriesCounter) -// })) -// }; -// } +export default { + FIRST_KEY_INDEX: 1, + IS_READ_ONLY: true, + transformArguments(key: RedisArgument, group: RedisArgument) { + return ['XPENDING', key, group]; + }, + transformReply(reply: XPendingRawReply) { + return { + pending: reply[0], + firstId: reply[1], + lastId: reply[2], + consumers: reply[3] === null ? null : reply[3].map(([name, deliveriesCounter]) => ({ + name, + deliveriesCounter: Number(deliveriesCounter) + })) + } + } +} as const satisfies Command; diff --git a/packages/client/lib/commands/XPENDING_RANGE.spec.ts b/packages/client/lib/commands/XPENDING_RANGE.spec.ts index b08f71d88a..2f2d75b40f 100644 --- a/packages/client/lib/commands/XPENDING_RANGE.spec.ts +++ b/packages/client/lib/commands/XPENDING_RANGE.spec.ts @@ -1,53 +1,67 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XPENDING_RANGE'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XPENDING_RANGE from './XPENDING_RANGE'; -// describe('XPENDING RANGE', () => { -// describe('transformArguments', () => { -// it('simple', () => { -// assert.deepEqual( -// transformArguments('key', 'group', '-', '+', 1), -// ['XPENDING', 'key', 'group', '-', '+', '1'] -// ); -// }); +describe('XPENDING RANGE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1), + ['XPENDING', 'key', 'group', '-', '+', '1'] + ); + }); -// it('with IDLE', () => { -// assert.deepEqual( -// transformArguments('key', 'group', '-', '+', 1, { -// IDLE: 1, -// }), -// ['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1'] -// ); -// }); + it('with IDLE', () => { + assert.deepEqual( + XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, { + IDLE: 1, + }), + ['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1'] + ); + }); -// it('with consumer', () => { -// assert.deepEqual( -// transformArguments('key', 'group', '-', '+', 1, { -// consumer: 'consumer' -// }), -// ['XPENDING', 'key', 'group', '-', '+', '1', 'consumer'] -// ); -// }); + it('with consumer', () => { + assert.deepEqual( + XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, { + consumer: 'consumer' + }), + ['XPENDING', 'key', 'group', '-', '+', '1', 'consumer'] + ); + }); -// it('with IDLE, consumer', () => { -// assert.deepEqual( -// transformArguments('key', 'group', '-', '+', 1, { -// IDLE: 1, -// consumer: 'consumer' -// }), -// ['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1', 'consumer'] -// ); -// }); -// }); + it('with IDLE, consumer', () => { + assert.deepEqual( + XPENDING_RANGE.transformArguments('key', 'group', '-', '+', 1, { + IDLE: 1, + consumer: 'consumer' + }), + ['XPENDING', 'key', 'group', 'IDLE', '1', '-', '+', '1', 'consumer'] + ); + }); + }); -// testUtils.testWithClient('client.xPendingRange', async client => { -// await client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }); + testUtils.testAll('xPendingRange', async client => { + 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', + id: '>' + }), + client.xPendingRange('key', 'group', '-', '+', 1) + ]); -// assert.deepEqual( -// await client.xPendingRange('key', 'group', '-', '+', 1), -// [] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + assert.ok(Array.isArray(reply)); + assert.equal(reply.length, 1); + assert.equal(reply[0].id, id); + assert.equal(reply[0].consumer, 'consumer'); + assert.equal(typeof reply[0].millisecondsSinceLastDelivery, 'number'); + assert.equal(reply[0].deliveriesCounter, '1'); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XPENDING_RANGE.ts b/packages/client/lib/commands/XPENDING_RANGE.ts index 37d95efd4f..9ca37dae9c 100644 --- a/packages/client/lib/commands/XPENDING_RANGE.ts +++ b/packages/client/lib/commands/XPENDING_RANGE.ts @@ -32,19 +32,7 @@ // return args; // } -// type XPendingRangeRawReply = Array<[ -// id: RedisCommandArgument, -// consumer: RedisCommandArgument, -// millisecondsSinceLastDelivery: number, -// deliveriesCounter: number -// ]>; -// type XPendingRangeReply = Array<{ -// id: RedisCommandArgument; -// owner: RedisCommandArgument; -// millisecondsSinceLastDelivery: number; -// deliveriesCounter: number; -// }>; // export function transformReply(reply: XPendingRangeRawReply): XPendingRangeReply { // return reply.map(([id, owner, millisecondsSinceLastDelivery, deliveriesCounter]) => ({ @@ -54,3 +42,56 @@ // deliveriesCounter // })); // } + +import { RedisArgument, ArrayReply, TuplesReply, BlobStringReply, NumberReply, Command } from '../RESP/types'; + +export interface XPendingRangeOptions { + IDLE?: number; + consumer?: RedisArgument; +} + +type XPendingRangeRawReply = ArrayReply>; + +export default { + FIRST_KEY_INDEX: 1, + IS_READ_ONLY: true, + transformArguments( + key: RedisArgument, + group: RedisArgument, + start: RedisArgument, + end: RedisArgument, + count: number, + options?: XPendingRangeOptions + ) { + const args = ['XPENDING', key, group]; + + if (options?.IDLE !== undefined) { + args.push('IDLE', options.IDLE.toString()); + } + + args.push( + start, + end, + count.toString() + ); + + if (options?.consumer) { + args.push(options.consumer); + } + + return args; + }, + transformReply(reply: XPendingRangeRawReply) { + return reply.map(pending => ({ + id: pending[0], + consumer: pending[1], + millisecondsSinceLastDelivery: pending[2], + deliveriesCounter: pending[3] + })); + } +} as const satisfies Command; diff --git a/packages/client/lib/commands/XRANGE.spec.ts b/packages/client/lib/commands/XRANGE.spec.ts index 4d937c4e32..dfcc059064 100644 --- a/packages/client/lib/commands/XRANGE.spec.ts +++ b/packages/client/lib/commands/XRANGE.spec.ts @@ -1,30 +1,39 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XRANGE'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XRANGE from './XRANGE'; -// describe('XRANGE', () => { -// describe('transformArguments', () => { -// it('simple', () => { -// assert.deepEqual( -// transformArguments('key', '-', '+'), -// ['XRANGE', 'key', '-', '+'] -// ); -// }); +describe('XRANGE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + XRANGE.transformArguments('key', '-', '+'), + ['XRANGE', 'key', '-', '+'] + ); + }); -// it('with COUNT', () => { -// assert.deepEqual( -// transformArguments('key', '-', '+', { -// COUNT: 1 -// }), -// ['XRANGE', 'key', '-', '+', 'COUNT', '1'] -// ); -// }); -// }); + it('with COUNT', () => { + assert.deepEqual( + XRANGE.transformArguments('key', '-', '+', { + COUNT: 1 + }), + ['XRANGE', 'key', '-', '+', 'COUNT', '1'] + ); + }); + }); -// testUtils.testWithClient('client.xRange', async client => { -// assert.deepEqual( -// await client.xRange('key', '+', '-'), -// [] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + testUtils.testAll('xRange', async client => { + const message = { field: 'value' }, + [id, reply] = await Promise.all([ + client.xAdd('key', '*', message), + client.xRange('key', '-', '+') + ]); + + assert.deepEqual(reply, [{ + id, + message + }]); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XRANGE.ts b/packages/client/lib/commands/XRANGE.ts index 1f3cf1d856..1eed1e12b9 100644 --- a/packages/client/lib/commands/XRANGE.ts +++ b/packages/client/lib/commands/XRANGE.ts @@ -1,26 +1,29 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { RedisArgument, Command } from '../RESP/types'; +import { transformStreamMessagesReply } from './generic-transformers'; -// export const FIRST_KEY_INDEX = 1; +export interface XRangeOptions { + COUNT?: number; +} -// export const IS_READ_ONLY = true; +export function transformXRangeArguments( + command: RedisArgument, + key: RedisArgument, + start: RedisArgument, + end: RedisArgument, + options?: XRangeOptions +) { + const args = [command, key, start, end]; -// interface XRangeOptions { -// COUNT?: number; -// } + if (options?.COUNT) { + args.push('COUNT', options.COUNT.toString()); + } -// export function transformArguments( -// key: RedisCommandArgument, -// start: RedisCommandArgument, -// end: RedisCommandArgument, -// options?: XRangeOptions -// ): RedisCommandArguments { -// const args = ['XRANGE', key, start, end]; + return args; +} -// if (options?.COUNT) { -// args.push('COUNT', options.COUNT.toString()); -// } - -// return args; -// } - -// export { transformStreamMessagesReply as transformReply } from './generic-transformers'; +export default { + FIRST_KEY_INDEX: 1, + IS_READ_ONLY: true, + transformArguments: transformXRangeArguments.bind(undefined, 'XRANGE'), + transformReply: transformStreamMessagesReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/XREAD.spec.ts b/packages/client/lib/commands/XREAD.spec.ts index 13aa35b83f..c707d6ef52 100644 --- a/packages/client/lib/commands/XREAD.spec.ts +++ b/packages/client/lib/commands/XREAD.spec.ts @@ -1,103 +1,111 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { FIRST_KEY_INDEX, transformArguments } from './XREAD'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XREAD from './XREAD'; -// describe('XREAD', () => { -// describe('FIRST_KEY_INDEX', () => { -// it('single stream', () => { -// assert.equal( -// FIRST_KEY_INDEX({ key: 'key', id: '' }), -// 'key' -// ); -// }); +describe('XREAD', () => { + describe('FIRST_KEY_INDEX', () => { + it('single stream', () => { + assert.equal( + XREAD.FIRST_KEY_INDEX({ + key: 'key', + id: '' + }), + 'key' + ); + }); -// it('multiple streams', () => { -// assert.equal( -// FIRST_KEY_INDEX([{ key: '1', id: '' }, { key: '2', id: '' }]), -// '1' -// ); -// }); -// }); + it('multiple streams', () => { + assert.equal( + XREAD.FIRST_KEY_INDEX([{ + key: '1', + id: '' + }, { + key: '2', + id: '' + }]), + '1' + ); + }); + }); -// describe('transformArguments', () => { -// it('single stream', () => { -// assert.deepEqual( -// transformArguments({ -// key: 'key', -// id: '0' -// }), -// ['XREAD', 'STREAMS', 'key', '0'] -// ); -// }); + describe('transformArguments', () => { + it('single stream', () => { + assert.deepEqual( + XREAD.transformArguments({ + key: 'key', + id: '0-0' + }), + ['XREAD', 'STREAMS', 'key', '0-0'] + ); + }); -// it('multiple streams', () => { -// assert.deepEqual( -// transformArguments([{ -// key: '1', -// id: '0' -// }, { -// key: '2', -// id: '0' -// }]), -// ['XREAD', 'STREAMS', '1', '2', '0', '0'] -// ); -// }); + it('multiple streams', () => { + assert.deepEqual( + XREAD.transformArguments([{ + key: '1', + id: '0-0' + }, { + key: '2', + id: '0-0' + }]), + ['XREAD', 'STREAMS', '1', '2', '0-0', '0-0'] + ); + }); -// it('with COUNT', () => { -// assert.deepEqual( -// transformArguments({ -// key: 'key', -// id: '0' -// }, { -// COUNT: 1 -// }), -// ['XREAD', 'COUNT', '1', 'STREAMS', 'key', '0'] -// ); -// }); + it('with COUNT', () => { + assert.deepEqual( + XREAD.transformArguments({ + key: 'key', + id: '0-0' + }, { + COUNT: 1 + }), + ['XREAD', 'COUNT', '1', 'STREAMS', 'key', '0-0'] + ); + }); -// it('with BLOCK', () => { -// assert.deepEqual( -// transformArguments({ -// key: 'key', -// id: '0' -// }, { -// BLOCK: 0 -// }), -// ['XREAD', 'BLOCK', '0', 'STREAMS', 'key', '0'] -// ); -// }); + it('with BLOCK', () => { + assert.deepEqual( + XREAD.transformArguments({ + key: 'key', + id: '0-0' + }, { + BLOCK: 0 + }), + ['XREAD', 'BLOCK', '0', 'STREAMS', 'key', '0-0'] + ); + }); -// it('with COUNT, BLOCK', () => { -// assert.deepEqual( -// transformArguments({ -// key: 'key', -// id: '0' -// }, { -// COUNT: 1, -// BLOCK: 0 -// }), -// ['XREAD', 'COUNT', '1', 'BLOCK', '0', 'STREAMS', 'key', '0'] -// ); -// }); -// }); + it('with COUNT, BLOCK', () => { + assert.deepEqual( + XREAD.transformArguments({ + key: 'key', + id: '0-0' + }, { + COUNT: 1, + BLOCK: 0 + }), + ['XREAD', 'COUNT', '1', 'BLOCK', '0', 'STREAMS', 'key', '0-0'] + ); + }); + }); -// testUtils.testWithClient('client.xRead', async client => { -// assert.equal( -// await client.xRead({ -// key: 'key', -// id: '0' -// }), -// null -// ); -// }, GLOBAL.SERVERS.OPEN); - -// testUtils.testWithCluster('cluster.xRead', async cluster => { -// assert.equal( -// await cluster.xRead({ -// key: 'key', -// id: '0' -// }), -// null -// ); -// }, GLOBAL.CLUSTERS.OPEN); -// }); + // TODO + // testUtils.testAll('client.xRead', async client => { + // const message = { field: 'value' }, + // [, reply] = await Promise.all([ + // client.xAdd('key', '*', message), + // client.xRead({ + // key: 'key', + // id: '0-0' + // }) + // ]) + // assert.equal( + // await client.xRead({ + // key: 'key', + // id: '0' + // }), + // null + // ); + // }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/client/lib/commands/XREAD.ts b/packages/client/lib/commands/XREAD.ts index f58972b1f6..2c1aa3d827 100644 --- a/packages/client/lib/commands/XREAD.ts +++ b/packages/client/lib/commands/XREAD.ts @@ -1,46 +1,55 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { Command, RedisArgument } from '../RESP/types'; -// export const FIRST_KEY_INDEX = (streams: Array | XReadStream): RedisCommandArgument => { -// return Array.isArray(streams) ? streams[0].key : streams.key; -// }; +export interface XReadStream { + key: RedisArgument; + id: RedisArgument; +} -// export const IS_READ_ONLY = true; +export type XReadStreams = Array | XReadStream; -// interface XReadStream { -// key: RedisCommandArgument; -// id: RedisCommandArgument; -// } +export function pushXReadStreams(args: Array, streams: XReadStreams) { + args.push('STREAMS'); -// interface XReadOptions { -// COUNT?: number; -// BLOCK?: number; -// } + if (Array.isArray(streams)) { + const keysStart = args.length, + idsStart = keysStart + streams.length; + for (let i = 0; i < streams.length; i++) { + const stream = streams[i]; + args[keysStart + i] = stream.key; + args[idsStart + i] = stream.id; + } + } else { + args.push(streams.key, streams.id); + } +} -// export function transformArguments( -// streams: Array | XReadStream, -// options?: XReadOptions -// ): RedisCommandArguments { -// const args: RedisCommandArguments = ['XREAD']; +export interface XReadOptions { + COUNT?: number; + BLOCK?: number; +} -// if (options?.COUNT) { -// args.push('COUNT', options.COUNT.toString()); -// } +export default { + FIRST_KEY_INDEX(streams: XReadStreams) { + return Array.isArray(streams) ? streams[0].key : streams.key; + }, + IS_READ_ONLY: true, + transformArguments(streams: XReadStreams, options?: XReadOptions) { + const args: Array = ['XREAD']; -// if (typeof options?.BLOCK === 'number') { -// args.push('BLOCK', options.BLOCK.toString()); -// } + if (options?.COUNT) { + args.push('COUNT', options.COUNT.toString()); + } -// args.push('STREAMS'); + if (options?.BLOCK !== undefined) { + args.push('BLOCK', options.BLOCK.toString()); + } -// const streamsArray = Array.isArray(streams) ? streams : [streams], -// argsLength = args.length; -// for (let i = 0; i < streamsArray.length; i++) { -// const stream = streamsArray[i]; -// args[argsLength + i] = stream.key; -// args[argsLength + streamsArray.length + i] = stream.id; -// } + pushXReadStreams(args, streams); -// return args; -// } + return args; + }, + // export { transformStreamsMessagesReply as transformReply } from './generic-transformers'; + // TODO + transformReply: undefined as unknown as () => unknown +} as const satisfies Command; -// export { transformStreamsMessagesReply as transformReply } from './generic-transformers'; diff --git a/packages/client/lib/commands/XREADGROUP.spec.ts b/packages/client/lib/commands/XREADGROUP.spec.ts index 1cccdb79e6..ee23689add 100644 --- a/packages/client/lib/commands/XREADGROUP.spec.ts +++ b/packages/client/lib/commands/XREADGROUP.spec.ts @@ -1,153 +1,137 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { FIRST_KEY_INDEX, transformArguments } from './XREADGROUP'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XREADGROUP from './XREADGROUP'; -// describe('XREADGROUP', () => { -// describe('FIRST_KEY_INDEX', () => { -// it('single stream', () => { -// assert.equal( -// FIRST_KEY_INDEX('', '', { key: 'key', id: '' }), -// 'key' -// ); -// }); +describe('XREADGROUP', () => { + describe('FIRST_KEY_INDEX', () => { + it('single stream', () => { + assert.equal( + XREADGROUP.FIRST_KEY_INDEX('', '', { key: 'key', id: '' }), + 'key' + ); + }); -// it('multiple streams', () => { -// assert.equal( -// FIRST_KEY_INDEX('', '', [{ key: '1', id: '' }, { key: '2', id: '' }]), -// '1' -// ); -// }); -// }); + it('multiple streams', () => { + assert.equal( + XREADGROUP.FIRST_KEY_INDEX('', '', [{ key: '1', id: '' }, { key: '2', id: '' }]), + '1' + ); + }); + }); -// describe('transformArguments', () => { -// it('single stream', () => { -// assert.deepEqual( -// transformArguments('group', 'consumer', { -// key: 'key', -// id: '0' -// }), -// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', 'key', '0'] -// ); -// }); + describe('transformArguments', () => { + it('single stream', () => { + assert.deepEqual( + XREADGROUP.transformArguments('group', 'consumer', { + key: 'key', + id: '0-0' + }), + ['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', 'key', '0-0'] + ); + }); -// it('multiple streams', () => { -// assert.deepEqual( -// transformArguments('group', 'consumer', [{ -// key: '1', -// id: '0' -// }, { -// key: '2', -// id: '0' -// }]), -// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', '1', '2', '0', '0'] -// ); -// }); + it('multiple streams', () => { + assert.deepEqual( + XREADGROUP.transformArguments('group', 'consumer', [{ + key: '1', + id: '0-0' + }, { + key: '2', + id: '0-0' + }]), + ['XREADGROUP', 'GROUP', 'group', 'consumer', 'STREAMS', '1', '2', '0-0', '0-0'] + ); + }); -// it('with COUNT', () => { -// assert.deepEqual( -// transformArguments('group', 'consumer', { -// key: 'key', -// id: '0' -// }, { -// COUNT: 1 -// }), -// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'STREAMS', 'key', '0'] -// ); -// }); + it('with COUNT', () => { + assert.deepEqual( + XREADGROUP.transformArguments('group', 'consumer', { + key: 'key', + id: '0-0' + }, { + COUNT: 1 + }), + ['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'STREAMS', 'key', '0-0'] + ); + }); -// it('with BLOCK', () => { -// assert.deepEqual( -// transformArguments('group', 'consumer', { -// key: 'key', -// id: '0' -// }, { -// BLOCK: 0 -// }), -// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'BLOCK', '0', 'STREAMS', 'key', '0'] -// ); -// }); + it('with BLOCK', () => { + assert.deepEqual( + XREADGROUP.transformArguments('group', 'consumer', { + key: 'key', + id: '0-0' + }, { + BLOCK: 0 + }), + ['XREADGROUP', 'GROUP', 'group', 'consumer', 'BLOCK', '0', 'STREAMS', 'key', '0-0'] + ); + }); -// it('with NOACK', () => { -// assert.deepEqual( -// transformArguments('group', 'consumer', { -// key: 'key', -// id: '0' -// }, { -// NOACK: true -// }), -// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'NOACK', 'STREAMS', 'key', '0'] -// ); -// }); + it('with NOACK', () => { + assert.deepEqual( + XREADGROUP.transformArguments('group', 'consumer', { + key: 'key', + id: '0-0' + }, { + NOACK: true + }), + ['XREADGROUP', 'GROUP', 'group', 'consumer', 'NOACK', 'STREAMS', 'key', '0-0'] + ); + }); -// it('with COUNT, BLOCK, NOACK', () => { -// assert.deepEqual( -// transformArguments('group', 'consumer', { -// key: 'key', -// id: '0' -// }, { -// COUNT: 1, -// BLOCK: 0, -// NOACK: true -// }), -// ['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'BLOCK', '0', 'NOACK', 'STREAMS', 'key', '0'] -// ); -// }); -// }); + it('with COUNT, BLOCK, NOACK', () => { + assert.deepEqual( + XREADGROUP.transformArguments('group', 'consumer', { + key: 'key', + id: '0-0' + }, { + COUNT: 1, + BLOCK: 0, + NOACK: true + }), + ['XREADGROUP', 'GROUP', 'group', 'consumer', 'COUNT', '1', 'BLOCK', '0', 'NOACK', 'STREAMS', 'key', '0-0'] + ); + }); + }); -// describe('client.xReadGroup', () => { -// testUtils.testWithClient('null', async client => { -// const [, readGroupReply] = await Promise.all([ -// client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }), -// client.xReadGroup('group', 'consumer', { -// key: 'key', -// id: '>' -// }) -// ]); + // testUtils.testAll('xReadGroup - null', async client => { + // const [, readGroupReply] = await Promise.all([ + // client.xGroupCreate('key', 'group', '$', { + // MKSTREAM: true + // }), + // client.xReadGroup('group', 'consumer', { + // key: 'key', + // id: '>' + // }) + // ]); -// assert.equal(readGroupReply, null); -// }, GLOBAL.SERVERS.OPEN); + // assert.equal(readGroupReply, null); + // }, GLOBAL.SERVERS.OPEN); -// testUtils.testWithClient('with a message', async client => { -// const [, id, readGroupReply] = await Promise.all([ -// client.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }), -// client.xAdd('key', '*', { field: 'value' }), -// client.xReadGroup('group', 'consumer', { -// key: 'key', -// id: '>' -// }) -// ]); + // testUtils.testAll('xReadGroup - with a message', async client => { + // const [, id, readGroupReply] = await Promise.all([ + // client.xGroupCreate('key', 'group', '$', { + // MKSTREAM: true + // }), + // client.xAdd('key', '*', { field: 'value' }), + // client.xReadGroup('group', 'consumer', { + // key: 'key', + // id: '>' + // }) + // ]); -// assert.deepEqual(readGroupReply, [{ -// name: 'key', -// messages: [{ -// id, -// message: Object.create(null, { -// field: { -// value: 'value', -// configurable: true, -// enumerable: true -// } -// }) -// }] -// }]); -// }, GLOBAL.SERVERS.OPEN); -// }); - -// testUtils.testWithCluster('cluster.xReadGroup', async cluster => { -// const [, readGroupReply] = await Promise.all([ -// cluster.xGroupCreate('key', 'group', '$', { -// MKSTREAM: true -// }), -// cluster.xReadGroup('group', 'consumer', { -// key: 'key', -// id: '>' -// }) -// ]); - -// assert.equal(readGroupReply, null); -// }, GLOBAL.CLUSTERS.OPEN); -// }); + // assert.deepEqual(readGroupReply, [{ + // name: 'key', + // messages: [{ + // id, + // message: Object.create(null, { + // field: { + // value: 'value', + // configurable: true, + // enumerable: true + // } + // }) + // }] + // }]); + // }, GLOBAL.SERVERS.OPEN); +}); diff --git a/packages/client/lib/commands/XREADGROUP.ts b/packages/client/lib/commands/XREADGROUP.ts index 40064934cd..f1a2782208 100644 --- a/packages/client/lib/commands/XREADGROUP.ts +++ b/packages/client/lib/commands/XREADGROUP.ts @@ -1,57 +1,46 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { Command, RedisArgument } from '../RESP/types'; +import XREAD, { XReadStreams, pushXReadStreams } from './XREAD'; -// export interface XReadGroupStream { -// key: RedisCommandArgument; -// id: RedisCommandArgument; -// } +export interface XReadGroupOptions { + COUNT?: number; + BLOCK?: number; + NOACK?: boolean; +} -// export interface XReadGroupOptions { -// COUNT?: number; -// BLOCK?: number; -// NOACK?: true; -// } +export default { + FIRST_KEY_INDEX( + _group: RedisArgument, + _consumer: RedisArgument, + streams: XReadStreams + ) { + return XREAD.FIRST_KEY_INDEX(streams); + }, + IS_READ_ONLY: true, + transformArguments( + group: RedisArgument, + consumer: RedisArgument, + streams: XReadStreams, + options?: XReadGroupOptions + ) { + const args = ['XREADGROUP', group, consumer]; -// export const FIRST_KEY_INDEX = ( -// _group: RedisCommandArgument, -// _consumer: RedisCommandArgument, -// streams: Array | XReadGroupStream -// ): RedisCommandArgument => { -// return Array.isArray(streams) ? streams[0].key : streams.key; -// }; + if (options?.COUNT !== undefined) { + args.push('COUNT', options.COUNT.toString()); + } -// export const IS_READ_ONLY = true; + if (options?.BLOCK !== undefined) { + args.push('BLOCK', options.BLOCK.toString()); + } -// export function transformArguments( -// group: RedisCommandArgument, -// consumer: RedisCommandArgument, -// streams: Array | XReadGroupStream, -// options?: XReadGroupOptions -// ): RedisCommandArguments { -// const args = ['XREADGROUP', 'GROUP', group, consumer]; + if (options?.NOACK) { + args.push('NOACK'); + } -// if (options?.COUNT) { -// args.push('COUNT', options.COUNT.toString()); -// } + pushXReadStreams(args, streams); -// if (typeof options?.BLOCK === 'number') { -// args.push('BLOCK', options.BLOCK.toString()); -// } - -// if (options?.NOACK) { -// args.push('NOACK'); -// } - -// args.push('STREAMS'); - -// const streamsArray = Array.isArray(streams) ? streams : [streams], -// argsLength = args.length; -// for (let i = 0; i < streamsArray.length; i++) { -// const stream = streamsArray[i]; -// args[argsLength + i] = stream.key; -// args[argsLength + streamsArray.length + i] = stream.id; -// } - -// return args; -// } - -// export { transformStreamsMessagesReply as transformReply } from './generic-transformers'; + return args; + }, + // export { transformStreamsMessagesReply as transformReply } from './generic-transformers'; + // TODO + transformReply: undefined as unknown as () => unknown +} as const satisfies Command; diff --git a/packages/client/lib/commands/XREVRANGE.spec.ts b/packages/client/lib/commands/XREVRANGE.spec.ts index 344edd62e5..f935f3bcdd 100644 --- a/packages/client/lib/commands/XREVRANGE.spec.ts +++ b/packages/client/lib/commands/XREVRANGE.spec.ts @@ -1,30 +1,39 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './XREVRANGE'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import XREVRANGE from './XREVRANGE'; -// describe('XREVRANGE', () => { -// describe('transformArguments', () => { -// it('simple', () => { -// assert.deepEqual( -// transformArguments('key', '-', '+'), -// ['XREVRANGE', 'key', '-', '+'] -// ); -// }); +describe('XREVRANGE', () => { + describe('transformArguments', () => { + it('simple', () => { + assert.deepEqual( + XREVRANGE.transformArguments('key', '-', '+'), + ['XREVRANGE', 'key', '-', '+'] + ); + }); -// it('with COUNT', () => { -// assert.deepEqual( -// transformArguments('key', '-', '+', { -// COUNT: 1 -// }), -// ['XREVRANGE', 'key', '-', '+', 'COUNT', '1'] -// ); -// }); -// }); + it('with COUNT', () => { + assert.deepEqual( + XREVRANGE.transformArguments('key', '-', '+', { + COUNT: 1 + }), + ['XREVRANGE', 'key', '-', '+', 'COUNT', '1'] + ); + }); + }); -// testUtils.testWithClient('client.xRevRange', async client => { -// assert.deepEqual( -// await client.xRevRange('key', '+', '-'), -// [] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + testUtils.testAll('xRevRange', async client => { + const message = { field: 'value' }, + [id, reply] = await Promise.all([ + client.xAdd('key', '*', message), + client.xRevRange('key', '-', '+') + ]); + + assert.deepEqual(reply, [{ + id, + message + }]); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/XREVRANGE.ts b/packages/client/lib/commands/XREVRANGE.ts index de095dc029..86e4d8abc9 100644 --- a/packages/client/lib/commands/XREVRANGE.ts +++ b/packages/client/lib/commands/XREVRANGE.ts @@ -1,26 +1,13 @@ -// import { RedisCommandArgument, RedisCommandArguments } from '.'; +import { Command } from '../RESP/types'; +import XRANGE, { transformXRangeArguments } from './XRANGE'; -// export const FIRST_KEY_INDEX = 1; +export interface XRevRangeOptions { + COUNT?: number; +} -// export const IS_READ_ONLY = true; - -// interface XRangeRevOptions { -// COUNT?: number; -// } - -// export function transformArguments( -// key: RedisCommandArgument, -// start: RedisCommandArgument, -// end: RedisCommandArgument, -// options?: XRangeRevOptions -// ): RedisCommandArguments { -// const args = ['XREVRANGE', key, start, end]; - -// if (options?.COUNT) { -// args.push('COUNT', options.COUNT.toString()); -// } - -// return args; -// } - -// export { transformStreamMessagesReply as transformReply } from './generic-transformers'; +export default { + FIRST_KEY_INDEX: XRANGE.FIRST_KEY_INDEX, + IS_READ_ONLY: XRANGE.IS_READ_ONLY, + transformArguments: transformXRangeArguments.bind(undefined, 'XREVRANGE'), + transformReply: XRANGE.transformReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/XSETID.ts b/packages/client/lib/commands/XSETID.ts index bd3a8fd0bc..a2ac8af001 100644 --- a/packages/client/lib/commands/XSETID.ts +++ b/packages/client/lib/commands/XSETID.ts @@ -1,6 +1,8 @@ import { RedisArgument, SimpleStringReply, Command } from '../RESP/types'; export interface XSetIdOptions { + /** added in 7.0 */ ENTRIESADDED?: number; + /** added in 7.0 */ MAXDELETEDID?: RedisArgument; } diff --git a/packages/client/lib/commands/XTRIM.ts b/packages/client/lib/commands/XTRIM.ts index edbb11f3ea..0512323a32 100644 --- a/packages/client/lib/commands/XTRIM.ts +++ b/packages/client/lib/commands/XTRIM.ts @@ -2,6 +2,7 @@ import { NumberReply, Command, RedisArgument } from '../RESP/types'; export interface XTrimOptions { strategyModifier?: '=' | '~'; + /** added in 6.2 */ LIMIT?: number; } @@ -12,7 +13,8 @@ export default { key: RedisArgument, strategy: 'MAXLEN' | 'MINID', threshold: number, - options?: XTrimOptions) { + options?: XTrimOptions + ) { const args = ['XTRIM', key, strategy]; if (options?.strategyModifier) { diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts index 03884ac44a..8298a966d8 100644 --- a/packages/client/lib/commands/generic-transformers.ts +++ b/packages/client/lib/commands/generic-transformers.ts @@ -58,39 +58,37 @@ export function transformTuplesReply( return message; } -export interface StreamMessageReply { - id: RedisArgument; - message: Record; +export type StreamMessageRawReply = TuplesReply<[ + id: BlobStringReply, + message: ArrayReply +]>; + +export function transformStreamMessageReply([id, message]: StreamMessageRawReply) { + return { + id, + message: transformTuplesReply(message) + }; } -export type StreamMessagesReply = Array; +export type StreamMessagesRawReply = ArrayReply; -export function transformStreamMessagesReply(reply: Array): StreamMessagesReply { - const messages = []; - - for (const [id, message] of reply) { - messages.push({ - id, - message: transformTuplesReply(message) - }); - } - - return messages; +export function transformStreamMessagesReply(reply: StreamMessagesRawReply) { + return reply.map(transformStreamMessageReply); } -export type StreamsMessagesReply = Array<{ - name: RedisArgument; - messages: StreamMessagesReply; -}> | null; +// export type StreamsMessagesReply = Array<{ +// name: RedisArgument; +// messages: StreamMessagesReply; +// }> | null; -export function transformStreamsMessagesReply(reply: Array | null): StreamsMessagesReply | null { - if (reply === null) return null; +// export function transformStreamsMessagesReply(reply: Array | null): StreamsMessagesReply | null { +// if (reply === null) return null; - return reply.map(([name, rawMessages]) => ({ - name, - messages: transformStreamMessagesReply(rawMessages) - })); -} +// return reply.map(([name, rawMessages]) => ({ +// name, +// messages: transformStreamMessagesReply(rawMessages) +// })); +// } export interface SortedSetMember { value: RedisArgument; diff --git a/packages/client/lib/commands/index.ts b/packages/client/lib/commands/index.ts index 6537d89913..cca2f9f128 100644 --- a/packages/client/lib/commands/index.ts +++ b/packages/client/lib/commands/index.ts @@ -253,10 +253,28 @@ import WATCH from './WATCH'; import XACK from './XACK'; import XADD_NOMKSTREAM from './XADD_NOMKSTREAM'; import XADD from './XADD'; +import XAUTOCLAIM_JUSTID from './XAUTOCLAIM_JUSTID'; +import XAUTOCLAIM from './XAUTOCLAIM'; +import XCLAIM_JUSTID from './XCLAIM_JUSTID'; +import XCLAIM from './XCLAIM'; import XDEL from './XDEL'; +import XGROUP_CREATE from './XGROUP_CREATE'; +import XGROUP_CREATECONSUMER from './XGROUP_CREATECONSUMER'; +import XGROUP_DELCONSUMER from './XGROUP_DELCONSUMER'; +import XGROUP_DESTROY from './XGROUP_DESTROY'; +import XGROUP_SETID from './XGROUP_SETID'; +import XINFO_CONSUMERS from './XINFO_CONSUMERS'; +import XINFO_GROUPS from './XINFO_GROUPS'; +import XINFO_STREAM from './XINFO_STREAM'; +import XLEN from './XLEN'; +import XPENDING_RANGE from './XPENDING_RANGE'; +import XPENDING from './XPENDING'; +import XRANGE from './XRANGE'; +import XREAD from './XREAD'; +import XREADGROUP from './XREADGROUP'; +import XREVRANGE from './XREVRANGE'; import XSETID from './XSETID'; import XTRIM from './XTRIM'; -import XLEN from './XLEN'; import ZADD_INCR from './ZADD_INCR'; import ZADD from './ZADD'; import ZCARD from './ZCARD'; @@ -554,10 +572,28 @@ type WATCH = typeof import('./WATCH').default; type XACK = typeof import('./XACK').default; type XADD_NOMKSTREAM = typeof import('./XADD_NOMKSTREAM').default; type XADD = typeof import('./XADD').default; +type XAUTOCLAIM_JUSTID = typeof import('./XAUTOCLAIM_JUSTID').default; +type XAUTOCLAIM = typeof import('./XAUTOCLAIM').default; +type XCLAIM_JUSTID = typeof import('./XCLAIM_JUSTID').default; +type XCLAIM = typeof import('./XCLAIM').default; type XDEL = typeof import('./XDEL').default; +type XGROUP_CREATE = typeof import('./XGROUP_CREATE').default; +type XGROUP_CREATECONSUMER = typeof import('./XGROUP_CREATECONSUMER').default; +type XGROUP_DELCONSUMER = typeof import('./XGROUP_DELCONSUMER').default; +type XGROUP_DESTROY = typeof import('./XGROUP_DESTROY').default; +type XGROUP_SETID = typeof import('./XGROUP_SETID').default; +type XINFO_CONSUMERS = typeof import('./XINFO_CONSUMERS').default; +type XINFO_GROUPS = typeof import('./XINFO_GROUPS').default; +type XINFO_STREAM = typeof import('./XINFO_STREAM').default; +type XLEN = typeof import('./XLEN').default; +type XPENDING_RANGE = typeof import('./XPENDING_RANGE').default; +type XPENDING = typeof import('./XPENDING').default; +type XRANGE = typeof import('./XRANGE').default; +type XREAD = typeof import('./XREAD').default; +type XREADGROUP = typeof import('./XREADGROUP').default; +type XREVRANGE = typeof import('./XREVRANGE').default; type XSETID = typeof import('./XSETID').default; type XTRIM = typeof import('./XTRIM').default; -type XLEN = typeof import('./XLEN').default; type ZADD_INCR = typeof import('./ZADD_INCR').default; type ZADD = typeof import('./ZADD').default; type ZCARD = typeof import('./ZCARD').default; @@ -1112,14 +1148,50 @@ type Commands = { xAddNoMkStream: XADD_NOMKSTREAM; XADD: XADD; xAdd: XADD; + XAUTOCLAIM_JUSTID: XAUTOCLAIM_JUSTID; + xAutoClaimJustId: XAUTOCLAIM_JUSTID; + XAUTOCLAIM: XAUTOCLAIM; + xAutoClaim: XAUTOCLAIM; + XCLAIM_JUSTID: XCLAIM_JUSTID; + xClaimJustId: XCLAIM_JUSTID; + XCLAIM: XCLAIM; + xClaim: XCLAIM; XDEL: XDEL; xDel: XDEL; + XGROUP_CREATE: XGROUP_CREATE; + xGroupCreate: XGROUP_CREATE; + XGROUP_CREATECONSUMER: XGROUP_CREATECONSUMER; + xGroupCreateConsumer: XGROUP_CREATECONSUMER; + XGROUP_DELCONSUMER: XGROUP_DELCONSUMER; + xGroupDelConsumer: XGROUP_DELCONSUMER; + XGROUP_DESTROY: XGROUP_DESTROY; + xGroupDestroy: XGROUP_DESTROY; + XGROUP_SETID: XGROUP_SETID; + xGroupSetId: XGROUP_SETID; + XINFO_CONSUMERS: XINFO_CONSUMERS; + xInfoConsumers: XINFO_CONSUMERS; + XINFO_GROUPS: XINFO_GROUPS; + xInfoGroups: XINFO_GROUPS; + XINFO_STREAM: XINFO_STREAM; + xInfoStream: XINFO_STREAM; + XLEN: XLEN; + xLen: XLEN; + XPENDING_RANGE: XPENDING_RANGE; + xPendingRange: XPENDING_RANGE; + XPENDING: XPENDING; + xPending: XPENDING; + XRANGE: XRANGE; + xRange: XRANGE; + XREAD: XREAD; + xRead: XREAD; + XREADGROUP: XREADGROUP; + xReadGroup: XREADGROUP; + XREVRANGE: XREVRANGE; + xRevRange: XREVRANGE; XSETID: XSETID; xSetId: XSETID; XTRIM: XTRIM; xTrim: XTRIM; - XLEN: XLEN; - xLen: XLEN; ZADD_INCR: ZADD_INCR; zAddIncr: ZADD_INCR; ZADD: ZADD; @@ -1715,14 +1787,50 @@ export default { xAddNoMkStream: XADD_NOMKSTREAM, XADD, xAdd: XADD, + XAUTOCLAIM_JUSTID, + xAutoClaimJustId: XAUTOCLAIM_JUSTID, + XAUTOCLAIM, + xAutoClaim: XAUTOCLAIM, + XCLAIM_JUSTID, + xClaimJustId: XCLAIM_JUSTID, + XCLAIM, + xClaim: XCLAIM, XDEL, xDel: XDEL, + XGROUP_CREATE, + xGroupCreate: XGROUP_CREATE, + XGROUP_CREATECONSUMER, + xGroupCreateConsumer: XGROUP_CREATECONSUMER, + XGROUP_DELCONSUMER, + xGroupDelConsumer: XGROUP_DELCONSUMER, + XGROUP_DESTROY, + xGroupDestroy: XGROUP_DESTROY, + XGROUP_SETID, + xGroupSetId: XGROUP_SETID, + XINFO_CONSUMERS, + xInfoConsumers: XINFO_CONSUMERS, + XINFO_GROUPS, + xInfoGroups: XINFO_GROUPS, + XINFO_STREAM, + xInfoStream: XINFO_STREAM, + XLEN, + xLen: XLEN, + XPENDING_RANGE, + xPendingRange: XPENDING_RANGE, + XPENDING, + xPending: XPENDING, + XRANGE, + xRange: XRANGE, + XREAD, + xRead: XREAD, + XREADGROUP, + xReadGroup: XREADGROUP, + XREVRANGE, + xRevRange: XREVRANGE, XSETID, xSetId: XSETID, XTRIM, xTrim: XTRIM, - XLEN, - xLen: XLEN, ZADD_INCR, zAddIncr: ZADD_INCR, ZADD, diff --git a/test/package-lock.json b/test/package-lock.json index 2419e2490c..878a92a6ad 100644 --- a/test/package-lock.json +++ b/test/package-lock.json @@ -9,69 +9,19 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@redis/client": "^1.5.7", - "ioredis": "^5.3.2", - "local": "file:../packages/client", - "redis": "^4.6.6", - "redis-om": "^0.3.6" - } - }, - "node_modules/@ioredis/commands": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", - "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" - }, - "node_modules/@redis/bloom": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", - "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", - "peerDependencies": { - "@redis/client": "^1.0.0" + "@redis/client": "next" } }, "node_modules/@redis/client": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz", - "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==", + "version": "2.0.0-next.2", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-2.0.0-next.2.tgz", + "integrity": "sha512-+sf9n+PBHac2xXSofSX0x79cYa5H4ighu80F993q4H1T109ZthFNGBmg33DfwfPrDMKc256qTXvsb0lCqzwMmg==", "dependencies": { "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "4.0.0" + "generic-pool": "3.9.0" }, "engines": { - "node": ">=14" - } - }, - "node_modules/@redis/graph": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", - "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/json": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", - "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/search": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", - "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", - "peerDependencies": { - "@redis/client": "^1.0.0" - } - }, - "node_modules/@redis/time-series": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", - "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", - "peerDependencies": { - "@redis/client": "^1.0.0" + "node": ">=16" } }, "node_modules/cluster-key-slot": { @@ -82,30 +32,6 @@ "node": ">=0.10.0" } }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "engines": { - "node": ">=0.10" - } - }, "node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -113,120 +39,6 @@ "engines": { "node": ">= 4" } - }, - "node_modules/ioredis": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.3.2.tgz", - "integrity": "sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==", - "dependencies": { - "@ioredis/commands": "^1.1.1", - "cluster-key-slot": "^1.1.0", - "debug": "^4.3.4", - "denque": "^2.1.0", - "lodash.defaults": "^4.2.0", - "lodash.isarguments": "^3.1.0", - "redis-errors": "^1.2.0", - "redis-parser": "^3.0.0", - "standard-as-callback": "^2.1.0" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/ioredis" - } - }, - "node_modules/local": { - "name": "@redis/client", - "version": "2.0.0-next.1", - "resolved": "file:../packages/client", - "license": "MIT", - "dependencies": { - "cluster-key-slot": "1.1.2", - "generic-pool": "3.9.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/lodash.defaults": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", - "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==" - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/redis": { - "version": "4.6.6", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz", - "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==", - "dependencies": { - "@redis/bloom": "1.2.0", - "@redis/client": "1.5.7", - "@redis/graph": "1.1.0", - "@redis/json": "1.0.4", - "@redis/search": "1.1.2", - "@redis/time-series": "1.0.4" - } - }, - "node_modules/redis-errors": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", - "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", - "engines": { - "node": ">=4" - } - }, - "node_modules/redis-om": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/redis-om/-/redis-om-0.3.6.tgz", - "integrity": "sha512-WRmrAm1n1EQIQbEwbfqpceuxHgr7LKOZ471c/KGxyOTVFFm53E0S7vFSZA7a1Jnga7aHTOYqLhhMWE0lKKdsNw==", - "dependencies": { - "redis": "^4.0.4", - "ulid": "^2.3.0" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/redis-parser": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", - "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", - "dependencies": { - "redis-errors": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/standard-as-callback": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", - "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" - }, - "node_modules/ulid": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/ulid/-/ulid-2.3.0.tgz", - "integrity": "sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw==", - "bin": { - "ulid": "bin/cli.js" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } } diff --git a/test/package.json b/test/package.json index f7fbbbf5d1..23ca20e058 100644 --- a/test/package.json +++ b/test/package.json @@ -10,10 +10,6 @@ "author": "", "license": "ISC", "dependencies": { - "@redis/client": "^1.5.7", - "ioredis": "^5.3.2", - "local": "file:../packages/client", - "redis": "^4.6.6", - "redis-om": "^0.3.6" + "@redis/client": "next" } } diff --git a/test/test.js b/test/test.js index 8d9b54bc27..f9b83cae7a 100644 --- a/test/test.js +++ b/test/test.js @@ -1,26 +1,21 @@ -import { createClient } from '@redis/client'; -import { setTimeout } from 'node:timers/promises'; +import { RESP_TYPES, createClient } from '@redis/client'; -const client = createClient(); +const client = createClient({ + RESP: 3, + commandOptions: { + typeMapping: { + [RESP_TYPES.MAP]: Map + } + } +}); client.on('error', err => console.error(err)); await client.connect(); -await client.set('key', 'a'.repeat(1_000)); +console.log( + await client.flushAll(), + await client.hSet('key', 'field', 'value'), + await client.hGetAll('key') +) -throw 'a'; - -while (true) { - const promises = []; - for (let i = 0; i < 20_000; i++) { - promises.push(client.sendCommand(['HMSET', `aa${i.toString()}`, 'txt1', Math.random().toString()])); - } - - await Promise.all(promises); - console.log( - await client.dbSize(), - (await client.info('MEMORY')).split('\n')[1] - ); - - await setTimeout(1000); -} +client.destroy();