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 ZDIFF command #1972

Merged
merged 2 commits into from
Jul 18, 2024
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 @@ -2,6 +2,7 @@
* Node: Added LPUSHX and RPUSHX command([#1959](https://github.com/valkey-io/valkey-glide/pull/1959))
* Node: Added LSET command ([#1952](https://github.com/valkey-io/valkey-glide/pull/1952))
* Node: Added SDIFFSTORE command ([#1931](https://github.com/valkey-io/valkey-glide/pull/1931))
* Node: Added ZDIFF command ([#1972](https://github.com/valkey-io/valkey-glide/pull/1972))
* Node: Added SINTERCARD command ([#1956](https://github.com/valkey-io/valkey-glide/pull/1956))
* Node: Added SINTERSTORE command ([#1929](https://github.com/valkey-io/valkey-glide/pull/1929))
* Node: Added SUNION command ([#1919](https://github.com/valkey-io/valkey-glide/pull/1919))
Expand Down
54 changes: 54 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ import {
createZAdd,
createZCard,
createZCount,
createZDiff,
createZDiffWithScores,
createZInterCard,
createZInterstore,
createZPopMax,
Expand Down Expand Up @@ -2020,6 +2022,58 @@ export class BaseClient {
return this.createWritePromise(createZInterCard(keys, limit));
}

/**
* Returns the difference between the first sorted set and all the successive sorted sets.
* To get the elements with their scores, see {@link zdiffWithScores}.
*
* See https://valkey.io/commands/zdiff/ for more details.
*
* @remarks When in cluster mode, all `keys` must map to the same hash slot.
* @param keys - The keys of the sorted sets.
* @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`.
*
* since Valkey version 6.2.0.
*
* @example
* ```typescript
* await client.zadd("zset1", {"member1": 1.0, "member2": 2.0, "member3": 3.0});
* await client.zadd("zset2", {"member2": 2.0});
* await client.zadd("zset3", {"member3": 3.0});
* const result = await client.zdiff(["zset1", "zset2", "zset3"]);
* console.log(result); // Output: ["member1"] - "member1" is in "zset1" but not "zset2" or "zset3".
* ```
*/
public zdiff(keys: string[]): Promise<string[]> {
return this.createWritePromise(createZDiff(keys));
}

/**
* Returns the difference between the first sorted set and all the successive sorted sets, with the associated
* scores.
*
* See https://valkey.io/commands/zdiff/ for more details.
*
* @remarks When in cluster mode, all `keys` must map to the same hash slot.
* @param keys - The keys of the sorted sets.
* @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`.
*
* since Valkey version 6.2.0.
*
* @example
* ```typescript
* await client.zadd("zset1", {"member1": 1.0, "member2": 2.0, "member3": 3.0});
* await client.zadd("zset2", {"member2": 2.0});
* await client.zadd("zset3", {"member3": 3.0});
* const result = await client.zdiffWithScores(["zset1", "zset2", "zset3"]);
* console.log(result); // Output: {"member1": 1.0} - "member1" is in "zset1" but not "zset2" or "zset3".
* ```
*/
public zdiffWithScores(keys: string[]): Promise<Record<string, number>> {
return this.createWritePromise(createZDiffWithScores(keys));
}

/** Returns the score of `member` in the sorted set stored at `key`.
* See https://valkey.io/commands/zscore/ for more details.
*
Expand Down
19 changes: 19 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1025,6 +1025,25 @@ export function createZInterCard(
return createCommand(RequestType.ZInterCard, args);
}

/**
* @internal
*/
export function createZDiff(keys: string[]): command_request.Command {
const args: string[] = keys;
args.unshift(keys.length.toString());
return createCommand(RequestType.ZDiff, args);
}

/**
* @internal
*/
export function createZDiffWithScores(keys: string[]): command_request.Command {
const args: string[] = keys;
args.unshift(keys.length.toString());
args.push("WITHSCORES");
return createCommand(RequestType.ZDiff, args);
}

/**
* @internal
*/
Expand Down
36 changes: 36 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ import {
createZAdd,
createZCard,
createZCount,
createZDiff,
createZDiffWithScores,
createZInterCard,
createZInterstore,
createZPopMax,
Expand Down Expand Up @@ -1145,6 +1147,40 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
return this.addAndReturn(createZInterCard(keys, limit));
}

/**
* Returns the difference between the first sorted set and all the successive sorted sets.
* To get the elements with their scores, see {@link zdiffWithScores}.
*
* See https://valkey.io/commands/zdiff/ for more details.
*
* @param keys - The keys of the sorted sets.
*
* 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`.
*
* since Valkey version 6.2.0.
*/
public zdiff(keys: string[]): T {
return this.addAndReturn(createZDiff(keys));
}

/**
* Returns the difference between the first sorted set and all the successive sorted sets, with the associated
* scores.
*
* See https://valkey.io/commands/zdiff/ for more details.
*
* @param keys - The keys of the sorted sets.
*
* 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`.
*
* since Valkey version 6.2.0.
*/
public zdiffWithScores(keys: string[]): T {
return this.addAndReturn(createZDiffWithScores(keys));
}

/** Returns the score of `member` in the sorted set stored at `key`.
* See https://valkey.io/commands/zscore/ for more details.
*
Expand Down
2 changes: 2 additions & 0 deletions node/tests/RedisClusterClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ describe("GlideClusterClient", () => {
client.sintercard(["abc", "zxy", "lkn"]),
client.sinterstore("abc", ["zxy", "lkn"]),
client.zinterstore("abc", ["zxy", "lkn"]),
client.zdiff(["abc", "zxy", "lkn"]),
client.zdiffWithScores(["abc", "zxy", "lkn"]),
client.sunionstore("abc", ["zxy", "lkn"]),
client.sunion(["abc", "zxy", "lkn"]),
client.pfcount(["abc", "zxy", "lkn"]),
Expand Down
70 changes: 70 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2168,6 +2168,76 @@ export function runBaseTests<Context>(config: {
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`zdiff test_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
if (await checkIfServerVersionLessThan("6.2.0")) {
return;
}

const key1 = `{key}-${uuidv4()}`;
const key2 = `{key}-${uuidv4()}`;
const key3 = `{key}-${uuidv4()}`;
const nonExistingKey = `{key}-${uuidv4()}`;
const stringKey = `{key}-${uuidv4()}`;

const entries1 = {
one: 1.0,
two: 2.0,
three: 3.0,
};
const entries2 = { two: 2.0 };
const entries3 = {
one: 1.0,
two: 2.0,
three: 3.0,
four: 4.0,
};

expect(await client.zadd(key1, entries1)).toEqual(3);
expect(await client.zadd(key2, entries2)).toEqual(1);
expect(await client.zadd(key3, entries3)).toEqual(4);

checkSimple(await client.zdiff([key1, key2])).toEqual([
"one",
"three",
]);
checkSimple(await client.zdiff([key1, key3])).toEqual([]);
checkSimple(await client.zdiff([nonExistingKey, key3])).toEqual(
[],
);

let result = await client.zdiffWithScores([key1, key2]);
const expected = {
one: 1.0,
three: 3.0,
};
expect(compareMaps(result, expected)).toBe(true);

result = await client.zdiffWithScores([key1, key3]);
expect(compareMaps(result, {})).toBe(true);

result = await client.zdiffWithScores([nonExistingKey, key3]);
expect(compareMaps(result, {})).toBe(true);

// invalid arg - key list must not be empty
await expect(client.zdiff([])).rejects.toThrow(RequestError);
await expect(client.zdiffWithScores([])).rejects.toThrow(
RequestError,
);

// key exists, but it is not a sorted set
checkSimple(await client.set(stringKey, "foo")).toEqual("OK");
await expect(client.zdiff([stringKey, key1])).rejects.toThrow();
await expect(
client.zdiffWithScores([stringKey, key1]),
).rejects.toThrow();
}, protocol);
},
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`zscore test_%p`,
async (protocol) => {
Expand Down
10 changes: 9 additions & 1 deletion node/tests/TestUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,16 @@ export async function transactionTest(
args.push({ member2: 3, member3: 3.5, member4: 4, member5: 5 });
baseTransaction.zadd(key12, { one: 1, two: 2 });
args.push(2);
baseTransaction.zadd(key13, { one: 1, two: 2, tree: 3.5 });
baseTransaction.zadd(key13, { one: 1, two: 2, three: 3.5 });
Copy link
Collaborator

Choose a reason for hiding this comment

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

<3

args.push(3);

if (!(await checkIfServerVersionLessThan("6.2.0"))) {
baseTransaction.zdiff([key13, key12]);
args.push(["three"]);
baseTransaction.zdiffWithScores([key13, key12]);
args.push({ three: 3.5 });
}

baseTransaction.zinterstore(key12, [key12, key13]);
args.push(2);
baseTransaction.zcount(key8, { value: 2 }, "positiveInfinity");
Expand Down
Loading