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 all commits
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 @@ -86,6 +86,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
137 changes: 133 additions & 4 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ import {
createZDiffStore,
createZDiffWithScores,
createZIncrBy,
createZInter,
createZInterCard,
createZInterstore,
createZLexCount,
Expand All @@ -216,6 +217,7 @@ import {
createZRevRankWithScore,
createZScan,
createZScore,
createZUnion,
createZUnionStore,
} from "./Commands";
import {
Expand Down Expand Up @@ -3808,7 +3810,7 @@ export class BaseClient {
/**
* 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.
* To get the result directly, see `zinter_withscores`.
* To get the result directly, see {@link zinterWithScores}.
*
* @see {@link https://valkey.io/commands/zinterstore/|valkey.io} for more details.
* @remarks When in cluster mode, `destination` and all keys in `keys` must map to the same hash slot.
Expand All @@ -3817,7 +3819,8 @@ export class BaseClient {
* @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`.
* @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
Expand All @@ -3826,9 +3829,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.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 async zinterstore(
Expand All @@ -3841,6 +3844,132 @@ 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 {@link zinterWithScores}.
* 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.
*
* @remarks 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 {@link zinter}.
* 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.
*
* @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`.
* @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 {@link zunionWithScores}.
*
* To store the result in a key as a sorted set, see {@link zunionStore}.
*
* @remarks When in cluster mode, all keys in `keys` must map to the same hash slot.
*
* @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 {@link 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.
*
* @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`.
* @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
59 changes: 54 additions & 5 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1431,16 +1431,59 @@ export function createZInterstore(
keys: string[] | KeyWeight[],
aggregationType?: AggregationType,
): command_request.Command {
const args = createZCmdStoreArgs(destination, keys, aggregationType);
const args = createZCmdArgs(keys, {
aggregationType,
withScores: 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[],
options: {
aggregationType?: AggregationType;
withScores?: boolean;
destination?: string;
},
): string[] {
const args: string[] = [destination, keys.length.toString()];
const args = [];

const destination = options.destination;

if (destination) {
args.push(destination);
}

args.push(keys.length.toString());

if (typeof keys[0] === "string") {
args.push(...(keys as string[]));
Expand All @@ -1451,10 +1494,16 @@ function createZCmdStoreArgs(
args.push("WEIGHTS", ...weights);
}

const aggregationType = options.aggregationType;

if (aggregationType) {
args.push("AGGREGATE", aggregationType);
}

if (options.withScores) {
args.push("WITHSCORES");
}

return args;
}

Expand Down Expand Up @@ -1540,7 +1589,7 @@ export function createZUnionStore(
keys: string[] | KeyWeight[],
aggregationType?: AggregationType,
): command_request.Command {
const args = createZCmdStoreArgs(destination, keys, aggregationType);
const args = createZCmdArgs(keys, { destination, aggregationType });
return createCommand(RequestType.ZUnionStore, args);
}

Expand Down
90 changes: 89 additions & 1 deletion node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ import {
createZDiffStore,
createZDiffWithScores,
createZIncrBy,
createZInter,
createZInterCard,
createZInterstore,
createZLexCount,
Expand All @@ -250,6 +251,7 @@ import {
createZRevRankWithScore,
createZScan,
createZScore,
createZUnion,
createZUnionStore,
} from "./Commands";
import { command_request } from "./ProtobufMessage";
Expand Down Expand Up @@ -1915,11 +1917,15 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
*
* @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.
* @param aggregationType - Specifies the aggregation strategy to apply when combining the scores of elements. See `AggregationType`.
* @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(
Expand All @@ -1932,6 +1938,88 @@ 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 {@link zinterWithScores}.
* To store the result in a key as a sorted set, see {@link zinterStore}.
*
* @remarks 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 {@link zinter}.
* To store the result in a key as a sorted set, see {@link zinterStore}.
*
* @see {@link https://valkey.io/commands/zinter/|valkey.io} for details.
*
* @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`.
*
* 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 {@link zunionWithScores}.
*
* To store the result in a key as a sorted set, see {@link zunionStore}.
*
* @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.
*
* 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 {@link zunion}.
*
* @see {@link https://valkey.io/commands/zunion/|valkey.io} for details.
*
* @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`.
*
* 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
Loading
Loading