Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node: add ZINTER and ZUNION commands #2146

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
* 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.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
* ```
*/
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`.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
* To store the result in a key as a sorted set, see `zinterStore`.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* @remarks When in cluster mode, all keys in `keys` must map to the same hash slot.
*
* since - Valkey version 6.2.0.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* @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`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* To get the elements only, see `zinter`.
* To get the elements only, see {@link zinter}.

* To store the result in a key as a sorted set, see `zinterStore`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* 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 {@link 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.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* @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`.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
* @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`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use @link here too

*
* To store the result in a key as a sorted set, see `zunionStore`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use @link here too

*
* @remarks When in cluster mode, all keys in `keys` must map to the same hash slot.
*
* since - Valkey version 6.2.0.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* since - Valkey version 6.2.0.
* @remarks 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`.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use @link here too

*
* @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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* since Valkey version 6.2.0.
* @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 - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
* @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,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit - change this to use an anonymous object to define the 3 optional variables:

function createZCmdArgs(
    keys: string[] | KeyWeight[],
    options: {aggregationType: string?, withscores: boolean?, destination: string? }
): string[] {

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.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* since Valkey version 6.2.0.
* @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.
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.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* @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.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* @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`.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* 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.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* @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.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* @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`.
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
*
* 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"]),
tjzhang-BQ marked this conversation as resolved.
Show resolved Hide resolved
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
Loading