From 95653139df214b750828fc9280b073df7418269a Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Wed, 28 Aug 2024 13:19:48 -0700 Subject: [PATCH] Node: Add binary variant to sorted set commands - part 1. (#2190) * Add binary variant to sorted set commands - part 1. Signed-off-by: Yury-Fridlyand --- CHANGELOG.md | 1 + node/src/BaseClient.ts | 141 ++++++++++++++++++++++++-------------- node/src/Commands.ts | 61 +++++++++-------- node/src/Transaction.ts | 73 +++++++++++--------- node/tests/SharedTests.ts | 136 +++++++++++++++++++++++++----------- 5 files changed, 259 insertions(+), 153 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 78bb75ed77..f9a1decdad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,5 @@ #### Changes +* Node: Added binary variant to sorted set commands - part 1 ([#2190](https://github.com/valkey-io/valkey-glide/pull/2190)) * Node: Added binary variant to HASH commands ([#2194](https://github.com/valkey-io/valkey-glide/pull/2194)) * Node: Added binary variant to server management commands ([#2179](https://github.com/valkey-io/valkey-glide/pull/2179)) * Node: Added/updated binary variant to connection management commands and WATCH/UNWATCH ([#2160](https://github.com/valkey-io/valkey-glide/pull/2160)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 0e14bcfe12..ce8afe3112 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -3337,7 +3337,7 @@ export class BaseClient { * @see {@link https://valkey.io/commands/ttl/|valkey.io} for details. * * @param key - The key to return its timeout. - * @returns TTL in seconds, -2 if `key` does not exist or -1 if `key` exists but has no associated expire. + * @returns TTL in seconds, `-2` if `key` does not exist or `-1` if `key` exists but has no associated expire. * * @example * ```typescript @@ -3495,16 +3495,17 @@ export class BaseClient { return this.createWritePromise(createXRevRange(key, end, start, count)); } - /** Adds members with their scores to the sorted set stored at `key`. + /** + * Adds members with their scores to the sorted set stored at `key`. * If a member is already a part of the sorted set, its score is updated. * * @see {@link https://valkey.io/commands/zadd/|valkey.io} for more details. * * @param key - The key of the sorted set. * @param membersScoresMap - A mapping of members to their corresponding scores. - * @param options - The ZAdd options. + * @param options - (Optional) The ZAdd options - see {@link ZAddOptions}. * @returns The number of elements added to the sorted set. - * If `changed` is set, returns the number of elements updated in the sorted set. + * If {@link ZAddOptions.changed|changed} is set, returns the number of elements updated in the sorted set. * * @example * ```typescript @@ -3531,7 +3532,8 @@ export class BaseClient { ); } - /** Increments the score of member in the sorted set stored at `key` by `increment`. + /** + * Increments the score of member in the sorted set stored at `key` by `increment`. * If `member` does not exist in the sorted set, it is added with `increment` as its score (as if its previous score was 0.0). * If `key` does not exist, a new sorted set with the specified member as its sole member is created. * @@ -3540,7 +3542,7 @@ export class BaseClient { * @param key - The key of the sorted set. * @param member - A member in the sorted set to increment. * @param increment - The score to increment the member. - * @param options - The ZAdd options. + * @param options - (Optional) The ZAdd options - see {@link ZAddOptions}. * @returns The score of the member. * If there was a conflict with the options, the operation aborts and null is returned. * @@ -3597,13 +3599,14 @@ export class BaseClient { return this.createWritePromise(createZRem(key, members)); } - /** Returns the cardinality (number of elements) of the sorted set stored at `key`. + /** + * Returns the cardinality (number of elements) of the sorted set stored at `key`. * * @see {@link https://valkey.io/commands/zcard/|valkey.io} for more details. * * @param key - The key of the sorted set. * @returns The number of elements in the sorted set. - * If `key` does not exist, it is treated as an empty sorted set, and this command returns 0. + * If `key` does not exist, it is treated as an empty sorted set, and this command returns `0`. * * @example * ```typescript @@ -3619,7 +3622,7 @@ export class BaseClient { * console.log(result); // Output: 0 * ``` */ - public async zcard(key: string): Promise { + public async zcard(key: GlideString): Promise { return this.createWritePromise(createZCard(key)); } @@ -3641,7 +3644,10 @@ export class BaseClient { * console.log(cardinality); // Output: 3 - The intersection of the sorted sets at "key1" and "key2" has a cardinality of 3. * ``` */ - public async zintercard(keys: string[], limit?: number): Promise { + public async zintercard( + keys: GlideString[], + limit?: number, + ): Promise { return this.createWritePromise(createZInterCard(keys, limit)); } @@ -3654,6 +3660,7 @@ export class BaseClient { * @remarks Since Valkey version 6.2.0. * * @param keys - The keys of the sorted sets. + * @param options - (Optional) See {@link DecoderOption}. * @returns An `array` of elements representing the difference between the sorted sets. * If the first key does not exist, it is treated as an empty sorted set, and the command returns an empty `array`. * @@ -3666,8 +3673,11 @@ export class BaseClient { * console.log(result); // Output: ["member1"] - "member1" is in "zset1" but not "zset2" or "zset3". * ``` */ - public async zdiff(keys: string[]): Promise { - return this.createWritePromise(createZDiff(keys)); + public async zdiff( + keys: GlideString[], + options?: DecoderOption, + ): Promise { + return this.createWritePromise(createZDiff(keys), options); } /** @@ -3679,6 +3689,7 @@ export class BaseClient { * @remarks Since Valkey version 6.2.0. * * @param keys - The keys of the sorted sets. + * @param options - (Optional) See {@link DecoderOption}. * @returns A map of elements and their scores representing the difference between the sorted sets. * If the first key does not exist, it is treated as an empty sorted set, and the command returns an empty `array`. * @@ -3692,9 +3703,11 @@ export class BaseClient { * ``` */ public async zdiffWithScores( - keys: string[], + keys: GlideString[], + options?: DecoderOption, ): Promise> { - return this.createWritePromise(createZDiffWithScores(keys)); + // TODO GlideString in Record and add a test + return this.createWritePromise(createZDiffWithScores(keys), options); } /** @@ -3722,8 +3735,8 @@ export class BaseClient { * ``` */ public async zdiffstore( - destination: string, - keys: string[], + destination: GlideString, + keys: GlideString[], ): Promise { return this.createWritePromise(createZDiffStore(destination, keys)); } @@ -3823,7 +3836,8 @@ export class BaseClient { return this.createWritePromise(createZMScore(key, members)); } - /** Returns the number of members in the sorted set stored at `key` with scores between `minScore` and `maxScore`. + /** + * Returns the number of members in the sorted set stored at `key` with scores between `minScore` and `maxScore`. * * @see {@link https://valkey.io/commands/zcount/|valkey.io} for more details. * @@ -3831,8 +3845,8 @@ export class BaseClient { * @param minScore - The minimum score to count from. Can be positive/negative infinity, or specific score and inclusivity. * @param maxScore - The maximum score to count up to. Can be positive/negative infinity, or specific score and inclusivity. * @returns The number of members in the specified score range. - * If `key` does not exist, it is treated as an empty sorted set, and the command returns 0. - * If `minScore` is greater than `maxScore`, 0 is returned. + * If `key` does not exist, it is treated as an empty sorted set, and the command returns `0`. + * If `minScore` is greater than `maxScore`, `0` is returned. * * @example * ```typescript @@ -3849,7 +3863,7 @@ export class BaseClient { * ``` */ public async zcount( - key: string, + key: GlideString, minScore: Boundary, maxScore: Boundary, ): Promise { @@ -3998,26 +4012,33 @@ export class BaseClient { * * @param destination - The key of the destination sorted set. * @param keys - The keys of the sorted sets with possible formats: - * string[] - for keys only. - * KeyWeight[] - for weighted keys with score multipliers. + * - `GlideString[]` - for keys only. + * - `KeyWeight[]` - for weighted keys with score multipliers. * @param aggregationType - (Optional) Specifies the aggregation strategy to apply when combining the scores of elements. See {@link AggregationType}. * If `aggregationType` is not specified, defaults to `AggregationType.SUM`. * @returns The number of elements in the resulting sorted set stored at `destination`. * * @example * ```typescript - * // Example usage of zinterstore command with an existing key * 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.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.zrangeWithScores("my_sorted_set", RangeByIndex(0, -1)) // Output: {'member1': 10.5} - "member1" is now stored in "my_sorted_set" with score of 10.5. + * + * // use `zinterstore` with default aggregation and weights + * console.log(await client.zinterstore("my_sorted_set", ["key1", "key2"])) + * // Output: 1 - Indicates that the sorted set "my_sorted_set" contains one element. + * console.log(await client.zrangeWithScores("my_sorted_set", {start: 0, stop: -1})) + * // Output: {'member1': 20} - "member1" is now stored in "my_sorted_set" with score of 20. + * + * // use `zinterstore` with default weights + * console.log(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. + * console.log(await client.zrangeWithScores("my_sorted_set", {start: 0, stop: -1})) + * // Output: {'member1': 10.5} - "member1" is now stored in "my_sorted_set" with score of 10.5. * ``` */ public async zinterstore( - destination: string, - keys: string[] | KeyWeight[], + destination: GlideString, + keys: GlideString[] | KeyWeight[], aggregationType?: AggregationType, ): Promise { return this.createWritePromise( @@ -4037,6 +4058,7 @@ export class BaseClient { * @see {@link https://valkey.io/commands/zinter/|valkey.io} for details. * * @param keys - The keys of the sorted sets. + * @param options - (Optional) See {@link DecoderOption}. * @returns The resulting array of intersecting elements. * * @example @@ -4047,8 +4069,11 @@ export class BaseClient { * console.log(result); // Output: ['member1'] * ``` */ - public async zinter(keys: string[]): Promise { - return this.createWritePromise(createZInter(keys)); + public async zinter( + keys: GlideString[], + options?: DecoderOption, + ): Promise { + return this.createWritePromise(createZInter(keys), options); } /** @@ -4063,10 +4088,12 @@ export class BaseClient { * @remarks Since Valkey version 6.2.0. * * @param keys - The keys of the sorted sets with possible formats: - * - string[] - for keys only. - * - KeyWeight[] - for weighted keys with score multipliers. - * @param aggregationType - (Optional) Specifies the aggregation strategy to apply when combining the scores of elements. See {@link AggregationType}. - * If `aggregationType` is not specified, defaults to `AggregationType.SUM`. + * - `GlideString[]` - for keys only. + * - `KeyWeight[]` - for weighted keys with score multipliers. + * @param options - (Optional) Additional parameters: + * - (Optional) `aggregationType`: the aggregation strategy to apply when combining the scores of elements. + * If `aggregationType` is not specified, defaults to `AggregationType.SUM`. See {@link AggregationType}. + * - (Optional) `decoder`: see {@link DecoderOption}. * @returns The resulting sorted set with scores. * * @example @@ -4080,11 +4107,13 @@ export class BaseClient { * ``` */ public async zinterWithScores( - keys: string[] | KeyWeight[], - aggregationType?: AggregationType, + keys: GlideString[] | KeyWeight[], + options?: { aggregationType?: AggregationType } & DecoderOption, ): Promise> { + // TODO Record with GlideString and add tests return this.createWritePromise( - createZInter(keys, aggregationType, true), + createZInter(keys, options?.aggregationType, true), + options, ); } @@ -4341,6 +4370,7 @@ export class BaseClient { * @param keys - The keys of the sorted sets. * @param timeout - The number of seconds to wait for a blocking operation to complete. A value of * `0` will block indefinitely. Since 6.0.0: timeout is interpreted as a double instead of an integer. + * @param options - (Optional) See {@link DecoderOption}. * @returns An `array` containing the key where the member was popped out, the member, itself, and the member score. * If no member could be popped and the `timeout` expired, returns `null`. * @@ -4351,10 +4381,11 @@ export class BaseClient { * ``` */ public async bzpopmin( - keys: string[], + keys: GlideString[], timeout: number, - ): Promise<[string, string, number] | null> { - return this.createWritePromise(createBZPopMin(keys, timeout)); + options?: DecoderOption, + ): Promise<[GlideString, GlideString, number] | null> { + return this.createWritePromise(createBZPopMin(keys, timeout), options); } /** Removes and returns the members with the highest scores from the sorted set stored at `key`. @@ -4402,6 +4433,7 @@ export class BaseClient { * @param keys - The keys of the sorted sets. * @param timeout - The number of seconds to wait for a blocking operation to complete. A value of * `0` will block indefinitely. Since 6.0.0: timeout is interpreted as a double instead of an integer. + * @param options - (Optional) See {@link DecoderOption}. * @returns An `array` containing the key where the member was popped out, the member, itself, and the member score. * If no member could be popped and the `timeout` expired, returns `null`. * @@ -4412,10 +4444,11 @@ export class BaseClient { * ``` */ public async bzpopmax( - keys: string[], + keys: GlideString[], timeout: number, - ): Promise<[string, string, number] | null> { - return this.createWritePromise(createBZPopMax(keys, timeout)); + options?: DecoderOption, + ): Promise<[GlideString, GlideString, number] | null> { + return this.createWritePromise(createBZPopMax(keys, timeout), options); } /** @@ -4424,7 +4457,7 @@ export class BaseClient { * @see {@link https://valkey.io/commands/pttl/|valkey.io} for more details. * * @param key - The key to return its timeout. - * @returns TTL in milliseconds. -2 if `key` does not exist, -1 if `key` exists but has no associated expire. + * @returns TTL in milliseconds, `-2` if `key` does not exist, `-1` if `key` exists but has no associated expire. * * @example * ```typescript @@ -6163,7 +6196,9 @@ export class BaseClient { * {@link ScoreFilter.MAX} to pop the member with the lowest/highest score accordingly. * @param timeout - The number of seconds to wait for a blocking operation to complete. * A value of 0 will block indefinitely. - * @param count - (Optional) The number of elements to pop. If not supplied, only one element will be popped. + * @param options - (Optional) Additional parameters: + * - (Optional) `count`: the number of elements to pop. If not supplied, only one element will be popped. + * - (Optional) `decoder`: see {@link DecoderOption}. * @returns A two-element `array` containing the key name of the set from which the element * was popped, and a member-score `Record` of the popped element. * If no member could be popped, returns `null`. @@ -6177,13 +6212,15 @@ export class BaseClient { * ``` */ public async bzmpop( - keys: string[], + keys: GlideString[], modifier: ScoreFilter, timeout: number, - count?: number, - ): Promise<[string, [Record]] | null> { + options?: { count?: number } & DecoderOption, + ): Promise<[string, Record] | null> { + // TODO GlideString in Record return this.createWritePromise( - createBZMPop(keys, modifier, timeout, count), + createBZMPop(keys, modifier, timeout, options?.count), + options, ); } @@ -6213,9 +6250,9 @@ export class BaseClient { * ``` */ public async zincrby( - key: string, + key: GlideString, increment: number, - member: string, + member: GlideString, ): Promise { return this.createWritePromise(createZIncrBy(key, increment, member)); } diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 41c8eea946..f3d6d934d1 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1421,7 +1421,7 @@ export function createZAdd( /** * `KeyWeight` - pair of variables represents a weighted key for the `ZINTERSTORE` and `ZUNIONSTORE` sorted sets commands. */ -export type KeyWeight = [string, number]; +export type KeyWeight = [GlideString, number]; /** * `AggregationType` - representing aggregation types for `ZINTERSTORE` and `ZUNIONSTORE` sorted set commands. */ @@ -1431,8 +1431,8 @@ export type AggregationType = "SUM" | "MIN" | "MAX"; * @internal */ export function createZInterstore( - destination: string, - keys: string[] | KeyWeight[], + destination: GlideString, + keys: GlideString[] | KeyWeight[], aggregationType?: AggregationType, ): command_request.Command { const args = createZCmdArgs(keys, { @@ -1447,7 +1447,7 @@ export function createZInterstore( * @internal */ export function createZInter( - keys: string[] | KeyWeight[], + keys: GlideString[] | KeyWeight[], aggregationType?: AggregationType, withScores?: boolean, ): command_request.Command { @@ -1472,14 +1472,14 @@ export function createZUnion( * Helper function for Zcommands (ZInter, ZinterStore, ZUnion..) that arranges arguments in the server's required order. */ function createZCmdArgs( - keys: string[] | KeyWeight[], + keys: GlideString[] | KeyWeight[], options: { aggregationType?: AggregationType; withScores?: boolean; - destination?: string; + destination?: GlideString; }, -): string[] { - const args = []; +): GlideString[] { + const args: GlideString[] = []; const destination = options.destination; @@ -1489,11 +1489,12 @@ function createZCmdArgs( args.push(keys.length.toString()); - if (typeof keys[0] === "string") { - args.push(...(keys as string[])); + if (!Array.isArray(keys[0])) { + // KeyWeight is an array + args.push(...(keys as GlideString[])); } else { const weightsKeys = keys.map(([key]) => key); - args.push(...(weightsKeys as string[])); + args.push(...(weightsKeys as GlideString[])); const weights = keys.map(([, weight]) => weight.toString()); args.push("WEIGHTS", ...weights); } @@ -1524,7 +1525,7 @@ export function createZRem( /** * @internal */ -export function createZCard(key: string): command_request.Command { +export function createZCard(key: GlideString): command_request.Command { return createCommand(RequestType.ZCard, [key]); } @@ -1532,14 +1533,14 @@ export function createZCard(key: string): command_request.Command { * @internal */ export function createZInterCard( - keys: string[], + keys: GlideString[], limit?: number, ): command_request.Command { - let args: string[] = keys; + const args = keys; args.unshift(keys.length.toString()); if (limit != undefined) { - args = args.concat(["LIMIT", limit.toString()]); + args.push("LIMIT", limit.toString()); } return createCommand(RequestType.ZInterCard, args); @@ -1548,8 +1549,8 @@ export function createZInterCard( /** * @internal */ -export function createZDiff(keys: string[]): command_request.Command { - const args: string[] = keys; +export function createZDiff(keys: GlideString[]): command_request.Command { + const args = keys; args.unshift(keys.length.toString()); return createCommand(RequestType.ZDiff, args); } @@ -1557,8 +1558,10 @@ export function createZDiff(keys: string[]): command_request.Command { /** * @internal */ -export function createZDiffWithScores(keys: string[]): command_request.Command { - const args: string[] = keys; +export function createZDiffWithScores( + keys: GlideString[], +): command_request.Command { + const args = keys; args.unshift(keys.length.toString()); args.push("WITHSCORES"); return createCommand(RequestType.ZDiff, args); @@ -1568,10 +1571,10 @@ export function createZDiffWithScores(keys: string[]): command_request.Command { * @internal */ export function createZDiffStore( - destination: string, - keys: string[], + destination: GlideString, + keys: GlideString[], ): command_request.Command { - const args: string[] = [destination, keys.length.toString(), ...keys]; + const args = [destination, keys.length.toString(), ...keys]; return createCommand(RequestType.ZDiffStore, args); } @@ -1790,7 +1793,7 @@ function createZRangeArgs( * @internal */ export function createZCount( - key: string, + key: GlideString, minScore: Boundary, maxScore: Boundary, ): command_request.Command { @@ -3455,12 +3458,12 @@ export function createZMPop( * @internal */ export function createBZMPop( - keys: string[], + keys: GlideString[], modifier: ScoreFilter, timeout: number, count?: number, ): command_request.Command { - const args: string[] = [ + const args = [ timeout.toString(), keys.length.toString(), ...keys, @@ -3479,9 +3482,9 @@ export function createBZMPop( * @internal */ export function createZIncrBy( - key: string, + key: GlideString, increment: number, - member: string, + member: GlideString, ): command_request.Command { return createCommand(RequestType.ZIncrBy, [ key, @@ -3898,7 +3901,7 @@ export function createPubSubShardNumSub( * @internal */ export function createBZPopMax( - keys: string[], + keys: GlideString[], timeout: number, ): command_request.Command { return createCommand(RequestType.BZPopMax, [...keys, timeout.toString()]); @@ -3908,7 +3911,7 @@ export function createBZPopMax( * @internal */ export function createBZPopMin( - keys: string[], + keys: GlideString[], timeout: number, ): command_request.Command { return createCommand(RequestType.BZPopMin, [...keys, timeout.toString()]); diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 0422fdee09..c338d01923 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -1711,22 +1711,24 @@ export class BaseTransaction> { * * @param key - The key to return its timeout. * - * Command Response - TTL in seconds, -2 if `key` does not exist or -1 if `key` exists but has no associated expire. + * Command Response - TTL in seconds, `-2` if `key` does not exist or `-1` if `key` exists but has no associated expire. */ public ttl(key: GlideString): T { return this.addAndReturn(createTTL(key)); } - /** Adds members with their scores to the sorted set stored at `key`. + /** + * Adds members with their scores to the sorted set stored at `key`. * If a member is already a part of the sorted set, its score is updated. + * * @see {@link https://valkey.io/commands/zadd/|valkey.io} for details. * * @param key - The key of the sorted set. * @param membersScoresMap - A mapping of members to their corresponding scores. - * @param options - The ZAdd options. + * @param options - (Optional) The ZAdd options - see {@link ZAddOptions}. * * Command Response - The number of elements added to the sorted set. - * If `changed` is set, returns the number of elements updated in the sorted set. + * If {@link ZAddOptions.changed|changed} is set, returns the number of elements updated in the sorted set. */ public zadd( key: string, @@ -1736,7 +1738,8 @@ export class BaseTransaction> { return this.addAndReturn(createZAdd(key, membersScoresMap, options)); } - /** Increments the score of member in the sorted set stored at `key` by `increment`. + /** + * Increments the score of member in the sorted set stored at `key` by `increment`. * If `member` does not exist in the sorted set, it is added with `increment` as its score (as if its previous score was 0.0). * If `key` does not exist, a new sorted set with the specified member as its sole member is created. * @see {@link https://valkey.io/commands/zadd/|valkey.io} for details. @@ -1744,7 +1747,7 @@ export class BaseTransaction> { * @param key - The key of the sorted set. * @param member - A member in the sorted set to increment. * @param increment - The score to increment the member. - * @param options - The ZAdd options. + * @param options - (Optional) The ZAdd options - see {@link ZAddOptions}. * * Command Response - The score of the member. * If there was a conflict with the options, the operation aborts and null is returned. @@ -1774,15 +1777,17 @@ export class BaseTransaction> { return this.addAndReturn(createZRem(key, members)); } - /** Returns the cardinality (number of elements) of the sorted set stored at `key`. + /** + * Returns the cardinality (number of elements) of the sorted set stored at `key`. + * * @see {@link https://valkey.io/commands/zcard/|valkey.io} for details. * * @param key - The key of the sorted set. * * Command Response - The number of elements in the sorted set. - * If `key` does not exist, it is treated as an empty sorted set, and this command returns 0. + * If `key` does not exist, it is treated as an empty sorted set, and this command returns `0`. */ - public zcard(key: string): T { + public zcard(key: GlideString): T { return this.addAndReturn(createZCard(key)); } @@ -1798,7 +1803,7 @@ export class BaseTransaction> { * * Command Response - The cardinality of the intersection of the given sorted sets. */ - public zintercard(keys: string[], limit?: number): T { + public zintercard(keys: GlideString[], limit?: number): T { return this.addAndReturn(createZInterCard(keys, limit)); } @@ -1814,7 +1819,7 @@ export class BaseTransaction> { * Command Response - An `array` of elements representing the difference between the sorted sets. * If the first key does not exist, it is treated as an empty sorted set, and the command returns an empty `array`. */ - public zdiff(keys: string[]): T { + public zdiff(keys: GlideString[]): T { return this.addAndReturn(createZDiff(keys)); } @@ -1830,7 +1835,7 @@ export class BaseTransaction> { * Command Response - A map of elements and their scores representing the difference between the sorted sets. * If the first key does not exist, it is treated as an empty sorted set, and the command returns an empty `array`. */ - public zdiffWithScores(keys: string[]): T { + public zdiffWithScores(keys: GlideString[]): T { return this.addAndReturn(createZDiffWithScores(keys)); } @@ -1847,7 +1852,7 @@ export class BaseTransaction> { * * Command Response - The number of members in the resulting sorted set stored at `destination`. */ - public zdiffstore(destination: string, keys: string[]): T { + public zdiffstore(destination: GlideString, keys: GlideString[]): T { return this.addAndReturn(createZDiffStore(destination, keys)); } @@ -1905,7 +1910,9 @@ export class BaseTransaction> { return this.addAndReturn(createZMScore(key, members)); } - /** Returns the number of members in the sorted set stored at `key` with scores between `minScore` and `maxScore`. + /** + * Returns the number of members in the sorted set stored at `key` with scores between `minScore` and `maxScore`. + * * @see {@link https://valkey.io/commands/zcount/|valkey.io} for details. * * @param key - The key of the sorted set. @@ -1913,11 +1920,11 @@ export class BaseTransaction> { * @param maxScore - The maximum score to count up to. Can be positive/negative infinity, or specific score and inclusivity. * * Command Response - The number of members in the specified score range. - * If `key` does not exist, it is treated as an empty sorted set, and the command returns 0. - * If `minScore` is greater than `maxScore`, 0 is returned. + * If `key` does not exist, it is treated as an empty sorted set, and the command returns `0`. + * If `minScore` is greater than `maxScore`, `0` is returned. */ public zcount( - key: string, + key: GlideString, minScore: Boundary, maxScore: Boundary, ): T { @@ -2005,24 +2012,22 @@ export class BaseTransaction> { * Computes the intersection of sorted sets given by the specified `keys` and stores the result in `destination`. * If `destination` already exists, it is overwritten. Otherwise, a new sorted set will be created. * - * When in cluster mode, `destination` and all keys in `keys` must map to the same hash slot. - * * @see {@link https://valkey.io/commands/zinterstore/|valkey.io} for details. * * @remarks Since Valkey version 6.2.0. * * @param destination - The key of the destination sorted set. * @param keys - The keys of the sorted sets with possible formats: - * string[] - for keys only. - * KeyWeight[] - for weighted keys with score multipliers. + * - `GlideString[]` - for keys only. + * - `KeyWeight[]` - for weighted keys with score multipliers. * @param aggregationType - (Optional) Specifies the aggregation strategy to apply when combining the scores of elements. See {@link AggregationType}. * If `aggregationType` is not specified, defaults to `AggregationType.SUM`. * * Command Response - The number of elements in the resulting sorted set stored at `destination`. */ public zinterstore( - destination: string, - keys: string[] | KeyWeight[], + destination: GlideString, + keys: GlideString[] | KeyWeight[], aggregationType?: AggregationType, ): T { return this.addAndReturn( @@ -2043,7 +2048,7 @@ export class BaseTransaction> { * * Command Response - The resulting array of intersecting elements. */ - public zinter(keys: string[]): T { + public zinter(keys: GlideString[]): T { return this.addAndReturn(createZInter(keys)); } @@ -2057,15 +2062,15 @@ export class BaseTransaction> { * @remarks Since Valkey version 6.2.0. * * @param keys - The keys of the sorted sets with possible formats: - * - string[] - for keys only. - * - KeyWeight[] - for weighted keys with score multipliers. + * - `GlideString[]` - for keys only. + * - `KeyWeight[]` - for weighted keys with score multipliers. * @param aggregationType - (Optional) Specifies the aggregation strategy to apply when combining the scores of elements. See {@link AggregationType}. * If `aggregationType` is not specified, defaults to `AggregationType.SUM`. * * Command Response - The resulting sorted set with scores. */ public zinterWithScores( - keys: string[] | KeyWeight[], + keys: GlideString[] | KeyWeight[], aggregationType?: AggregationType, ): T { return this.addAndReturn(createZInter(keys, aggregationType, true)); @@ -2214,7 +2219,7 @@ export class BaseTransaction> { * Command Response - An `array` containing the key where the member was popped out, the member, itself, and the member score. * If no member could be popped and the `timeout` expired, returns `null`. */ - public bzpopmin(keys: string[], timeout: number): T { + public bzpopmin(keys: GlideString[], timeout: number): T { return this.addAndReturn(createBZPopMin(keys, timeout)); } @@ -2249,7 +2254,7 @@ export class BaseTransaction> { * Command Response - An `array` containing the key where the member was popped out, the member, itself, and the member score. * If no member could be popped and the `timeout` expired, returns `null`. */ - public bzpopmax(keys: string[], timeout: number): T { + public bzpopmax(keys: GlideString[], timeout: number): T { return this.addAndReturn(createBZPopMax(keys, timeout)); } @@ -2273,7 +2278,7 @@ export class BaseTransaction> { * * @param key - The key to return its timeout. * - * Command Response - TTL in milliseconds. -2 if `key` does not exist, -1 if `key` exists but has no associated expire. + * Command Response - TTL in milliseconds, `-2` if `key` does not exist, `-1` if `key` exists but has no associated expire. */ public pttl(key: GlideString): T { return this.addAndReturn(createPTTL(key)); @@ -3573,7 +3578,7 @@ export class BaseTransaction> { * If no member could be popped, returns `null`. */ public bzmpop( - keys: string[], + keys: GlideString[], modifier: ScoreFilter, timeout: number, count?: number, @@ -3594,7 +3599,11 @@ export class BaseTransaction> { * * Command Response - The new score of `member`. */ - public zincrby(key: string, increment: number, member: string): T { + public zincrby( + key: GlideString, + increment: number, + member: GlideString, + ): T { return this.addAndReturn(createZIncrBy(key, increment, member)); } diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 0fb3074630..f93f18e9ce 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -4138,7 +4138,7 @@ export function runBaseTests(config: { expect(await client.zadd(key, membersScores)).toEqual(3); expect(await client.zcard(key)).toEqual(3); expect(await client.zrem(key, ["one"])).toEqual(1); - expect(await client.zcard(key)).toEqual(2); + expect(await client.zcard(Buffer.from(key))).toEqual(2); }, protocol); }, config.timeout, @@ -4162,7 +4162,9 @@ export function runBaseTests(config: { expect(await client.zadd(key1, memberScores1)).toEqual(3); expect(await client.zadd(key2, memberScores2)).toEqual(3); - expect(await client.zintercard([key1, key2])).toEqual(2); + expect( + await client.zintercard([key1, Buffer.from(key2)]), + ).toEqual(2); expect(await client.zintercard([key1, nonExistingKey])).toEqual( 0, ); @@ -4218,10 +4220,15 @@ export function runBaseTests(config: { expect(await client.zadd(key2, entries2)).toEqual(1); expect(await client.zadd(key3, entries3)).toEqual(4); - expect(await client.zdiff([key1, key2])).toEqual([ + expect(await client.zdiff([key1, Buffer.from(key2)])).toEqual([ "one", "three", ]); + expect( + await client.zdiff([key1, key2], { + decoder: Decoder.Bytes, + }), + ).toEqual([Buffer.from("one"), Buffer.from("three")]); expect(await client.zdiff([key1, key3])).toEqual([]); expect(await client.zdiff([nonExistingKey, key3])).toEqual([]); @@ -4231,6 +4238,12 @@ export function runBaseTests(config: { three: 3.0, }; expect(compareMaps(result, expected)).toBe(true); + // same with byte[] + result = await client.zdiffWithScores([ + key1, + Buffer.from(key2), + ]); + expect(compareMaps(result, expected)).toBe(true); result = await client.zdiffWithScores([key1, key3]); expect(compareMaps(result, {})).toBe(true); @@ -4296,7 +4309,11 @@ export function runBaseTests(config: { expect(compareMaps(result1, expected1)).toBe(true); expect( - await client.zdiffstore(key4, [key3, key2, key1]), + await client.zdiffstore(Buffer.from(key4), [ + key3, + key2, + key1, + ]), ).toEqual(1); const result2 = await client.zrangeWithScores(key4, { start: 0, @@ -4304,7 +4321,9 @@ export function runBaseTests(config: { }); expect(compareMaps(result2, { four: 4.0 })).toBe(true); - expect(await client.zdiffstore(key4, [key1, key3])).toEqual(0); + expect( + await client.zdiffstore(key4, [Buffer.from(key1), key3]), + ).toEqual(0); const result3 = await client.zrangeWithScores(key4, { start: 0, stop: -1, @@ -4627,9 +4646,13 @@ export function runBaseTests(config: { ), ).toEqual(2); expect( - await client.zcount(key1, InfBoundary.NegativeInfinity, { - value: 3, - }), + await client.zcount( + Buffer.from(key1), + InfBoundary.NegativeInfinity, + { + value: 3, + }, + ), ).toEqual(3); expect( await client.zcount(key1, InfBoundary.PositiveInfinity, { @@ -4638,7 +4661,7 @@ export function runBaseTests(config: { ).toEqual(0); expect( await client.zcount( - "nonExistingKey", + Buffer.from("nonExistingKey"), InfBoundary.NegativeInfinity, InfBoundary.PositiveInfinity, ), @@ -5156,7 +5179,9 @@ export function runBaseTests(config: { expect(compareMaps(zinterstoreMapMax, expectedMapMax)).toBe(true); // Intersection results are aggregated by the MIN score of elements - expect(await client.zinterstore(key3, [key1, key2], "MIN")).toEqual(2); + expect( + await client.zinterstore(Buffer.from(key3), [key1, key2], "MIN"), + ).toEqual(2); const zinterstoreMapMin = await client.zrangeWithScores(key3, range); const expectedMapMin = { one: 1, @@ -5165,7 +5190,9 @@ export function runBaseTests(config: { expect(compareMaps(zinterstoreMapMin, expectedMapMin)).toBe(true); // Intersection results are aggregated by the SUM score of elements - expect(await client.zinterstore(key3, [key1, key2], "SUM")).toEqual(2); + expect( + await client.zinterstore(key3, [Buffer.from(key1), key2], "SUM"), + ).toEqual(2); const zinterstoreMapSum = await client.zrangeWithScores(key3, range); const expectedMapSum = { one: 3, @@ -5279,9 +5306,19 @@ export function runBaseTests(config: { 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); + expect(await client.zinter([key1, key2])).toEqual([ + "one", + "two", + ]); + expect(await client.zinter([key1, Buffer.from(key2)])).toEqual([ + "one", + "two", + ]); + expect( + await client.zinter([key1, key2], { + decoder: Decoder.Bytes, + }), + ).toEqual([Buffer.from("one"), Buffer.from("two")]); }, protocol); }, config.timeout, @@ -5303,7 +5340,7 @@ export function runBaseTests(config: { const resultZinterWithScores = await client.zinterWithScores([ key1, - key2, + Buffer.from(key2), ]); const expectedZinterWithScores = { one: 2.5, @@ -5334,7 +5371,7 @@ export function runBaseTests(config: { // Intersection results are aggregated by the MAX score of elements const zinterWithScoresResults = await client.zinterWithScores( [key1, key2], - "MAX", + { aggregationType: "MAX" }, ); const expectedMapMax = { one: 1.5, @@ -5363,7 +5400,7 @@ export function runBaseTests(config: { // Intersection results are aggregated by the MIN score of elements const zinterWithScoresResults = await client.zinterWithScores( [key1, key2], - "MIN", + { aggregationType: "MIN" }, ); const expectedMapMin = { one: 1.0, @@ -5392,7 +5429,7 @@ export function runBaseTests(config: { // Intersection results are aggregated by the SUM score of elements const zinterWithScoresResults = await client.zinterWithScores( [key1, key2], - "SUM", + { aggregationType: "SUM" }, ); const expectedMapSum = { one: 2.5, @@ -5424,7 +5461,7 @@ export function runBaseTests(config: { [key1, 3], [key2, 2], ], - "SUM", + { aggregationType: "SUM" }, ); const expectedMapSum = { one: 6, @@ -5987,11 +6024,15 @@ export function runBaseTests(config: { ).toBeNull(); // pops from the second key - expect(await client.bzpopmax([key3, key2], 0.5)).toEqual([ - key2, - "c", - 2.0, - ]); + expect( + await client.bzpopmax([key3, Buffer.from(key2)], 0.5), + ).toEqual([key2, "c", 2.0]); + // pop with decoder + expect( + await client.bzpopmax([key1], 0.5, { + decoder: Decoder.Bytes, + }), + ).toEqual([Buffer.from(key1), Buffer.from("a"), 1.0]); // key exists but holds non-ZSET value expect(await client.set(key3, "bzpopmax")).toBe("OK"); @@ -6030,11 +6071,15 @@ export function runBaseTests(config: { ).toBeNull(); // pops from the second key - expect(await client.bzpopmin([key3, key2], 0.5)).toEqual([ - key2, - "c", - 2.0, - ]); + expect( + await client.bzpopmin([key3, Buffer.from(key2)], 0.5), + ).toEqual([key2, "c", 2.0]); + // pop with decoder + expect( + await client.bzpopmin([key1], 0.5, { + decoder: Decoder.Bytes, + }), + ).toEqual([Buffer.from(key1), Buffer.from("b"), 1.5]); // key exists but holds non-ZSET value expect(await client.set(key3, "bzpopmin")).toBe("OK"); @@ -9057,13 +9102,15 @@ export function runBaseTests(config: { expect(await client.zscore(key, member)).toEqual(2.5); // key exists, but value doesn't - expect(await client.zincrby(key, -3.3, othermember)).toEqual( - -3.3, - ); + expect( + await client.zincrby(Buffer.from(key), -3.3, othermember), + ).toEqual(-3.3); expect(await client.zscore(key, othermember)).toEqual(-3.3); // updating existing value in existing key - expect(await client.zincrby(key, 1.0, member)).toEqual(3.5); + expect( + await client.zincrby(key, 1.0, Buffer.from(member)), + ).toEqual(3.5); expect(await client.zscore(key, member)).toEqual(3.5); // Key exists, but it is not a sorted set @@ -9253,7 +9300,14 @@ export function runBaseTests(config: { await client.bzmpop([key1, key2], ScoreFilter.MAX, 0.1), ).toEqual([key1, { b1: 2 }]); expect( - await client.bzmpop([key2, key1], ScoreFilter.MAX, 0.1, 10), + await client.bzmpop( + [key2, Buffer.from(key1)], + ScoreFilter.MAX, + 0.1, + { + count: 10, + }, + ), ).toEqual([key2, { a2: 0.1, b2: 0.2 }]); // ensure that command doesn't time out even if timeout > request timeout (250ms by default) @@ -9265,7 +9319,7 @@ export function runBaseTests(config: { [nonExistingKey], ScoreFilter.MAX, 0.55, - 1, + { count: 1 }, ), ).toBeNull(); @@ -9275,22 +9329,24 @@ export function runBaseTests(config: { client.bzmpop([stringKey], ScoreFilter.MAX, 0.1), ).rejects.toThrow(RequestError); await expect( - client.bzmpop([stringKey], ScoreFilter.MAX, 0.1, 1), + client.bzmpop([stringKey], ScoreFilter.MAX, 0.1, { + count: 1, + }), ).rejects.toThrow(RequestError); // incorrect argument: key list should not be empty await expect( - client.bzmpop([], ScoreFilter.MAX, 0.1, 1), + client.bzmpop([], ScoreFilter.MAX, 0.1, { count: 1 }), ).rejects.toThrow(RequestError); // incorrect argument: count should be greater than 0 await expect( - client.bzmpop([key1], ScoreFilter.MAX, 0.1, 0), + client.bzmpop([key1], ScoreFilter.MAX, 0.1, { count: 0 }), ).rejects.toThrow(RequestError); // incorrect argument: timeout can not be a negative number await expect( - client.bzmpop([key1], ScoreFilter.MAX, -1, 10), + client.bzmpop([key1], ScoreFilter.MAX, -1, { count: 10 }), ).rejects.toThrow(RequestError); // check that order of entries in the response is preserved @@ -9306,7 +9362,7 @@ export function runBaseTests(config: { [key2], ScoreFilter.MIN, 0.1, - 10, + { count: 10 }, ); if (result) {