Skip to content

Commit

Permalink
Node: add SINTERSTORE command
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 committed Jul 12, 2024
1 parent a597a5d commit c31a581
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))

## 1.0.0 (2024-07-09)
Expand Down
21 changes: 21 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import {
createSAdd,
createSCard,
createSInter,
createSInterStore,
createSIsMember,
createSMembers,
createSMove,
Expand Down Expand Up @@ -1317,6 +1318,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));
}

/**
* Gets the union of all the given sets.
*
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 @@ -77,6 +77,7 @@ import {
createSAdd,
createSCard,
createSInter,
createSInterStore,
createSIsMember,
createSMembers,
createSMove,
Expand Down Expand Up @@ -733,6 +734,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));
}

/**
* Gets the union of all the given sets.
*
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])(
`sunion 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.srem(key7, ["foo"]);
args.push(1);
baseTransaction.scard(key7);
Expand Down

0 comments on commit c31a581

Please sign in to comment.