From 017a9fa9d0b269137fc38e445b195fc1a07f1b80 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 11 Jun 2024 15:03:13 +0000 Subject: [PATCH 1/6] Node: ZINTER and ZUNION commands Signed-off-by: Adar Ovadia --- node/src/BaseClient.ts | 128 +++++++++++++++++++++++++++++++++++++++- node/src/Commands.ts | 42 +++++++++++-- node/src/Transaction.ts | 102 ++++++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 6 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 0ef0563708..0264d32a26 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -161,6 +161,7 @@ import { createZDiffStore, createZDiffWithScores, createZIncrBy, + createZInter, createZInterCard, createZInterstore, createZLexCount, @@ -180,6 +181,7 @@ import { createZRevRankWithScore, createZScan, createZScore, + createZUnion } from "./Commands"; import { ClosingError, @@ -3051,9 +3053,9 @@ export class BaseClient { * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) * await client.zadd("key2", {"member1": 9.5}) * await client.zinterstore("my_sorted_set", ["key1", "key2"]) // Output: 1 - Indicates that the sorted set "my_sorted_set" contains one element. - * await client.zrange_withscores("my_sorted_set", RangeByIndex(0, -1)) // Output: {'member1': 20} - "member1" is now stored in "my_sorted_set" with score of 20. + * await client.zrangeWithScores("my_sorted_set", RangeByIndex(0, -1)) // Output: {'member1': 20} - "member1" is now stored in "my_sorted_set" with score of 20. * await client.zinterstore("my_sorted_set", ["key1", "key2"] , AggregationType.MAX ) // Output: 1 - Indicates that the sorted set "my_sorted_set" contains one element, and it's score is the maximum score between the sets. - * await client.zrange_withscores("my_sorted_set", RangeByIndex(0, -1)) // Output: {'member1': 10.5} - "member1" is now stored in "my_sorted_set" with score of 10.5. + * await client.zrangeWithScores("my_sorted_set", RangeByIndex(0, -1)) // Output: {'member1': 10.5} - "member1" is now stored in "my_sorted_set" with score of 10.5. * ``` */ public zinterstore( @@ -3066,6 +3068,128 @@ export class BaseClient { ); } + /** + * Computes the intersection of sorted sets given by the specified `keys` and returns a list of intersecting elements. + * To get the scores as well, see `zinter_withscores`. + * To store the result in a key as a sorted set, see `zinterstore`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zinter/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * @returns The resulting array of intersecting elements. + * + * @example + * ```typescript + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) + * await client.zadd("key2", {"member1": 9.5}) + * await client.zinter(["key1", "key2"]) // Output: ['member1'] + * ``` + */ + public zinter( + keys: string[] | KeyWeight[], + ): Promise { + return this.createWritePromise( + createZInter(keys), + ); + } + + /** + * Computes the intersection of sorted sets given by the specified `keys` and returns a list of intersecting elements with scores. + * To get the elements only, see `zinter`. + * To store the result in a key as a sorted set, see `zinterstore`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zinter/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. + * @returns The resulting sorted set with scores. + * + * @example + * ```typescript + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) + * await client.zadd("key2", {"member1": 9.5}) + * await client.zinterWithScores(["key1", "key2"]) // Output: {'member1': 20} - "member1" with score of 20 is the result + * await client.zinterWithScores(["key1", "key2"], AggregationType.MAX) // Output: {'member1': 10.5} - "member1" with score of 10.5 is the result. + * ``` + */ + public zinterWithScores( + keys: string[] | KeyWeight[], + aggregationType?: AggregationType, + ): Promise> { + return this.createWritePromise( + createZInter(keys, aggregationType, true), + ); + } + + /** + * Computes the union of sorted sets given by the specified `keys` and returns a list of union elements. + * To get the scores as well, see `zunion_withscores`. + * + * To store the result in a key as a sorted set, see `zunionstore`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zunion/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * @returns The resulting array of union elements. + * + * @example + * ```typescript + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) + * await client.zadd("key2", {"member1": 9.5}) + * await client.zunion(["key1", "key2"]) // Output: ['member1', 'member2'] + * ``` + */ + public zunioun( + keys: string[] | KeyWeight[], + ): Promise { + return this.createWritePromise( + createZUnion(keys), + ); + } + + /** + * Computes the intersection of sorted sets given by the specified `keys` and returns a list of union elements with scores. + * To get the elements only, see `zunion`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zunion/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. + * @returns The resulting sorted set with scores. + * + * @example + * ```typescript + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) + * await client.zadd("key2", {"member1": 9.5}) + * await client.zunionWithScores(["key1", "key2"]) // {'member1': 20, 'member2': 8.2} + * await client.zunionWithScores(["key1", "key2"], "MAX") // {'member1': 10.5, 'member2': 8.2} + * ``` + */ + public zunionWithScores( + keys: string[] | KeyWeight[], + aggregationType?: AggregationType, + ): Promise> { + return this.createWritePromise( + createZUnion(keys, aggregationType, true), + ); + } + /** * Returns a random member from the sorted set stored at `key`. * diff --git a/node/src/Commands.ts b/node/src/Commands.ts index c80e5db0e3..5b64861594 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1406,16 +1406,46 @@ export function createZInterstore( keys: string[] | KeyWeight[], aggregationType?: AggregationType, ): command_request.Command { - const args = createZCmdStoreArgs(destination, keys, aggregationType); + const args = createZCmdArgs(keys, aggregationType, false, destination); return createCommand(RequestType.ZInterStore, args); } -function createZCmdStoreArgs( - destination: string, +/** + * @internal + */ +export function createZInter( + keys: string[] | KeyWeight[], + aggregationType?: AggregationType, + withScores?: boolean, +): command_request.Command { + const args = createZCmdArgs(keys, aggregationType, withScores); + return createCommand(RequestType.ZInter, args); +} + +/** + * @internal + */ +export function createZUnion( keys: string[] | KeyWeight[], aggregationType?: AggregationType, + withScores?: boolean, +): command_request.Command { + const args = createZCmdArgs(keys, aggregationType, withScores); + return createCommand(RequestType.ZUnion, args); +} + +function createZCmdArgs( + keys: string[] | KeyWeight[], + aggregationType?: AggregationType, + withscores?: boolean, + destination?: string, ): string[] { - const args: string[] = [destination, keys.length.toString()]; + const args = []; + if (destination) { + args.push(destination); + } + + args.push(keys.length.toString()); if (typeof keys[0] === "string") { args.push(...(keys as string[])); @@ -1430,6 +1460,10 @@ function createZCmdStoreArgs( args.push("AGGREGATE", aggregationType); } + if (withscores) { + args.push("WITHSCORES"); + } + return args; } diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 1009b966c1..4e48b9e934 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -192,6 +192,7 @@ import { createZDiffStore, createZDiffWithScores, createZIncrBy, + createZInter, createZInterCard, createZInterstore, createZLexCount, @@ -211,6 +212,7 @@ import { createZRevRankWithScore, createZScan, createZScore, + createZUnion, } from "./Commands"; import { command_request } from "./ProtobufMessage"; @@ -1676,6 +1678,8 @@ export class BaseTransaction> { * KeyWeight[] - for weighted keys with score multipliers. * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * Command Response - The number of elements in the resulting sorted set stored at `destination`. + * + * since */ public zinterstore( destination: string, @@ -1687,6 +1691,104 @@ export class BaseTransaction> { ); } + /** + * Computes the intersection of sorted sets given by the specified `keys` and returns a list of intersecting elements. + * To get the scores as well, see `zinter_withscores`. + * To store the result in a key as a sorted set, see `zinterstore`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zinter/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * Command Response - The resulting array of intersecting elements. + * + * since + */ + public zinter( + keys: string[] | KeyWeight[], + ): T { + return this.addAndReturn( + createZInter(keys), + ); + } + + /** + * Computes the intersection of sorted sets given by the specified `keys` and returns a list of intersecting elements with scores. + * To get the elements only, see `zinter`. + * To store the result in a key as a sorted set, see `zinterstore`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zinter/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. + * Command Response - The resulting sorted set with scores. + * + * since + */ + public zinterWithScores( + keys: string[] | KeyWeight[], + aggregationType?: AggregationType, + ): T { + return this.addAndReturn( + createZInter(keys, aggregationType, true), + ); + } + + /** + * Computes the union of sorted sets given by the specified `keys` and returns a list of union elements. + * To get the scores as well, see `zunion_withscores`. + * + * To store the result in a key as a sorted set, see `zunionstore`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zunion/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * Command Response - The resulting array of union elements. + * + * since + */ + public zunioun( + keys: string[] | KeyWeight[], + ): T { + return this.addAndReturn( + createZUnion(keys), + ); + } + + /** + * Computes the intersection of sorted sets given by the specified `keys` and returns a list of union elements with scores. + * To get the elements only, see `zunion`. + * + * When in cluster mode, all keys in `keys` must map to the same hash slot. + * + * See https://valkey.io/commands/zunion/ for more details. + * + * @param keys - The keys of the sorted sets with possible formats: + * string[] - for keys only. + * KeyWeight[] - for weighted keys with score multipliers. + * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. + * Commnd Response - The resulting sorted set with scores. + */ + public zunionWithScores( + keys: string[] | KeyWeight[], + aggregationType?: AggregationType, + ): T { + return this.addAndReturn( + createZUnion(keys, aggregationType, true), + ); + } + /** * Returns a random member from the sorted set stored at `key`. * From 328a73a50e030aa37eac9a92368129b8dd1c5aa6 Mon Sep 17 00:00:00 2001 From: Adar Ovadia Date: Mon, 5 Aug 2024 08:58:59 +0000 Subject: [PATCH 2/6] fix merge Signed-off-by: Adar Ovadia --- node/src/BaseClient.ts | 32 ++-- node/src/Transaction.ts | 22 ++- node/tests/SharedTests.ts | 313 ++++++++++++++++++++++++++++++++++++ node/tests/TestUtilities.ts | 14 +- 4 files changed, 354 insertions(+), 27 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 0264d32a26..e1ea5ebd36 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -3070,18 +3070,18 @@ export class BaseClient { /** * Computes the intersection of sorted sets given by the specified `keys` and returns a list of intersecting elements. - * To get the scores as well, see `zinter_withscores`. - * To store the result in a key as a sorted set, see `zinterstore`. + * To get the scores as well, see `zinterWithScores`. + * To store the result in a key as a sorted set, see `zinterStore`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. * * See https://valkey.io/commands/zinter/ for more details. * - * @param keys - The keys of the sorted sets with possible formats: - * string[] - for keys only. - * KeyWeight[] - for weighted keys with score multipliers. + * @param keys - The keys of the sorted sets. * @returns The resulting array of intersecting elements. * + * since Valkey version 6.2.0. + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) @@ -3090,7 +3090,7 @@ export class BaseClient { * ``` */ public zinter( - keys: string[] | KeyWeight[], + keys: string[], ): Promise { return this.createWritePromise( createZInter(keys), @@ -3100,7 +3100,7 @@ export class BaseClient { /** * Computes the intersection of sorted sets given by the specified `keys` and returns a list of intersecting elements with scores. * To get the elements only, see `zinter`. - * To store the result in a key as a sorted set, see `zinterstore`. + * To store the result in a key as a sorted set, see `zinterStore`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. * @@ -3112,6 +3112,8 @@ export class BaseClient { * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * @returns The resulting sorted set with scores. * + * since Valkey version 6.2.0. + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) @@ -3131,19 +3133,19 @@ export class BaseClient { /** * Computes the union of sorted sets given by the specified `keys` and returns a list of union elements. - * To get the scores as well, see `zunion_withscores`. + * To get the scores as well, see `zunionWithScores`. * - * To store the result in a key as a sorted set, see `zunionstore`. + * To store the result in a key as a sorted set, see `zunionStore`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. * * See https://valkey.io/commands/zunion/ for more details. * - * @param keys - The keys of the sorted sets with possible formats: - * string[] - for keys only. - * KeyWeight[] - for weighted keys with score multipliers. + * @param keys - The keys of the sorted sets. * @returns The resulting array of union elements. * + * since Valkey version 6.2.0. + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) @@ -3151,8 +3153,8 @@ export class BaseClient { * await client.zunion(["key1", "key2"]) // Output: ['member1', 'member2'] * ``` */ - public zunioun( - keys: string[] | KeyWeight[], + public zunion( + keys: string[], ): Promise { return this.createWritePromise( createZUnion(keys), @@ -3173,6 +3175,8 @@ export class BaseClient { * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * @returns The resulting sorted set with scores. * + * since Valkey version 6.2.0. + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 4e48b9e934..95bec38f3c 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -1700,15 +1700,13 @@ export class BaseTransaction> { * * See https://valkey.io/commands/zinter/ for more details. * - * @param keys - The keys of the sorted sets with possible formats: - * string[] - for keys only. - * KeyWeight[] - for weighted keys with score multipliers. + * @param keys - The keys of the sorted sets. * Command Response - The resulting array of intersecting elements. * - * since + * since Valkey version 6.2.0. */ public zinter( - keys: string[] | KeyWeight[], + keys: string[], ): T { return this.addAndReturn( createZInter(keys), @@ -1730,7 +1728,7 @@ export class BaseTransaction> { * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * Command Response - The resulting sorted set with scores. * - * since + * since Valkey version 6.2.0. */ public zinterWithScores( keys: string[] | KeyWeight[], @@ -1751,15 +1749,13 @@ export class BaseTransaction> { * * See https://valkey.io/commands/zunion/ for more details. * - * @param keys - The keys of the sorted sets with possible formats: - * string[] - for keys only. - * KeyWeight[] - for weighted keys with score multipliers. + * @param keys - The keys of the sorted sets. * Command Response - The resulting array of union elements. * - * since + * since Valkey version 6.2.0. */ - public zunioun( - keys: string[] | KeyWeight[], + public zunion( + keys: string[], ): T { return this.addAndReturn( createZUnion(keys), @@ -1779,6 +1775,8 @@ export class BaseTransaction> { * KeyWeight[] - for weighted keys with score multipliers. * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * Commnd Response - The resulting sorted set with scores. + * + * since Valkey version 6.2.0. */ public zunionWithScores( keys: string[] | KeyWeight[], diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index dd47041824..89d8317475 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -3726,6 +3726,319 @@ export function runBaseTests(config: { config.timeout, ); + async function zinterBasicTest(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + const resultZinter = await client.zinter([key1, key2]); + const expectedZinter = ["one", "two"]; + expect(resultZinter).toEqual(expectedZinter); + } + + async function zinterWithScoresBasicTest(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + const resultZinterWithScores = await client.zinterWithScores([key1, key2]); + const expectedZinterWithScores = { + one: 2.5, + two: 4.5, + }; + expect(resultZinterWithScores).toEqual(expectedZinterWithScores); + } + + async function zinterWithScoresWithMaxAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Intersection results are aggregated by the MAX score of elements + const zinterWithScoresResults = await client.zinterWithScores([key1, key2], "MAX"); + const expectedMapMax = { + one: 1.5, + two: 2.5, + }; + expect(zinterWithScoresResults).toEqual(expectedMapMax); + } + + async function zinterWithScoresWithMinAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Intersection results are aggregated by the MIN score of elements + const zinterWithScoresResults = await client.zinterWithScores([key1, key2], "MIN"); + const expectedMapMin = { + one: 1.0, + two: 2.0, + }; + expect(zinterWithScoresResults).toEqual(expectedMapMin); + } + + async function zinterWithScoresWithSumAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Intersection results are aggregated by the SUM score of elements + const zinterWithScoresResults = await client.zinterWithScores([key1, key2], "SUM"); + const expectedMapSum = { + one: 2.5, + two: 4.5, + }; + expect(zinterWithScoresResults).toEqual(expectedMapSum); + } + + async function zinterWithScoresWithWeightsAndAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Intersection results are aggregated by the SUM score of elements with weights + const zinterWithScoresResults = await client.zinterWithScores([[key1, 3], [key2, 2]], "SUM"); + const expectedMapSum = { + one: 6, + two: 11, + }; + expect(zinterWithScoresResults).toEqual(expectedMapSum); + } + + async function zinterEmptyCases(client: BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + + // Non existing key zinter + expect( + await client.zinter([ + key1, + "{testKey}-non_existing_key", + ]), + ).toEqual([]); + + // Non existing key zinterWithScores + expect( + await client.zinterWithScores([ + key1, + "{testKey}-non_existing_key", + ]), + ).toEqual({}); + + // Empty list check zinter + await expect(client.zinter([])).rejects.toThrow(); + + // Empty list check zinterWithScores + await expect(client.zinterWithScores([])).rejects.toThrow(); + } + + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `zinter test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + await zinterBasicTest(client); + await zinterWithScoresBasicTest(client); + await zinterWithScoresWithMaxAggregation(client); + await zinterWithScoresWithMinAggregation(client); + await zinterWithScoresWithSumAggregation(client); + await zinterWithScoresWithWeightsAndAggregation(client); + await zinterEmptyCases(client); + }, protocol); + }, + config.timeout, + ); + + async function zunionBasicTest(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + const resultZunion = await client.zunion([key1, key2]); + const expectedZunion = ["one", "two", "three"]; + + expect(resultZunion.sort()).toEqual(expectedZunion.sort()); + } + + async function zunionWithScoresBasicTest(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + const resultZunionWithScores = await client.zunionWithScores([key1, key2]); + const expectedZunionWithScores = { + one: 2.5, + two: 4.5, + three: 3.5 + }; + expect(resultZunionWithScores).toEqual(expectedZunionWithScores); + } + + async function zunionWithScoresWithMaxAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Union results are aggregated by the MAX score of elements + const zunionWithScoresResults = await client.zunionWithScores([key1, key2], "MAX"); + const expectedMapMax = { + one: 1.5, + two: 2.5, + three: 3.5 + }; + expect(zunionWithScoresResults).toEqual(expectedMapMax); + } + + async function zunionWithScoresWithMinAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Union results are aggregated by the MIN score of elements + const zunionWithScoresResults = await client.zunionWithScores([key1, key2], "MIN"); + const expectedMapMin = { + one: 1.0, + two: 2.0, + three: 3.5 + }; + expect(zunionWithScoresResults).toEqual(expectedMapMin); + } + + async function zunionWithScoresWithSumAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Union results are aggregated by the SUM score of elements + const zunionWithScoresResults = await client.zunionWithScores([key1, key2], "SUM"); + const expectedMapSum = { + one: 2.5, + two: 4.5, + three: 3.5 + }; + expect(zunionWithScoresResults).toEqual(expectedMapSum); + } + + async function zunionWithScoresWithWeightsAndAggregation(client:BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + const key2 = "{testKey}:2-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + const membersScores2 = { one: 1.5, two: 2.5, three: 3.5 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + expect(await client.zadd(key2, membersScores2)).toEqual(3); + + // Union results are aggregated by the SUM score of elements with weights + const zunionWithScoresResults = await client.zunionWithScores([[key1, 3], [key2, 2]], "SUM"); + const expectedMapSum = { + one: 6, + two: 11, + three: 7 + }; + expect(zunionWithScoresResults).toEqual(expectedMapSum); + } + + async function zunionEmptyCases(client: BaseClient) { + const key1 = "{testKey}:1-" + uuidv4(); + + const membersScores1 = { one: 1.0, two: 2.0 }; + + expect(await client.zadd(key1, membersScores1)).toEqual(2); + + // Non existing key zunion + expect( + await client.zunion([ + key1, + "{testKey}-non_existing_key", + ]), + ).toEqual(["one", "two"]); + + // Non existing key zunionWithScores + expect( + await client.zunionWithScores([ + key1, + "{testKey}-non_existing_key", + ]), + ).toEqual(membersScores1); + + // Empty list check zunion + await expect(client.zunion([])).rejects.toThrow(); + + // Empty list check zunionWithScores + await expect(client.zunionWithScores([])).rejects.toThrow(); + } + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `zunion test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + await zunionBasicTest(client); + await zunionWithScoresBasicTest(client); + await zunionWithScoresWithMaxAggregation(client); + await zunionWithScoresWithMinAggregation(client); + await zunionWithScoresWithSumAggregation(client); + await zunionWithScoresWithWeightsAndAggregation(client); + await zunionEmptyCases(client); + }, protocol); + }, + config.timeout, + ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `type test_%p`, async (protocol) => { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index bf840b29d4..8b12cebed6 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -33,7 +33,7 @@ import { SignedEncoding, SortOrder, Transaction, - UnsignedEncoding, + UnsignedEncoding } from ".."; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -472,6 +472,8 @@ export async function transactionTest( const key22 = "{key}" + uuidv4(); // list for sort const key23 = "{key}" + uuidv4(); // zset random const key24 = "{key}" + uuidv4(); // list value + const key25 = "{key}" + uuidv4(); // sorted set + const key26 = "{key}" + uuidv4(); // sorted set const field = uuidv4(); const value = uuidv4(); // array of tuples - first element is test name/description, second - expected return value @@ -772,6 +774,16 @@ export async function transactionTest( responseData.push(['zmscore(key12, ["two", "one"]', [2.0, 1.0]]); baseTransaction.zinterstore(key12, [key12, key13]); responseData.push(["zinterstore(key12, [key12, key13])", 0]); + baseTransaction.zadd(key25, { one: 1, two: 2 }); + responseData.push(["zadd(key25, { one: 1, two: 2 })", 2]); + baseTransaction.zadd(key26, { one: 1, two: 2, three: 3.5 }); + responseData.push(["zadd(key26, { one: 1, two: 2, three: 3.5 })", 3]); + baseTransaction.zinter([key26, key25]); + responseData.push(["zinter([key26, key25])", ["one", "two"]]); + baseTransaction.zinterWithScores([key26, key25]); + responseData.push(["zinterWithScores([key26, key25])", {one: 2, two: 4}]); + baseTransaction.zunionWithScores([key26, key25]); + responseData.push(["zunionWithScores([key26, key25])", {one: 2, two: 4, three: 3.5}]); } else { baseTransaction.zinterstore(key12, [key12, key13]); responseData.push(["zinterstore(key12, [key12, key13])", 2]); From 6e5f77a88f5c670294918e487425a0473755aec4 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Thu, 13 Jun 2024 14:33:31 +0000 Subject: [PATCH 3/6] add cross slot tests Signed-off-by: Adar Ovadia --- CHANGELOG.md | 1 + node/src/BaseClient.ts | 34 ++++++++++++++++----------- node/src/Commands.ts | 5 ++++ node/tests/GlideClusterClient.test.ts | 6 ++++- 4 files changed, 31 insertions(+), 15 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6730c12791..c6e212247d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ #### Changes +* Node: Added ZINTER and ZUNION commands ([#1556](https://github.com/aws/glide-for-redis/pull/1556)) * Node: Added EXPIRETIME and PEXPIRETIME commands ([#2063](https://github.com/valkey-io/valkey-glide/pull/2063)) * Node: Added SORT commands ([#2028](https://github.com/valkey-io/valkey-glide/pull/2028)) * Node: Added LASTSAVE command ([#2059](https://github.com/valkey-io/valkey-glide/pull/2059)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index e1ea5ebd36..89377386af 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -3084,9 +3084,10 @@ export class BaseClient { * * @example * ```typescript - * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) - * await client.zadd("key2", {"member1": 9.5}) - * await client.zinter(["key1", "key2"]) // Output: ['member1'] + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); + * await client.zadd("key2", {"member1": 9.5}); + * const result = await client.zinter(["key1", "key2"]); + * console.log(result); // Output: ['member1'] * ``` */ public zinter( @@ -3116,10 +3117,12 @@ export class BaseClient { * * @example * ```typescript - * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) - * await client.zadd("key2", {"member1": 9.5}) - * await client.zinterWithScores(["key1", "key2"]) // Output: {'member1': 20} - "member1" with score of 20 is the result - * await client.zinterWithScores(["key1", "key2"], AggregationType.MAX) // Output: {'member1': 10.5} - "member1" with score of 10.5 is the result. + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); + * await client.zadd("key2", {"member1": 9.5}); + * const result1 = await client.zinterWithScores(["key1", "key2"]); + * console.log(result1); // Output: {'member1': 20} - "member1" with score of 20 is the result + * const result2 = await client.zinterWithScores(["key1", "key2"], AggregationType.MAX) + * console.log(result2); // Output: {'member1': 10.5} - "member1" with score of 10.5 is the result. * ``` */ public zinterWithScores( @@ -3148,9 +3151,10 @@ export class BaseClient { * * @example * ```typescript - * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) - * await client.zadd("key2", {"member1": 9.5}) - * await client.zunion(["key1", "key2"]) // Output: ['member1', 'member2'] + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); + * await client.zadd("key2", {"member1": 9.5}); + * const result = await client.zunion(["key1", "key2"]); + * console.log(result); // Output: ['member1', 'member2'] * ``` */ public zunion( @@ -3179,10 +3183,12 @@ export class BaseClient { * * @example * ```typescript - * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}) - * await client.zadd("key2", {"member1": 9.5}) - * await client.zunionWithScores(["key1", "key2"]) // {'member1': 20, 'member2': 8.2} - * await client.zunionWithScores(["key1", "key2"], "MAX") // {'member1': 10.5, 'member2': 8.2} + * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); + * await client.zadd("key2", {"member1": 9.5}); + * const result1 = await client.zunionWithScores(["key1", "key2"]); + * console.log(result1); // {'member1': 20, 'member2': 8.2} + * const result2 = await client.zunionWithScores(["key1", "key2"], "MAX"); + * console.log(result2); // {'member1': 10.5, 'member2': 8.2} * ``` */ public zunionWithScores( diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 5b64861594..0438027f41 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1434,6 +1434,10 @@ export function createZUnion( return createCommand(RequestType.ZUnion, args); } +/** + * @internal + * Helper function for Zcommands (ZInter, ZinterStore, ZUnion..) that arranges arguments in the server's required order. + */ function createZCmdArgs( keys: string[] | KeyWeight[], aggregationType?: AggregationType, @@ -1441,6 +1445,7 @@ function createZCmdArgs( destination?: string, ): string[] { const args = []; + if (destination) { args.push(destination); } diff --git a/node/tests/GlideClusterClient.test.ts b/node/tests/GlideClusterClient.test.ts index 930df79c62..a058546dc2 100644 --- a/node/tests/GlideClusterClient.test.ts +++ b/node/tests/GlideClusterClient.test.ts @@ -311,7 +311,7 @@ describe("GlideClusterClient", () => { TIMEOUT, ); - it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + it.only.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `check that multi key command returns a cross slot error`, async (protocol) => { const client = await GlideClusterClient.createClient( @@ -327,8 +327,12 @@ describe("GlideClusterClient", () => { client.smove("abc", "zxy", "value"), client.renamenx("abc", "zxy"), client.sinter(["abc", "zxy", "lkn"]), + client.zinter(["abc", "zxy", "lkn"]), + client.zinterWithScores(["abc", "zxy", "lkn"]), client.sinterstore("abc", ["zxy", "lkn"]), client.zinterstore("abc", ["zxy", "lkn"]), + client.zunion(["abc", "zxy", "lkn"]), + client.zunionWithScores(["abc", "zxy", "lkn"]), client.sunionstore("abc", ["zxy", "lkn"]), client.sunion(["abc", "zxy", "lkn"]), client.pfcount(["abc", "zxy", "lkn"]), From 441071a7980f2a7b838ac0f855fa7536d422a2f4 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 15 Jun 2024 09:46:31 +0000 Subject: [PATCH 4/6] remove debuging helper Signed-off-by: Adar Ovadia --- node/tests/GlideClusterClient.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/tests/GlideClusterClient.test.ts b/node/tests/GlideClusterClient.test.ts index a058546dc2..48d5d314b6 100644 --- a/node/tests/GlideClusterClient.test.ts +++ b/node/tests/GlideClusterClient.test.ts @@ -311,7 +311,7 @@ describe("GlideClusterClient", () => { TIMEOUT, ); - it.only.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `check that multi key command returns a cross slot error`, async (protocol) => { const client = await GlideClusterClient.createClient( From ebb39374eb576dc8884456bb98c4f3001ace56d6 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 15 Jun 2024 17:00:36 +0000 Subject: [PATCH 5/6] add 'since' section Signed-off-by: Adar Ovadia --- node/src/BaseClient.ts | 4 ++++ node/src/Transaction.ts | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 89377386af..ad37ede90b 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -3075,6 +3075,8 @@ export class BaseClient { * * When in cluster mode, all keys in `keys` must map to the same hash slot. * + * since - Valkey version 6.2.0. + * * See https://valkey.io/commands/zinter/ for more details. * * @param keys - The keys of the sorted sets. @@ -3142,6 +3144,8 @@ export class BaseClient { * * When in cluster mode, all keys in `keys` must map to the same hash slot. * + * since - Valkey version 6.2.0. + * * See https://valkey.io/commands/zunion/ for more details. * * @param keys - The keys of the sorted sets. diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 95bec38f3c..b15299b519 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -1698,6 +1698,8 @@ export class BaseTransaction> { * * When in cluster mode, all keys in `keys` must map to the same hash slot. * + * since - Valkey version 6.2.0. + * * See https://valkey.io/commands/zinter/ for more details. * * @param keys - The keys of the sorted sets. @@ -1747,6 +1749,8 @@ export class BaseTransaction> { * * When in cluster mode, all keys in `keys` must map to the same hash slot. * + * since - Valkey version 6.2.0. + * * See https://valkey.io/commands/zunion/ for more details. * * @param keys - The keys of the sorted sets. From e0c497bd97fad6fa34b224c21911b291102dce47 Mon Sep 17 00:00:00 2001 From: Adar Ovadia Date: Mon, 5 Aug 2024 09:10:11 +0000 Subject: [PATCH 6/6] fix lint Signed-off-by: Adar Ovadia --- node/src/BaseClient.ts | 58 ++++++++---------- node/src/Transaction.ts | 64 ++++++++------------ node/tests/SharedTests.ts | 117 ++++++++++++++++++++++-------------- node/tests/TestUtilities.ts | 12 +++- 4 files changed, 130 insertions(+), 121 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index ad37ede90b..4ad3790ab3 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -181,7 +181,7 @@ import { createZRevRankWithScore, createZScan, createZScore, - createZUnion + createZUnion, } from "./Commands"; import { ClosingError, @@ -3074,16 +3074,16 @@ export class BaseClient { * To store the result in a key as a sorted set, see `zinterStore`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * + * * since - Valkey version 6.2.0. - * + * * See https://valkey.io/commands/zinter/ for more details. - * + * * @param keys - The keys of the sorted sets. * @returns The resulting array of intersecting elements. - * + * * since Valkey version 6.2.0. - * + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); @@ -3092,12 +3092,8 @@ export class BaseClient { * console.log(result); // Output: ['member1'] * ``` */ - public zinter( - keys: string[], - ): Promise { - return this.createWritePromise( - createZInter(keys), - ); + public zinter(keys: string[]): Promise { + return this.createWritePromise(createZInter(keys)); } /** @@ -3106,17 +3102,17 @@ export class BaseClient { * To store the result in a key as a sorted set, see `zinterStore`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * + * * See https://valkey.io/commands/zinter/ for more details. - * + * * @param keys - The keys of the sorted sets with possible formats: * string[] - for keys only. * KeyWeight[] - for weighted keys with score multipliers. * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * @returns The resulting sorted set with scores. - * + * * since Valkey version 6.2.0. - * + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); @@ -3139,20 +3135,20 @@ export class BaseClient { /** * Computes the union of sorted sets given by the specified `keys` and returns a list of union elements. * To get the scores as well, see `zunionWithScores`. - * + * * To store the result in a key as a sorted set, see `zunionStore`. - * + * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * + * * since - Valkey version 6.2.0. - * + * * See https://valkey.io/commands/zunion/ for more details. - * + * * @param keys - The keys of the sorted sets. * @returns The resulting array of union elements. - * + * * since Valkey version 6.2.0. - * + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); @@ -3161,12 +3157,8 @@ export class BaseClient { * console.log(result); // Output: ['member1', 'member2'] * ``` */ - public zunion( - keys: string[], - ): Promise { - return this.createWritePromise( - createZUnion(keys), - ); + public zunion(keys: string[]): Promise { + return this.createWritePromise(createZUnion(keys)); } /** @@ -3174,17 +3166,17 @@ export class BaseClient { * To get the elements only, see `zunion`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * + * * See https://valkey.io/commands/zunion/ for more details. - * + * * @param keys - The keys of the sorted sets with possible formats: * string[] - for keys only. * KeyWeight[] - for weighted keys with score multipliers. * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * @returns The resulting sorted set with scores. - * + * * since Valkey version 6.2.0. - * + * * @example * ```typescript * await client.zadd("key1", {"member1": 10.5, "member2": 8.2}); diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index b15299b519..8194506e78 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -1678,8 +1678,8 @@ export class BaseTransaction> { * KeyWeight[] - for weighted keys with score multipliers. * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * Command Response - The number of elements in the resulting sorted set stored at `destination`. - * - * since + * + * since Valkey version 6.2.0. */ public zinterstore( destination: string, @@ -1697,22 +1697,16 @@ export class BaseTransaction> { * To store the result in a key as a sorted set, see `zinterstore`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * - * since - Valkey version 6.2.0. - * + * * See https://valkey.io/commands/zinter/ for more details. - * + * * @param keys - The keys of the sorted sets. * Command Response - The resulting array of intersecting elements. - * - * since Valkey version 6.2.0. + * + * since Valkey version 6.2.0. */ - public zinter( - keys: string[], - ): T { - return this.addAndReturn( - createZInter(keys), - ); + public zinter(keys: string[]): T { + return this.addAndReturn(createZInter(keys)); } /** @@ -1721,49 +1715,41 @@ export class BaseTransaction> { * To store the result in a key as a sorted set, see `zinterstore`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * + * * See https://valkey.io/commands/zinter/ for more details. - * + * * @param keys - The keys of the sorted sets with possible formats: * string[] - for keys only. * KeyWeight[] - for weighted keys with score multipliers. * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * Command Response - The resulting sorted set with scores. - * - * since Valkey version 6.2.0. + * + * since Valkey version 6.2.0. */ public zinterWithScores( keys: string[] | KeyWeight[], aggregationType?: AggregationType, ): T { - return this.addAndReturn( - createZInter(keys, aggregationType, true), - ); + return this.addAndReturn(createZInter(keys, aggregationType, true)); } /** * Computes the union of sorted sets given by the specified `keys` and returns a list of union elements. * To get the scores as well, see `zunion_withscores`. - * + * * To store the result in a key as a sorted set, see `zunionstore`. - * + * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * - * since - Valkey version 6.2.0. - * + * * See https://valkey.io/commands/zunion/ for more details. - * + * * @param keys - The keys of the sorted sets. * Command Response - The resulting array of union elements. - * + * * since Valkey version 6.2.0. */ - public zunion( - keys: string[], - ): T { - return this.addAndReturn( - createZUnion(keys), - ); + public zunion(keys: string[]): T { + return this.addAndReturn(createZUnion(keys)); } /** @@ -1771,24 +1757,22 @@ export class BaseTransaction> { * To get the elements only, see `zunion`. * * When in cluster mode, all keys in `keys` must map to the same hash slot. - * + * * See https://valkey.io/commands/zunion/ for more details. - * + * * @param keys - The keys of the sorted sets with possible formats: * string[] - for keys only. * KeyWeight[] - for weighted keys with score multipliers. * @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`. * Commnd Response - The resulting sorted set with scores. - * + * * since Valkey version 6.2.0. */ public zunionWithScores( keys: string[] | KeyWeight[], aggregationType?: AggregationType, ): T { - return this.addAndReturn( - createZUnion(keys, aggregationType, true), - ); + return this.addAndReturn(createZUnion(keys, aggregationType, true)); } /** diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 89d8317475..e3e7939814 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -3726,7 +3726,7 @@ export function runBaseTests(config: { config.timeout, ); - async function zinterBasicTest(client:BaseClient) { + async function zinterBasicTest(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3741,7 +3741,7 @@ export function runBaseTests(config: { expect(resultZinter).toEqual(expectedZinter); } - async function zinterWithScoresBasicTest(client:BaseClient) { + async function zinterWithScoresBasicTest(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3751,7 +3751,10 @@ export function runBaseTests(config: { expect(await client.zadd(key1, membersScores1)).toEqual(2); expect(await client.zadd(key2, membersScores2)).toEqual(3); - const resultZinterWithScores = await client.zinterWithScores([key1, key2]); + const resultZinterWithScores = await client.zinterWithScores([ + key1, + key2, + ]); const expectedZinterWithScores = { one: 2.5, two: 4.5, @@ -3759,7 +3762,7 @@ export function runBaseTests(config: { expect(resultZinterWithScores).toEqual(expectedZinterWithScores); } - async function zinterWithScoresWithMaxAggregation(client:BaseClient) { + async function zinterWithScoresWithMaxAggregation(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3770,7 +3773,10 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Intersection results are aggregated by the MAX score of elements - const zinterWithScoresResults = await client.zinterWithScores([key1, key2], "MAX"); + const zinterWithScoresResults = await client.zinterWithScores( + [key1, key2], + "MAX", + ); const expectedMapMax = { one: 1.5, two: 2.5, @@ -3778,7 +3784,7 @@ export function runBaseTests(config: { expect(zinterWithScoresResults).toEqual(expectedMapMax); } - async function zinterWithScoresWithMinAggregation(client:BaseClient) { + async function zinterWithScoresWithMinAggregation(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3789,7 +3795,10 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Intersection results are aggregated by the MIN score of elements - const zinterWithScoresResults = await client.zinterWithScores([key1, key2], "MIN"); + const zinterWithScoresResults = await client.zinterWithScores( + [key1, key2], + "MIN", + ); const expectedMapMin = { one: 1.0, two: 2.0, @@ -3797,7 +3806,7 @@ export function runBaseTests(config: { expect(zinterWithScoresResults).toEqual(expectedMapMin); } - async function zinterWithScoresWithSumAggregation(client:BaseClient) { + async function zinterWithScoresWithSumAggregation(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3808,7 +3817,10 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Intersection results are aggregated by the SUM score of elements - const zinterWithScoresResults = await client.zinterWithScores([key1, key2], "SUM"); + const zinterWithScoresResults = await client.zinterWithScores( + [key1, key2], + "SUM", + ); const expectedMapSum = { one: 2.5, two: 4.5, @@ -3816,7 +3828,9 @@ export function runBaseTests(config: { expect(zinterWithScoresResults).toEqual(expectedMapSum); } - async function zinterWithScoresWithWeightsAndAggregation(client:BaseClient) { + async function zinterWithScoresWithWeightsAndAggregation( + client: BaseClient, + ) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3827,7 +3841,13 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Intersection results are aggregated by the SUM score of elements with weights - const zinterWithScoresResults = await client.zinterWithScores([[key1, 3], [key2, 2]], "SUM"); + const zinterWithScoresResults = await client.zinterWithScores( + [ + [key1, 3], + [key2, 2], + ], + "SUM", + ); const expectedMapSum = { one: 6, two: 11, @@ -3840,18 +3860,12 @@ export function runBaseTests(config: { // Non existing key zinter expect( - await client.zinter([ - key1, - "{testKey}-non_existing_key", - ]), + await client.zinter([key1, "{testKey}-non_existing_key"]), ).toEqual([]); // Non existing key zinterWithScores expect( - await client.zinterWithScores([ - key1, - "{testKey}-non_existing_key", - ]), + await client.zinterWithScores([key1, "{testKey}-non_existing_key"]), ).toEqual({}); // Empty list check zinter @@ -3860,7 +3874,6 @@ export function runBaseTests(config: { // Empty list check zinterWithScores await expect(client.zinterWithScores([])).rejects.toThrow(); } - it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `zinter test_%p`, @@ -3878,7 +3891,7 @@ export function runBaseTests(config: { config.timeout, ); - async function zunionBasicTest(client:BaseClient) { + async function zunionBasicTest(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3890,11 +3903,11 @@ export function runBaseTests(config: { const resultZunion = await client.zunion([key1, key2]); const expectedZunion = ["one", "two", "three"]; - + expect(resultZunion.sort()).toEqual(expectedZunion.sort()); } - async function zunionWithScoresBasicTest(client:BaseClient) { + async function zunionWithScoresBasicTest(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3904,16 +3917,19 @@ export function runBaseTests(config: { expect(await client.zadd(key1, membersScores1)).toEqual(2); expect(await client.zadd(key2, membersScores2)).toEqual(3); - const resultZunionWithScores = await client.zunionWithScores([key1, key2]); + const resultZunionWithScores = await client.zunionWithScores([ + key1, + key2, + ]); const expectedZunionWithScores = { one: 2.5, two: 4.5, - three: 3.5 + three: 3.5, }; expect(resultZunionWithScores).toEqual(expectedZunionWithScores); } - async function zunionWithScoresWithMaxAggregation(client:BaseClient) { + async function zunionWithScoresWithMaxAggregation(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3924,16 +3940,19 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Union results are aggregated by the MAX score of elements - const zunionWithScoresResults = await client.zunionWithScores([key1, key2], "MAX"); + const zunionWithScoresResults = await client.zunionWithScores( + [key1, key2], + "MAX", + ); const expectedMapMax = { one: 1.5, two: 2.5, - three: 3.5 + three: 3.5, }; expect(zunionWithScoresResults).toEqual(expectedMapMax); } - async function zunionWithScoresWithMinAggregation(client:BaseClient) { + async function zunionWithScoresWithMinAggregation(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3944,16 +3963,19 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Union results are aggregated by the MIN score of elements - const zunionWithScoresResults = await client.zunionWithScores([key1, key2], "MIN"); + const zunionWithScoresResults = await client.zunionWithScores( + [key1, key2], + "MIN", + ); const expectedMapMin = { one: 1.0, two: 2.0, - three: 3.5 + three: 3.5, }; expect(zunionWithScoresResults).toEqual(expectedMapMin); } - async function zunionWithScoresWithSumAggregation(client:BaseClient) { + async function zunionWithScoresWithSumAggregation(client: BaseClient) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3964,16 +3986,21 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Union results are aggregated by the SUM score of elements - const zunionWithScoresResults = await client.zunionWithScores([key1, key2], "SUM"); + const zunionWithScoresResults = await client.zunionWithScores( + [key1, key2], + "SUM", + ); const expectedMapSum = { one: 2.5, two: 4.5, - three: 3.5 + three: 3.5, }; expect(zunionWithScoresResults).toEqual(expectedMapSum); } - async function zunionWithScoresWithWeightsAndAggregation(client:BaseClient) { + async function zunionWithScoresWithWeightsAndAggregation( + client: BaseClient, + ) { const key1 = "{testKey}:1-" + uuidv4(); const key2 = "{testKey}:2-" + uuidv4(); @@ -3984,11 +4011,17 @@ export function runBaseTests(config: { expect(await client.zadd(key2, membersScores2)).toEqual(3); // Union results are aggregated by the SUM score of elements with weights - const zunionWithScoresResults = await client.zunionWithScores([[key1, 3], [key2, 2]], "SUM"); + const zunionWithScoresResults = await client.zunionWithScores( + [ + [key1, 3], + [key2, 2], + ], + "SUM", + ); const expectedMapSum = { one: 6, two: 11, - three: 7 + three: 7, }; expect(zunionWithScoresResults).toEqual(expectedMapSum); } @@ -4002,18 +4035,12 @@ export function runBaseTests(config: { // Non existing key zunion expect( - await client.zunion([ - key1, - "{testKey}-non_existing_key", - ]), + await client.zunion([key1, "{testKey}-non_existing_key"]), ).toEqual(["one", "two"]); // Non existing key zunionWithScores expect( - await client.zunionWithScores([ - key1, - "{testKey}-non_existing_key", - ]), + await client.zunionWithScores([key1, "{testKey}-non_existing_key"]), ).toEqual(membersScores1); // Empty list check zunion diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 8b12cebed6..4fd0851aa5 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -33,7 +33,7 @@ import { SignedEncoding, SortOrder, Transaction, - UnsignedEncoding + UnsignedEncoding, } from ".."; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -781,9 +781,15 @@ export async function transactionTest( baseTransaction.zinter([key26, key25]); responseData.push(["zinter([key26, key25])", ["one", "two"]]); baseTransaction.zinterWithScores([key26, key25]); - responseData.push(["zinterWithScores([key26, key25])", {one: 2, two: 4}]); + responseData.push([ + "zinterWithScores([key26, key25])", + { one: 2, two: 4 }, + ]); baseTransaction.zunionWithScores([key26, key25]); - responseData.push(["zunionWithScores([key26, key25])", {one: 2, two: 4, three: 3.5}]); + responseData.push([ + "zunionWithScores([key26, key25])", + { one: 2, two: 4, three: 3.5 }, + ]); } else { baseTransaction.zinterstore(key12, [key12, key13]); responseData.push(["zinterstore(key12, [key12, key13])", 2]);