From d59254e497813d1ceebf92386c1b76a67b86cd65 Mon Sep 17 00:00:00 2001 From: Leibale Date: Tue, 9 May 2023 14:04:26 +0300 Subject: [PATCH] some commands --- docs/v4-to-v5.md | 6 +- packages/client/lib/commands/BITPOS.spec.ts | 2 +- packages/client/lib/commands/FLUSHALL.spec.ts | 56 +++++----- packages/client/lib/commands/FLUSHALL.ts | 2 + packages/client/lib/commands/FLUSHDB.spec.ts | 58 +++++----- packages/client/lib/commands/FLUSHDB.ts | 2 + packages/client/lib/commands/GEOSEARCH.ts | 4 - packages/client/lib/commands/HEXISTS.spec.ts | 2 +- packages/client/lib/commands/MOVE.spec.ts | 2 +- packages/client/lib/commands/XADD.ts | 59 +++++----- .../lib/commands/XADD_NOMKSTREAM.spec.ts | 16 +-- .../client/lib/commands/XADD_NOMKSTREAM.ts | 19 ++-- packages/client/lib/commands/ZINTER.ts | 42 +------- packages/client/lib/commands/ZUNION.spec.ts | 22 +++- packages/client/lib/commands/ZUNION.ts | 11 +- .../client/lib/commands/ZUNIONSTORE.spec.ts | 2 +- packages/client/lib/commands/ZUNIONSTORE.ts | 11 +- .../lib/commands/ZUNION_WITHSCORES.spec.ts | 101 ++++++++++-------- .../client/lib/commands/ZUNION_WITHSCORES.ts | 25 ++--- .../lib/commands/generic-transformers.ts | 54 ++++++++++ packages/client/lib/commands/index.ts | 34 +++--- 21 files changed, 295 insertions(+), 235 deletions(-) diff --git a/docs/v4-to-v5.md b/docs/v4-to-v5.md index d13c4f1115..d520962d5a 100644 --- a/docs/v4-to-v5.md +++ b/docs/v4-to-v5.md @@ -85,7 +85,10 @@ Some command arguments/replies have changed to align more closely to data types - `HRANDFIELD_COUNT_WITHVALUES`: `Record` -> `Array<{ field: BlobString; value: BlobString; }>` (it can return duplicates). - `SCAN`, `HSCAN`, `SSCAN`, and `ZSCAN`: cursor type is `string` instead of `number`? - `HSETNX`: `boolean` -> `number` [^boolean-to-number] -- `ZINTER`: instead of `client.ZINTER('11, { WEIGHTS: [1] })` use `client.ZINTER({ key: '1', weight: 1 }])` +- `ZINTER`: instead of `client.ZINTER('key', { WEIGHTS: [1] })` use `client.ZINTER({ key: 'key', weight: 1 }])` +- `ZINTER_WITHSCORES`: instead of `client.ZINTER_WITHSCORES('key', { WEIGHTS: [1] })` use `client.ZINTER_WITHSCORES({ key: 'key', weight: 1 }])` +- `ZUNION`: instead of `client.ZUNION('key', { WEIGHTS: [1] })` use `client.ZUNION({ key: 'key', weight: 1 }])` +- `ZUNION_WITHSCORES`: instead of `client.ZUNION_WITHSCORES('key', { WEIGHTS: [1] })` use `client.ZUNION_WITHSCORES({ key: 'key', weight: 1 }])` - `SETNX`: `boolean` -> `number` [^boolean-to-number] - `COPY`: `destinationDb` -> `DB`, `replace` -> `REPLACE`, `boolean` -> `number` [^boolean-to-number] - `EXPIRE`: `boolean` -> `number` [^boolean-to-number] @@ -104,6 +107,7 @@ Some command arguments/replies have changed to align more closely to data types - `GEOSEARCH_WITH`/`GEORADIUS_WITH`: `GeoReplyWith` -> `GEO_REPLY_WITH` [^enum-to-constants] - `GEORADIUSSTORE` -> `GEORADIUS_STORE` - `GEORADIUSBYMEMBERSTORE` -> `GEORADIUSBYMEMBER_STORE` +- `XACK`: `boolean` -> `number` [^boolean-to-number] [^enum-to-constants]: TODO diff --git a/packages/client/lib/commands/BITPOS.spec.ts b/packages/client/lib/commands/BITPOS.spec.ts index 8891f43a15..34e975ca03 100644 --- a/packages/client/lib/commands/BITPOS.spec.ts +++ b/packages/client/lib/commands/BITPOS.spec.ts @@ -2,7 +2,7 @@ import { strict as assert } from 'assert'; import testUtils, { GLOBAL } from '../test-utils'; import BITPOS from './BITPOS'; -describe.only('BITPOS', () => { +describe('BITPOS', () => { describe('transformArguments', () => { it('simple', () => { assert.deepEqual( diff --git a/packages/client/lib/commands/FLUSHALL.spec.ts b/packages/client/lib/commands/FLUSHALL.spec.ts index db5bb72e9c..3cef3798a6 100644 --- a/packages/client/lib/commands/FLUSHALL.spec.ts +++ b/packages/client/lib/commands/FLUSHALL.spec.ts @@ -1,35 +1,35 @@ import { strict as assert } from 'assert'; import testUtils, { GLOBAL } from '../test-utils'; -import { RedisFlushModes, transformArguments } from './FLUSHALL'; +import FLUSHALL, { REDIS_FLUSH_MODES } from './FLUSHALL'; describe('FLUSHALL', () => { - describe('transformArguments', () => { - it('default', () => { - assert.deepEqual( - transformArguments(), - ['FLUSHALL'] - ); - }); - - it('ASYNC', () => { - assert.deepEqual( - transformArguments(RedisFlushModes.ASYNC), - ['FLUSHALL', 'ASYNC'] - ); - }); - - it('SYNC', () => { - assert.deepEqual( - transformArguments(RedisFlushModes.SYNC), - ['FLUSHALL', 'SYNC'] - ); - }); + describe('transformArguments', () => { + it('default', () => { + assert.deepEqual( + FLUSHALL.transformArguments(), + ['FLUSHALL'] + ); }); - testUtils.testWithClient('client.flushAll', async client => { - assert.equal( - await client.flushAll(), - 'OK' - ); - }, GLOBAL.SERVERS.OPEN); + it('ASYNC', () => { + assert.deepEqual( + FLUSHALL.transformArguments(REDIS_FLUSH_MODES.ASYNC), + ['FLUSHALL', 'ASYNC'] + ); + }); + + it('SYNC', () => { + assert.deepEqual( + FLUSHALL.transformArguments(REDIS_FLUSH_MODES.SYNC), + ['FLUSHALL', 'SYNC'] + ); + }); + }); + + testUtils.testWithClient('client.flushAll', async client => { + assert.equal( + await client.flushAll(), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); }); diff --git a/packages/client/lib/commands/FLUSHALL.ts b/packages/client/lib/commands/FLUSHALL.ts index bc41e24e0d..6c814b34a4 100644 --- a/packages/client/lib/commands/FLUSHALL.ts +++ b/packages/client/lib/commands/FLUSHALL.ts @@ -8,6 +8,8 @@ export const REDIS_FLUSH_MODES = { export type RedisFlushModes = typeof REDIS_FLUSH_MODES[keyof typeof REDIS_FLUSH_MODES]; export default { + FIRST_KEY_INDEX: undefined, + IS_READ_ONLY: false, transformArguments(mode?: RedisFlushModes) { const args = ['FLUSHALL']; diff --git a/packages/client/lib/commands/FLUSHDB.spec.ts b/packages/client/lib/commands/FLUSHDB.spec.ts index bf460e9e7a..93b328eda6 100644 --- a/packages/client/lib/commands/FLUSHDB.spec.ts +++ b/packages/client/lib/commands/FLUSHDB.spec.ts @@ -1,36 +1,36 @@ import { strict as assert } from 'assert'; import testUtils, { GLOBAL } from '../test-utils'; -import { RedisFlushModes } from './FLUSHALL'; -import { transformArguments } from './FLUSHDB'; +import FLUSHDB from './FLUSHDB'; +import { REDIS_FLUSH_MODES } from './FLUSHALL'; describe('FLUSHDB', () => { - describe('transformArguments', () => { - it('default', () => { - assert.deepEqual( - transformArguments(), - ['FLUSHDB'] - ); - }); - - it('ASYNC', () => { - assert.deepEqual( - transformArguments(RedisFlushModes.ASYNC), - ['FLUSHDB', 'ASYNC'] - ); - }); - - it('SYNC', () => { - assert.deepEqual( - transformArguments(RedisFlushModes.SYNC), - ['FLUSHDB', 'SYNC'] - ); - }); + describe('transformArguments', () => { + it('default', () => { + assert.deepEqual( + FLUSHDB.transformArguments(), + ['FLUSHDB'] + ); }); - testUtils.testWithClient('client.flushDb', async client => { - assert.equal( - await client.flushDb(), - 'OK' - ); - }, GLOBAL.SERVERS.OPEN); + it('ASYNC', () => { + assert.deepEqual( + FLUSHDB.transformArguments(REDIS_FLUSH_MODES.ASYNC), + ['FLUSHDB', 'ASYNC'] + ); + }); + + it('SYNC', () => { + assert.deepEqual( + FLUSHDB.transformArguments(REDIS_FLUSH_MODES.SYNC), + ['FLUSHDB', 'SYNC'] + ); + }); + }); + + testUtils.testWithClient('client.flushDb', async client => { + assert.equal( + await client.flushDb(), + 'OK' + ); + }, GLOBAL.SERVERS.OPEN); }); diff --git a/packages/client/lib/commands/FLUSHDB.ts b/packages/client/lib/commands/FLUSHDB.ts index 3dade5c0c5..cb7be1156a 100644 --- a/packages/client/lib/commands/FLUSHDB.ts +++ b/packages/client/lib/commands/FLUSHDB.ts @@ -2,6 +2,8 @@ import { SimpleStringReply, Command } from '../RESP/types'; import { RedisFlushModes } from './FLUSHALL'; export default { + FIRST_KEY_INDEX: undefined, + IS_READ_ONLY: false, transformArguments(mode?: RedisFlushModes) { const args = ['FLUSHDB']; diff --git a/packages/client/lib/commands/GEOSEARCH.ts b/packages/client/lib/commands/GEOSEARCH.ts index 4e81f361dd..c4deaa37e6 100644 --- a/packages/client/lib/commands/GEOSEARCH.ts +++ b/packages/client/lib/commands/GEOSEARCH.ts @@ -43,10 +43,6 @@ export function pushGeoSearchArguments( args.push('BYBOX', by.width.toString(), by.height.toString(), by.unit); } - if (options?.SORT) { - args.push(options.SORT); - } - pushGeoSearchOptions(args, options); return args; diff --git a/packages/client/lib/commands/HEXISTS.spec.ts b/packages/client/lib/commands/HEXISTS.spec.ts index fae7c11f2b..0e0e82fa21 100644 --- a/packages/client/lib/commands/HEXISTS.spec.ts +++ b/packages/client/lib/commands/HEXISTS.spec.ts @@ -13,7 +13,7 @@ describe('HEXISTS', () => { testUtils.testAll('hExists', async client => { assert.equal( await client.hExists('key', 'field'), - false + 0 ); }, { client: GLOBAL.SERVERS.OPEN, diff --git a/packages/client/lib/commands/MOVE.spec.ts b/packages/client/lib/commands/MOVE.spec.ts index 63e10c8e10..929fd2dfd4 100644 --- a/packages/client/lib/commands/MOVE.spec.ts +++ b/packages/client/lib/commands/MOVE.spec.ts @@ -13,7 +13,7 @@ describe('MOVE', () => { testUtils.testAll('move', async client => { assert.equal( await client.move('key', 1), - 1 + 0 ); }, { client: GLOBAL.SERVERS.OPEN, diff --git a/packages/client/lib/commands/XADD.ts b/packages/client/lib/commands/XADD.ts index 9b6fe045a8..b681069c72 100644 --- a/packages/client/lib/commands/XADD.ts +++ b/packages/client/lib/commands/XADD.ts @@ -1,4 +1,4 @@ -import { RedisArgument, BlobStringReply, Command } from '../RESP/types'; +import { RedisArgument, BlobStringReply, Command, CommandArguments } from '../RESP/types'; export interface XAddOptions { TRIM?: { @@ -9,6 +9,37 @@ export interface XAddOptions { }; } +export function pushXAddArguments( + args: CommandArguments, + id: RedisArgument, + message: Record, + options?: XAddOptions +) { + if (options?.TRIM) { + if (options.TRIM.strategy) { + args.push(options.TRIM.strategy); + } + + if (options.TRIM.strategyModifier) { + args.push(options.TRIM.strategyModifier); + } + + args.push(options.TRIM.threshold.toString()); + + if (options.TRIM.limit) { + args.push('LIMIT', options.TRIM.limit.toString()); + } + } + + args.push(id); + + for (const [key, value] of Object.entries(message)) { + args.push(key, value); + } + + return args; +} + export default { FIRST_KEY_INDEX: 1, IS_READ_ONLY: false, @@ -18,31 +49,7 @@ export default { message: Record, options?: XAddOptions ) { - const args = ['XADD', key]; - - if (options?.TRIM) { - if (options.TRIM.strategy) { - args.push(options.TRIM.strategy); - } - - if (options.TRIM.strategyModifier) { - args.push(options.TRIM.strategyModifier); - } - - args.push(options.TRIM.threshold.toString()); - - if (options.TRIM.limit) { - args.push('LIMIT', options.TRIM.limit.toString()); - } - } - - args.push(id); - - for (const [key, value] of Object.entries(message)) { - args.push(key, value); - } - - return args; + return pushXAddArguments(['XADD', key], id, message, options); }, transformReply: undefined as unknown as () => BlobStringReply } as const satisfies Command; diff --git a/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts b/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts index e28bd4e105..862b51a4aa 100644 --- a/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts +++ b/packages/client/lib/commands/XADD_NOMKSTREAM.spec.ts @@ -9,7 +9,7 @@ describe('XADD NOMKSTREAM', () => { XADD_NOMKSTREAM.transformArguments('key', '*', { field: 'value' }), - ['XADD', 'key', '*', 'field', 'value', 'NOMKSTREAM'] + ['XADD', 'key', 'NOMKSTREAM', '*', 'field', 'value'] ); }); @@ -19,7 +19,7 @@ describe('XADD NOMKSTREAM', () => { '1': 'I', '2': 'II' }), - ['XADD', 'key', '*', '1', 'I', '2', 'II', 'NOMKSTREAM'] + ['XADD', 'key', 'NOMKSTREAM', '*', '1', 'I', '2', 'II'] ); }); @@ -32,7 +32,7 @@ describe('XADD NOMKSTREAM', () => { threshold: 1000 } }), - ['XADD', 'key', '1000', '*', 'field', 'value', 'NOMKSTREAM'] + ['XADD', 'key', 'NOMKSTREAM', '1000', '*', 'field', 'value'] ); }); @@ -46,7 +46,7 @@ describe('XADD NOMKSTREAM', () => { threshold: 1000 } }), - ['XADD', 'key', 'MAXLEN', '1000', '*', 'field', 'value', 'NOMKSTREAM'] + ['XADD', 'key', 'NOMKSTREAM', 'MAXLEN', '1000', '*', 'field', 'value'] ); }); @@ -60,7 +60,7 @@ describe('XADD NOMKSTREAM', () => { threshold: 1000 } }), - ['XADD', 'key', '=', '1000', '*', 'field', 'value', 'NOMKSTREAM'] + ['XADD', 'key', 'NOMKSTREAM', '=', '1000', '*', 'field', 'value'] ); }); @@ -74,17 +74,17 @@ describe('XADD NOMKSTREAM', () => { limit: 1 } }), - ['XADD', 'key', '1000', 'LIMIT', '1', '*', 'field', 'value', 'NOMKSTREAM'] + ['XADD', 'key', 'NOMKSTREAM', '1000', 'LIMIT', '1', '*', 'field', 'value'] ); }); }); testUtils.testAll('xAddNoMkStream', async client => { assert.equal( - typeof await client.xAddNoMkStream('key', '*', { + await client.xAddNoMkStream('key', '*', { field: 'value' }), - 'string' + null ); }, { client: GLOBAL.SERVERS.OPEN, diff --git a/packages/client/lib/commands/XADD_NOMKSTREAM.ts b/packages/client/lib/commands/XADD_NOMKSTREAM.ts index 4c425f8982..65e7dd566e 100644 --- a/packages/client/lib/commands/XADD_NOMKSTREAM.ts +++ b/packages/client/lib/commands/XADD_NOMKSTREAM.ts @@ -1,13 +1,16 @@ -import { BlobStringReply, NullReply, Command } from '../RESP/types'; -import XADD from './XADD'; +import { RedisArgument, BlobStringReply, NullReply, Command } from '../RESP/types'; +import { XAddOptions, pushXAddArguments } from './XADD'; export default { - FIRST_KEY_INDEX: XADD.FIRST_KEY_INDEX, - IS_READ_ONLY: XADD.IS_READ_ONLY, - transformArguments(...args: Parameters) { - const redisArgs = XADD.transformArguments(...args); - redisArgs.push('NOMKSTREAM'); - return redisArgs; + FIRST_KEY_INDEX: 1, + IS_READ_ONLY: false, + transformArguments( + key: RedisArgument, + id: RedisArgument, + message: Record, + options?: XAddOptions + ) { + return pushXAddArguments(['XADD', key, 'NOMKSTREAM'], id, message, options); }, transformReply: undefined as unknown as () => BlobStringReply | NullReply } as const satisfies Command; diff --git a/packages/client/lib/commands/ZINTER.ts b/packages/client/lib/commands/ZINTER.ts index a4c0be6deb..97f01f2040 100644 --- a/packages/client/lib/commands/ZINTER.ts +++ b/packages/client/lib/commands/ZINTER.ts @@ -1,5 +1,5 @@ import { RedisArgument, ArrayReply, BlobStringReply, Command } from '../RESP/types'; -import { transformDoubleArgument } from './generic-transformers'; +import { ZKeys, pushZKeysArguments } from './generic-transformers'; export type ZInterKeyAndWeight = { key: RedisArgument; @@ -14,38 +14,10 @@ export interface ZInterOptions { export function pushZInterArguments( args: Array, - keys: ZInterKeys | ZInterKeys, + keys: ZKeys, options?: ZInterOptions ) { - if (Array.isArray(keys)) { - args.push(keys.length.toString()); - - if (keys.length) { - if (isPlainKeys(keys)) { - args = args.concat(keys); - } else { - const start = args.length; - args[start + keys.length] = 'WEIGHTS'; - for (let i = 0; i < keys.length; i++) { - const index = start + i; - args[index] = keys[i].key; - args[index + 1 + keys.length] = transformDoubleArgument(keys[i].weight); - } - } - } - } else { - args.push('1'); - - if (isPlainKey(keys)) { - args.push(keys); - } else { - args.push( - keys.key, - 'WEIGHTS', - transformDoubleArgument(keys.weight) - ); - } - } + pushZKeysArguments(args, keys); if (options?.AGGREGATE) { args.push('AGGREGATE', options.AGGREGATE); @@ -54,14 +26,6 @@ export function pushZInterArguments( return args; } -function isPlainKey(key: RedisArgument | ZInterKeyAndWeight): key is RedisArgument { - return typeof key === 'string' || Buffer.isBuffer(key); -} - -function isPlainKeys(keys: Array | Array): keys is Array { - return isPlainKey(keys[0]); -} - export default { FIRST_KEY_INDEX: 2, IS_READ_ONLY: true, diff --git a/packages/client/lib/commands/ZUNION.spec.ts b/packages/client/lib/commands/ZUNION.spec.ts index 8aca77531e..54542aaa81 100644 --- a/packages/client/lib/commands/ZUNION.spec.ts +++ b/packages/client/lib/commands/ZUNION.spec.ts @@ -13,22 +13,36 @@ describe('ZUNION', () => { ); }); - it('keys (array)', () => { + it('keys (Array)', () => { assert.deepEqual( ZUNION.transformArguments(['1', '2']), ['ZUNION', '2', '1', '2'] ); }); - it('with WEIGHTS', () => { + it('key & weight', () => { assert.deepEqual( - ZUNION.transformArguments('key', { - WEIGHTS: [1] + ZUNION.transformArguments({ + key: 'key', + weight: 1 }), ['ZUNION', '1', 'key', 'WEIGHTS', '1'] ); }); + it('keys & weights', () => { + assert.deepEqual( + ZUNION.transformArguments([{ + key: 'a', + weight: 1 + }, { + key: 'b', + weight: 2 + }]), + ['ZUNION', '2', 'a', 'b', 'WEIGHTS', '1', '2'] + ); + }); + it('with AGGREGATE', () => { assert.deepEqual( ZUNION.transformArguments('key', { diff --git a/packages/client/lib/commands/ZUNION.ts b/packages/client/lib/commands/ZUNION.ts index f9eb06fbdf..09614b9dc0 100644 --- a/packages/client/lib/commands/ZUNION.ts +++ b/packages/client/lib/commands/ZUNION.ts @@ -1,8 +1,7 @@ import { ArrayReply, BlobStringReply, Command } from '../RESP/types'; -import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers'; +import { ZKeys, pushZKeysArguments } from './generic-transformers'; export interface ZUnionOptions { - WEIGHTS?: Array; AGGREGATE?: 'SUM' | 'MIN' | 'MAX'; } @@ -10,14 +9,10 @@ export default { FIRST_KEY_INDEX: 2, IS_READ_ONLY: true, transformArguments( - keys: RedisVariadicArgument, + keys: ZKeys, options?: ZUnionOptions ) { - const args = pushVariadicArgument(['ZUNION'], keys); - - if (options?.WEIGHTS) { - args.push('WEIGHTS', ...options.WEIGHTS.map(weight => weight.toString())); - } + const args = pushZKeysArguments(['ZUNION'], keys); if (options?.AGGREGATE) { args.push('AGGREGATE', options.AGGREGATE); diff --git a/packages/client/lib/commands/ZUNIONSTORE.spec.ts b/packages/client/lib/commands/ZUNIONSTORE.spec.ts index ae561aff65..ca436dbd06 100644 --- a/packages/client/lib/commands/ZUNIONSTORE.spec.ts +++ b/packages/client/lib/commands/ZUNIONSTORE.spec.ts @@ -49,7 +49,7 @@ describe('ZUNIONSTORE', () => { testUtils.testAll('zUnionStore', async client => { assert.equal( - await client.zUnionStore('destination', 'key'), + await client.zUnionStore('{tag}destination', '{tag}key'), 0 ); }, { diff --git a/packages/client/lib/commands/ZUNIONSTORE.ts b/packages/client/lib/commands/ZUNIONSTORE.ts index ed70c75c3c..a14d3ba31c 100644 --- a/packages/client/lib/commands/ZUNIONSTORE.ts +++ b/packages/client/lib/commands/ZUNIONSTORE.ts @@ -1,8 +1,7 @@ import { RedisArgument, NumberReply, Command, } from '../RESP/types'; -import { RedisVariadicArgument, pushVariadicArgument } from './generic-transformers'; +import { ZKeys, pushZKeysArguments } from './generic-transformers'; export interface ZUnionOptions { - WEIGHTS?: Array; AGGREGATE?: 'SUM' | 'MIN' | 'MAX'; } @@ -11,14 +10,10 @@ export default { IS_READ_ONLY: false, transformArguments( destination: RedisArgument, - keys: RedisVariadicArgument, + keys: ZKeys, options?: ZUnionOptions ) { - const args = pushVariadicArgument(['ZUNIONSTORE', destination], keys); - - if (options?.WEIGHTS) { - args.push('WEIGHTS', ...options.WEIGHTS.map(weight => weight.toString())); - } + const args = pushZKeysArguments(['ZUNIONSTORE', destination], keys); if (options?.AGGREGATE) { args.push('AGGREGATE', options.AGGREGATE); diff --git a/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts b/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts index 6076801367..41442bb646 100644 --- a/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts +++ b/packages/client/lib/commands/ZUNION_WITHSCORES.spec.ts @@ -1,48 +1,65 @@ -// import { strict as assert } from 'assert'; -// import testUtils, { GLOBAL } from '../test-utils'; -// import { transformArguments } from './ZUNION_WITHSCORES'; +import { strict as assert } from 'assert'; +import testUtils, { GLOBAL } from '../test-utils'; +import ZUNION_WITHSCORES from './ZUNION_WITHSCORES'; -// describe('ZUNION WITHSCORES', () => { -// testUtils.isVersionGreaterThanHook([6, 2]); +describe('ZUNION WITHSCORES', () => { + testUtils.isVersionGreaterThanHook([6, 2]); -// describe('transformArguments', () => { -// it('key (string)', () => { -// assert.deepEqual( -// transformArguments('key'), -// ['ZUNION', '1', 'key', 'WITHSCORES'] -// ); -// }); + describe('transformArguments', () => { + it('key (string)', () => { + assert.deepEqual( + ZUNION_WITHSCORES.transformArguments('key'), + ['ZUNION', '1', 'key'] + ); + }); -// it('keys (array)', () => { -// assert.deepEqual( -// transformArguments(['1', '2']), -// ['ZUNION', '2', '1', '2', 'WITHSCORES'] -// ); -// }); + it('keys (Array)', () => { + assert.deepEqual( + ZUNION_WITHSCORES.transformArguments(['1', '2']), + ['ZUNION', '2', '1', '2'] + ); + }); -// it('with WEIGHTS', () => { -// assert.deepEqual( -// transformArguments('key', { -// WEIGHTS: [1] -// }), -// ['ZUNION', '1', 'key', 'WEIGHTS', '1', 'WITHSCORES'] -// ); -// }); + it('key & weight', () => { + assert.deepEqual( + ZUNION_WITHSCORES.transformArguments({ + key: 'key', + weight: 1 + }), + ['ZUNION', '1', 'key', 'WEIGHTS', '1'] + ); + }); -// it('with AGGREGATE', () => { -// assert.deepEqual( -// transformArguments('key', { -// AGGREGATE: 'SUM' -// }), -// ['ZUNION', '1', 'key', 'AGGREGATE', 'SUM', 'WITHSCORES'] -// ); -// }); -// }); + it('keys & weights', () => { + assert.deepEqual( + ZUNION_WITHSCORES.transformArguments([{ + key: 'a', + weight: 1 + }, { + key: 'b', + weight: 2 + }]), + ['ZUNION', '2', 'a', 'b', 'WEIGHTS', '1', '2'] + ); + }); -// testUtils.testWithClient('client.zUnionWithScores', async client => { -// assert.deepEqual( -// await client.zUnionWithScores('key'), -// [] -// ); -// }, GLOBAL.SERVERS.OPEN); -// }); + it('with AGGREGATE', () => { + assert.deepEqual( + ZUNION_WITHSCORES.transformArguments('key', { + AGGREGATE: 'SUM' + }), + ['ZUNION', '1', 'key', 'AGGREGATE', 'SUM', 'WITHSCORES'] + ); + }); + }); + + testUtils.testAll('zUnionWithScores', async client => { + assert.deepEqual( + await client.zUnionWithScores('key'), + [] + ); + }, { + client: GLOBAL.SERVERS.OPEN, + cluster: GLOBAL.CLUSTERS.OPEN + }); +}); diff --git a/packages/client/lib/commands/ZUNION_WITHSCORES.ts b/packages/client/lib/commands/ZUNION_WITHSCORES.ts index 54a43da7ec..d0895a3de7 100644 --- a/packages/client/lib/commands/ZUNION_WITHSCORES.ts +++ b/packages/client/lib/commands/ZUNION_WITHSCORES.ts @@ -1,13 +1,14 @@ -// import { RedisCommandArguments } from '.'; -// import { transformArguments as transformZUnionArguments } from './ZUNION'; +import { Command } from '../RESP/types'; +import ZUNION from './ZUNION'; +import { transformSortedSetReply } from './generic-transformers'; -// export { FIRST_KEY_INDEX, IS_READ_ONLY } from './ZUNION'; - -// export function transformArguments(...args: Parameters): RedisCommandArguments { -// return [ -// ...transformZUnionArguments(...args), -// 'WITHSCORES' -// ]; -// } - -// export { transformSortedSetWithScoresReply as transformReply } from './generic-transformers'; +export default { + FIRST_KEY_INDEX: ZUNION.FIRST_KEY_INDEX, + IS_READ_ONLY: ZUNION.IS_READ_ONLY, + transformArguments(...args: Parameters) { + const redisArgs = ZUNION.transformArguments(...args); + redisArgs.push('WITHSCORES'); + return redisArgs; + }, + transformReply: transformSortedSetReply +} as const satisfies Command; diff --git a/packages/client/lib/commands/generic-transformers.ts b/packages/client/lib/commands/generic-transformers.ts index 78bc983842..027a1cee34 100644 --- a/packages/client/lib/commands/generic-transformers.ts +++ b/packages/client/lib/commands/generic-transformers.ts @@ -432,3 +432,57 @@ export function transformRangeReply([start, end]: RawRangeReply): RangeReply { end }; } + +export type ZKeyAndWeight = { + key: RedisArgument; + weight: number; +}; + +export type ZVariadicKeys = T | [T, ...Array]; + +export type ZKeys = ZVariadicKeys | ZVariadicKeys; + +export function pushZKeysArguments( + args: CommandArguments, + keys: ZKeys +) { + if (Array.isArray(keys)) { + args.push(keys.length.toString()); + + if (keys.length) { + if (isPlainKeys(keys)) { + args = args.concat(keys); + } else { + const start = args.length; + args[start + keys.length] = 'WEIGHTS'; + for (let i = 0; i < keys.length; i++) { + const index = start + i; + args[index] = keys[i].key; + args[index + 1 + keys.length] = transformDoubleArgument(keys[i].weight); + } + } + } + } else { + args.push('1'); + + if (isPlainKey(keys)) { + args.push(keys); + } else { + args.push( + keys.key, + 'WEIGHTS', + transformDoubleArgument(keys.weight) + ); + } + } + + return args; +} + +function isPlainKey(key: RedisArgument | ZKeyAndWeight): key is RedisArgument { + return typeof key === 'string' || Buffer.isBuffer(key); +} + +function isPlainKeys(keys: Array | Array): keys is Array { + return isPlainKey(keys[0]); +} diff --git a/packages/client/lib/commands/index.ts b/packages/client/lib/commands/index.ts index 68f29c3751..a83177138b 100644 --- a/packages/client/lib/commands/index.ts +++ b/packages/client/lib/commands/index.ts @@ -68,7 +68,12 @@ import GETDEL from './GETDEL'; import GETEX from './GETEX'; import GETRANGE from './GETRANGE'; import GETSET from './GETSET'; +import EXISTS from './EXISTS'; +import EXPIRE from './EXPIRE'; +import EXPIREAT from './EXPIREAT'; +import EXPIRETIME from './EXPIRETIME'; import FLUSHALL from './FLUSHALL'; +import FLUSHDB from './FLUSHDB'; import HDEL from './HDEL'; import HEXISTS from './HEXISTS'; import HGET from './HGET'; @@ -119,10 +124,6 @@ import OBJECT_FREQ from './OBJECT_FREQ'; import OBJECT_IDLETIME from './OBJECT_IDLETIME'; import OBJECT_REFCOUNT from './OBJECT_REFCOUNT'; import PERSIST from './PERSIST'; -import EXISTS from './EXISTS'; -import EXPIRE from './EXPIRE'; -import EXPIREAT from './EXPIREAT'; -import EXPIRETIME from './EXPIRETIME'; import PEXPIRE from './PEXPIRE'; import PEXPIREAT from './PEXPIREAT'; import PEXPIRETIME from './PEXPIRETIME'; @@ -212,6 +213,7 @@ import ZREMRANGEBYRANK from './ZREMRANGEBYRANK'; import ZREVRANK from './ZREVRANK'; import ZSCAN from './ZSCAN'; import ZSCORE from './ZSCORE'; +import ZUNION_WITHSCORES from './ZUNION_WITHSCORES'; import ZUNION from './ZUNION'; import ZUNIONSTORE from './ZUNIONSTORE'; import { Command } from '../RESP/types'; @@ -311,6 +313,18 @@ export default { del: DEL, DUMP, dump: DUMP, + EXISTS, + exists: EXISTS, + EXPIRE, + expire: EXPIRE, + EXPIREAT, + expireAt: EXPIREAT, + EXPIRETIME, + expireTime: EXPIRETIME, + FLUSHALL, + flushAll: FLUSHALL, + FLUSHDB, + flushDb: FLUSHDB, GEOADD, geoAdd: GEOADD, GEODIST, @@ -357,8 +371,6 @@ export default { getRange: GETRANGE, GETSET, getSet: GETSET, - FLUSHALL, - flushAll: FLUSHALL, HDEL, hDel: HDEL, HEXISTS, @@ -457,14 +469,6 @@ export default { objectRefCount: OBJECT_REFCOUNT, PERSIST, persist: PERSIST, - EXISTS, - exists: EXISTS, - EXPIRE, - expire: EXPIRE, - EXPIREAT, - expireAt: EXPIREAT, - EXPIRETIME, - expireTime: EXPIRETIME, PEXPIRE, pExpire: PEXPIRE, PEXPIREAT, @@ -646,6 +650,8 @@ export default { zScan: ZSCAN, ZSCORE, zScore: ZSCORE, + ZUNION_WITHSCORES, + zUnionWithScores: ZUNION_WITHSCORES, ZUNION, zUnion: ZUNION, ZUNIONSTORE,