Skip to content

Commit

Permalink
Node: add ZINTER and ZUNION commands
Browse files Browse the repository at this point in the history
Signed-off-by: TJ Zhang <[email protected]>
  • Loading branch information
TJ Zhang committed Aug 15, 2024
1 parent 91fae38 commit a7ed20f
Show file tree
Hide file tree
Showing 7 changed files with 626 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
* Node: Added BZPOPMAX & BZPOPMIN command ([#2077]((https://github.com/valkey-io/valkey-glide/pull/2077))
* Node: Added XGROUP CREATECONSUMER & XGROUP DELCONSUMER commands ([#2088](https://github.com/valkey-io/valkey-glide/pull/2088))
* Node: Added GETEX command ([#2107]((https://github.com/valkey-io/valkey-glide/pull/2107))
* Node: Added ZINTER and ZUNION commands ([#2146](https://github.com/aws/glide-for-redis/pull/2146))

#### Breaking Changes
* Node: (Refactor) Convert classes to types ([#2005](https://github.com/valkey-io/valkey-glide/pull/2005))
Expand Down
130 changes: 128 additions & 2 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ import {
createZDiffStore,
createZDiffWithScores,
createZIncrBy,
createZInter,
createZInterCard,
createZInterstore,
createZLexCount,
Expand All @@ -208,6 +209,7 @@ import {
createZRevRankWithScore,
createZScan,
createZScore,
createZUnion,
} from "./Commands";
import {
ClosingError,
Expand Down Expand Up @@ -3627,9 +3629,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.zrangeWithsScores("my_sorted_set", RangeByIndex(0, -1)) // Output: {'member1': 10.5} - "member1" is now stored in "my_sorted_set" with score of 10.5.
* ```
*/
public async zinterstore(
Expand All @@ -3642,6 +3644,130 @@ 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 `zinterWithScores`.
* To store the result in a key as a sorted set, see `zinterStore`.
*
* @remarks When in cluster mode, all keys in `keys` must map to the same hash slot.
*
* since - Valkey version 6.2.0.
*
* @see {@link https://valkey.io/commands/zinter/|valkey.io} for details.
*
* @param keys - The keys of the sorted sets.
* @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});
* const result = await client.zinter(["key1", "key2"]);
* console.log(result); // Output: ['member1']
* ```
*/
public zinter(keys: string[]): Promise<string[]> {
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`.
*
* @remarks When in cluster mode, all keys in `keys` must map to the same hash slot.
*
* @see {@link https://valkey.io/commands/zinter/|valkey.io} for details.
*
* 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 - 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});
* 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(
keys: string[] | KeyWeight[],
aggregationType?: AggregationType,
): Promise<Record<string, number>> {
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 `zunionWithScores`.
*
* To store the result in a key as a sorted set, see `zunionStore`.
*
* @remarks When in cluster mode, all keys in `keys` must map to the same hash slot.
*
* since - Valkey version 6.2.0.
*
* @see {@link https://valkey.io/commands/zunion/|valkey.io} for details.
*
* @param keys - The keys of the sorted sets.
* @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});
* const result = await client.zunion(["key1", "key2"]);
* console.log(result); // Output: ['member1', 'member2']
* ```
*/
public zunion(keys: string[]): Promise<string[]> {
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`.
*
* @remarks When in cluster mode, all keys in `keys` must map to the same hash slot.
*
* @see {@link https://valkey.io/commands/zunion/|valkey.io} for details.
*
* 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 - 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});
* 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(
keys: string[] | KeyWeight[],
aggregationType?: AggregationType,
): Promise<Record<string, number>> {
return this.createWritePromise(
createZUnion(keys, aggregationType, true),
);
}

/**
* Returns a random member from the sorted set stored at `key`.
*
Expand Down
47 changes: 43 additions & 4 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1424,16 +1424,51 @@ 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);
}

/**
* @internal
* Helper function for Zcommands (ZInter, ZinterStore, ZUnion..) that arranges arguments in the server's required order.
*/
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[]));
Expand All @@ -1448,6 +1483,10 @@ function createZCmdStoreArgs(
args.push("AGGREGATE", aggregationType);
}

if (withscores) {
args.push("WITHSCORES");
}

return args;
}

Expand Down
84 changes: 84 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ import {
createZDiffStore,
createZDiffWithScores,
createZIncrBy,
createZInter,
createZInterCard,
createZInterstore,
createZLexCount,
Expand All @@ -244,6 +245,7 @@ import {
createZRevRankWithScore,
createZScan,
createZScore,
createZUnion,
} from "./Commands";
import { command_request } from "./ProtobufMessage";

Expand Down Expand Up @@ -1871,6 +1873,8 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
*
* @see {@link https://valkey.io/commands/zinterstore/|valkey.io} for details.
*
* 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.
Expand All @@ -1888,6 +1892,86 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
);
}

/**
* 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 `zinterWithScores`.
* To store the result in a key as a sorted set, see `zinterStore`.
*
* since - Valkey version 6.2.0.
*
* @see {@link https://valkey.io/commands/zinter/|valkey.io} for details.
*
* @param keys - The keys of the sorted sets.
*
* Command Response - The resulting array of intersecting elements.
*/
public zinter(keys: string[]): 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`.
*
* @see {@link https://valkey.io/commands/zinter/|valkey.io} for details.
*
* 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 - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`.
*
* Command Response - The resulting sorted set with scores.
*/
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 `zunionWithScores`.
*
* To store the result in a key as a sorted set, see `zunionStore`.
*
* since - Valkey version 6.2.0.
*
* @see {@link https://valkey.io/commands/zunion/|valkey.io} for details.
*
* @param keys - The keys of the sorted sets.
*
* Command Response - The resulting array of union elements.
*/
public zunion(keys: string[]): 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`.
*
* @see {@link https://valkey.io/commands/zunion/|valkey.io} for details.
*
* 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 - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`.
*
* Command 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`.
*
Expand Down
4 changes: 4 additions & 0 deletions node/tests/GlideClusterClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,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"]),
Expand Down
Loading

0 comments on commit a7ed20f

Please sign in to comment.