Skip to content

Commit

Permalink
Node: add SINTERSTORE command (valkey-io#1929)
Browse files Browse the repository at this point in the history
Signed-off-by: aaron-congo <aaron.congo@improving.com>
  • Loading branch information
aaron-congo authored and jonathanl-bq committed Jul 12, 2024
1 parent 5ff9575 commit 358e16d
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#### Changes
* 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))
* Node: Added SDIFF command ([#1924](https://github.com/valkey-io/valkey-glide/pull/1924))

Expand Down
21 changes: 21 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import {
createSCard,
createSDiff,
createSInter,
createSInterStore,
createSIsMember,
createSMembers,
createSMove,
Expand Down Expand Up @@ -1318,6 +1319,26 @@ export class BaseClient {
);
}

/**
* Stores the members of the intersection of all given sets specified by `keys` into a new set at `destination`.
*
* See https://valkey.io/commands/sinterstore/ for more details.
*
* @remarks When in cluster mode, `destination` and all `keys` must map to the same hash slot.
* @param destination - The key of the destination set.
* @param keys - The keys from which to retrieve the set members.
* @returns The number of elements in the resulting set.
*
* @example
* ```typescript
* const result = await client.sinterstore("my_set", ["set1", "set2"]);
* console.log(result); // Output: 2 - Two elements were stored at "my_set", and those elements are the intersection of "set1" and "set2".
* ```
*/
public sinterstore(destination: string, keys: string[]): Promise<number> {
return this.createWritePromise(createSInterStore(destination, keys));
}

/**
* Computes the difference between the first set and all the successive sets in `keys`.
*
Expand Down
10 changes: 10 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,16 @@ export function createSInter(keys: string[]): command_request.Command {
return createCommand(RequestType.SInter, keys);
}

/**
* @internal
*/
export function createSInterStore(
destination: string,
keys: string[],
): command_request.Command {
return createCommand(RequestType.SInterStore, [destination].concat(keys));
}

/**
* @internal
*/
Expand Down
15 changes: 15 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import {
createSCard,
createSDiff,
createSInter,
createSInterStore,
createSIsMember,
createSMembers,
createSMove,
Expand Down Expand Up @@ -734,6 +735,20 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
return this.addAndReturn(createSInter(keys), true);
}

/**
* Stores the members of the intersection of all given sets specified by `keys` into a new set at `destination`.
*
* See https://valkey.io/commands/sinterstore/ for more details.
*
* @param destination - The key of the destination set.
* @param keys - The keys from which to retrieve the set members.
*
* Command Response - The number of elements in the resulting set.
*/
public sinterstore(destination: string, keys: string[]): T {
return this.addAndReturn(createSInterStore(destination, keys));
}

/**
* Computes the difference between the first set and all the successive sets in `keys`.
*
Expand Down
1 change: 1 addition & 0 deletions node/tests/RedisClusterClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ describe("GlideClusterClient", () => {
client.smove("abc", "zxy", "value"),
client.renamenx("abc", "zxy"),
client.sinter(["abc", "zxy", "lkn"]),
client.sinterstore("abc", ["zxy", "lkn"]),
client.zinterstore("abc", ["zxy", "lkn"]),
client.sunionstore("abc", ["zxy", "lkn"]),
client.sunion(["abc", "zxy", "lkn"]),
Expand Down
58 changes: 58 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1191,6 +1191,64 @@ export function runBaseTests<Context>(config: {
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`sinterstore test_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key1 = `{key}-1-${uuidv4()}`;
const key2 = `{key}-2-${uuidv4()}`;
const key3 = `{key}-3-${uuidv4()}`;
const nonExistingKey = `{key}-4-${uuidv4()}`;
const stringKey = `{key}-5-${uuidv4()}`;
const member1_list = ["a", "b", "c"];
const member2_list = ["c", "d", "e"];

expect(await client.sadd(key1, member1_list)).toEqual(3);
expect(await client.sadd(key2, member2_list)).toEqual(3);

// store in a new key
expect(await client.sinterstore(key3, [key1, key2])).toEqual(1);
checkSimple(await client.smembers(key3)).toEqual(
new Set(["c"]),
);

// overwrite existing set, which is also a source set
expect(await client.sinterstore(key2, [key2, key3])).toEqual(1);
checkSimple(await client.smembers(key2)).toEqual(
new Set(["c"]),
);

// source set is the same as the existing set
expect(await client.sinterstore(key2, [key2])).toEqual(1);
checkSimple(await client.smembers(key2)).toEqual(
new Set(["c"]),
);

// intersection with non-existing key
expect(
await client.sinterstore(key1, [key2, nonExistingKey]),
).toEqual(0);
checkSimple(await client.smembers(key1)).toEqual(new Set());

// invalid argument - key list must not be empty
await expect(client.sinterstore(key3, [])).rejects.toThrow();

// non-set key
checkSimple(await client.set(stringKey, "foo")).toEqual("OK");
await expect(
client.sinterstore(key3, [stringKey]),
).rejects.toThrow();

// overwrite non-set key
expect(await client.sinterstore(stringKey, [key2])).toEqual(1);
checkSimple(await client.smembers(stringKey)).toEqual(
new Set("c"),
);
}, protocol);
},
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`sdiff test_%p`,
async (protocol) => {
Expand Down
2 changes: 2 additions & 0 deletions node/tests/TestUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ export async function transactionTest(
args.push(new Set(["bar", "foo"]));
baseTransaction.sinter([key7, key7]);
args.push(new Set(["bar", "foo"]));
baseTransaction.sinterstore(key7, [key7, key7]);
args.push(2);
baseTransaction.sdiff([key7, key7]);
args.push(new Set());
baseTransaction.srem(key7, ["foo"]);
Expand Down

0 comments on commit 358e16d

Please sign in to comment.