diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f17a6d306..94f678dbe9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ * Python, Node: Added ZPOPMIN command ([#975](https://github.com/aws/glide-for-redis/pull/975), [#1008](https://github.com/aws/glide-for-redis/pull/1008)) * Node: Added STRLEN command ([#993](https://github.com/aws/glide-for-redis/pull/993)) * Node: Added LINDEX command ([#999](https://github.com/aws/glide-for-redis/pull/999)) -* Python: Added ZPOPMAX command ([#996](https://github.com/aws/glide-for-redis/pull/996)) +* Python, Node: Added ZPOPMAX command ([#996](https://github.com/aws/glide-for-redis/pull/996), [#1009](https://github.com/aws/glide-for-redis/pull/1009)) #### Features * Python, Node: Added support in Lua Scripts ([#775](https://github.com/aws/glide-for-redis/pull/775), [#860](https://github.com/aws/glide-for-redis/pull/860)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index ef5b1f2835..a73c40f47e 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -59,6 +59,7 @@ import { createZadd, createZcard, createZcount, + createZpopmax, createZpopmin, createZrem, createZscore, @@ -1108,9 +1109,9 @@ export class BaseClient { * * @param key - The key of the sorted set. * @param count - Specifies the quantity of members to pop. If not specified, pops one member. - * If `count` is higher than the sorted set's cardinality, returns all members and their scores. * @returns A map of the removed members and their scores, ordered from the one with the lowest score to the one with the highest. * If `key` doesn't exist, it will be treated as an empty sorted set and the command returns an empty map. + * If `count` is higher than the sorted set's cardinality, returns all members and their scores. */ public zpopmin( key: string, @@ -1119,6 +1120,24 @@ export class BaseClient { return this.createWritePromise(createZpopmin(key, count)); } + /** Removes and returns the members with the highest scores from the sorted set stored at `key`. + * If `count` is provided, up to `count` members with the highest scores are removed and returned. + * Otherwise, only one member with the highest score is removed and returned. + * See https://redis.io/commands/zpopmax for more details. + * + * @param key - The key of the sorted set. + * @param count - Specifies the quantity of members to pop. If not specified, pops one member. + * @returns A map of the removed members and their scores, ordered from the one with the highest score to the one with the lowest. + * If `key` doesn't exist, it will be treated as an empty sorted set and the command returns an empty map. + * If `count` is higher than the sorted set's cardinality, returns all members and their scores, ordered from highest to lowest. + */ + public zpopmax( + key: string, + count?: number + ): Promise> { + return this.createWritePromise(createZpopmax(key, count)); + } + private readonly MAP_READ_FROM_STRATEGY: Record< ReadFrom, connection_request.ReadFrom diff --git a/node/src/Commands.ts b/node/src/Commands.ts index b5f772e600..ffd24f4731 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -855,3 +855,11 @@ export function createZpopmin(key: string, count?: number): redis_request.Comman const args: string[] = count == undefined ? [key] : [key, count.toString()]; return createCommand(RequestType.ZPopMin, args); } + +/** + * @internal + */ +export function createZpopmax(key: string, count?: number): redis_request.Command { + const args: string[] = count == undefined ? [key] : [key, count.toString()]; + return createCommand(RequestType.ZPopMax, args); +} diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index a7e70e9c73..cf6f3826b9 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -62,6 +62,7 @@ import { createZadd, createZcard, createZcount, + createZpopmax, createZpopmin, createZrem, createZscore, @@ -874,15 +875,31 @@ export class BaseTransaction> { * * @param key - The key of the sorted set. * @param count - Specifies the quantity of members to pop. If not specified, pops one member. - * If `count` is higher than the sorted set's cardinality, returns all members and their scores. * * Command Response - A map of the removed members and their scores, ordered from the one with the lowest score to the one with the highest. * If `key` doesn't exist, it will be treated as an empty sorted set and the command returns an empty map. + * If `count` is higher than the sorted set's cardinality, returns all members and their scores. */ public zpopmin(key: string, count?: number): T { return this.addAndReturn(createZpopmin(key, count)); } + /** Removes and returns the members with the highest scores from the sorted set stored at `key`. + * If `count` is provided, up to `count` members with the highest scores are removed and returned. + * Otherwise, only one member with the highest score is removed and returned. + * See https://redis.io/commands/zpopmax for more details. + * + * @param key - The key of the sorted set. + * @param count - Specifies the quantity of members to pop. If not specified, pops one member. + * + * Command Response - A map of the removed members and their scores, ordered from the one with the highest score to the one with the lowest. + * If `key` doesn't exist, it will be treated as an empty sorted set and the command returns an empty map. + * If `count` is higher than the sorted set's cardinality, returns all members and their scores, ordered from highest to lowest. + */ + public zpopmax(key: string, count?: number): T { + return this.addAndReturn(createZpopmax(key, count)); + } + /** Executes a single command, without checking inputs. Every part of the command, including subcommands, * should be added as a separate value in args. * diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 022eca1fba..2ed87bedbb 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -1597,6 +1597,27 @@ export function runBaseTests(config: { }, config.timeout ); + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `zpopmax test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + const key = uuidv4(); + const membersScores = { a: 1, b: 2, c: 3 }; + expect(await client.zadd(key, membersScores)).toEqual(3); + expect(await client.zpopmax(key)).toEqual({ c: 3.0 }); + expect(await client.zpopmax(key, 3)).toEqual({ + b: 2.0, + a: 1.0, + }); + expect(await client.zpopmax(key)).toEqual({}); + expect(await client.set(key, "value")).toEqual("OK"); + await expect(client.zpopmax(key)).rejects.toThrow(); + expect(await client.zpopmax("notExsitingKey")).toEqual({}); + }, protocol); + }, + config.timeout + ); } export function runCommonTests(config: { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 3e5b6377f7..fadf6e5fde 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -131,20 +131,22 @@ export function transactionTest( args.push(1); baseTransaction.smembers(key7); args.push(["bar"]); - baseTransaction.zadd(key8, { member1: 1, member2: 2 }); - args.push(2); + baseTransaction.zadd(key8, { member1: 1, member2: 2, member3: 3.5 }); + args.push(3); baseTransaction.zaddIncr(key8, "member2", 1); args.push(3); baseTransaction.zrem(key8, ["member1"]); args.push(1); baseTransaction.zcard(key8); - args.push(1); + args.push(2); baseTransaction.zscore(key8, "member2"); args.push(3.0); baseTransaction.zcount(key8, { bound: 2 }, "positiveInfinity"); - args.push(1); - baseTransaction.zpopmin(key8) - args.push({"member2": 3.0}) + args.push(2); + baseTransaction.zpopmin(key8); + args.push({"member2": 3.0}); + baseTransaction.zpopmax(key8); + args.push({"member3": 3.5}); return args; }