Skip to content

Commit

Permalink
Node: add SRANDMEMBER command (#2067)
Browse files Browse the repository at this point in the history
* Node: add SRANDMEMBER command

---------

Signed-off-by: Shoham Elias <[email protected]>
Signed-off-by: Andrew Carbonetto <[email protected]>
Co-authored-by: Shoham Elias <[email protected]>
  • Loading branch information
acarbonetto and shohamazon authored Aug 7, 2024
1 parent 80f8153 commit 1b5c73b
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 1 deletion.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@
* Node: Added PFMERGE command ([#2053](https://github.com/valkey-io/valkey-glide/pull/2053))
* Node: Added WATCH and UNWATCH commands ([#2076](https://github.com/valkey-io/valkey-glide/pull/2076))
* Node: Added ZLEXCOUNT command ([#2022](https://github.com/valkey-io/valkey-glide/pull/2022))
* Node: Added ZREMRANGEBYLEX command ([#2025](https://github.com/valkey-io/valkey-glide/pull/2025))
* Node: Added ZREMRANGEBYLEX command ([#2025]((https://github.com/valkey-io/valkey-glide/pull/2025))
* Node: Added SRANDMEMBER command ([#2067](https://github.com/valkey-io/valkey-glide/pull/2067))
* Node: Added ZSCAN command ([#2061](https://github.com/valkey-io/valkey-glide/pull/2061))
* Node: Added SETRANGE command ([#2066](https://github.com/valkey-io/valkey-glide/pull/2066))
* Node: Added XDEL command ([#2064](https://github.com/valkey-io/valkey-glide/pull/2064))
Expand Down
59 changes: 59 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ import {
createSMembers,
createSMove,
createSPop,
createSRandMember,
createSRem,
createSUnion,
createSUnionStore,
Expand Down Expand Up @@ -2377,6 +2378,64 @@ export class BaseClient {
);
}

/**
* Returns a random element from the set value stored at `key`.
*
* See https://valkey.io/commands/srandmember for more details.
*
* @param key - The key from which to retrieve the set member.
* @returns A random element from the set, or null if `key` does not exist.
*
* @example
* ```typescript
* // Example usage of srandmember method to return a random member from a set
* const result = await client.srandmember("my_set");
* console.log(result); // Output: 'member1' - A random member of "my_set".
* ```
*
* @example
* ```typescript
* // Example usage of srandmember method with non-existing key
* const result = await client.srandmember("non_existing_set");
* console.log(result); // Output: null
* ```
*/
public srandmember(key: string): Promise<string | null> {
return this.createWritePromise(createSRandMember(key));
}

/**
* Returns one or more random elements from the set value stored at `key`.
*
* See https://valkey.io/commands/srandmember for more details.
*
* @param key - The key of the sorted set.
* @param count - The number of members to return.
* If `count` is positive, returns unique members.
* If `count` is negative, allows for duplicates members.
* @returns a list of members from the set. If the set does not exist or is empty, an empty list will be returned.
*
* @example
* ```typescript
* // Example usage of srandmemberCount method to return multiple random members from a set
* const result = await client.srandmemberCount("my_set", -3);
* console.log(result); // Output: ['member1', 'member1', 'member2'] - Random members of "my_set".
* ```
*
* @example
* ```typescript
* // Example usage of srandmemberCount method with non-existing key
* const result = await client.srandmemberCount("non_existing_set", 3);
* console.log(result); // Output: [] - An empty list since the key does not exist.
* ```
*/
public async srandmemberCount(
key: string,
count: number,
): Promise<string[]> {
return this.createWritePromise(createSRandMember(key, count));
}

/** Returns the number of keys in `keys` that exist in the database.
* See https://valkey.io/commands/exists/ for details.
*
Expand Down
11 changes: 11 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1168,6 +1168,17 @@ export function createSPop(
return createCommand(RequestType.SPop, args);
}

/**
* @internal
*/
export function createSRandMember(
key: string,
count?: number,
): command_request.Command {
const args: string[] = count == undefined ? [key] : [key, count.toString()];
return createCommand(RequestType.SRandMember, args);
}

/**
* @internal
*/
Expand Down
26 changes: 26 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ import {
createSMembers,
createSMove,
createSPop,
createSRandMember,
createSRem,
createSUnion,
createSUnionStore,
Expand Down Expand Up @@ -1306,6 +1307,31 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
return this.addAndReturn(createSPop(key, count), true);
}

/** Returns a random element from the set value stored at `key`.
*
* See https://valkey.io/commands/srandmember for more details.
*
* @param key - The key from which to retrieve the set member.
* Command Response - A random element from the set, or null if `key` does not exist.
*/
public srandmember(key: string): T {
return this.addAndReturn(createSRandMember(key));
}

/** Returns one or more random elements from the set value stored at `key`.
*
* See https://valkey.io/commands/srandmember for more details.
*
* @param key - The key of the sorted set.
* @param count - The number of members to return.
* If `count` is positive, returns unique members.
* If `count` is negative, allows for duplicates members.
* Command Response - A list of members from the set. If the set does not exist or is empty, an empty list will be returned.
*/
public srandmemberCount(key: string, count: number): T {
return this.addAndReturn(createSRandMember(key, count));
}

/** Returns the number of keys in `keys` that exist in the database.
* See https://valkey.io/commands/exists/ for details.
*
Expand Down
42 changes: 42 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2656,6 +2656,48 @@ export function runBaseTests<Context>(config: {
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`srandmember and srandmemberCount test_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key = uuidv4();
const members = ["member1", "member2", "member3"];
expect(await client.sadd(key, members)).toEqual(3);

const result2 = await client.srandmember(key);
expect(members).toContain(result2);
expect(await client.srandmember("nonExistingKey")).toEqual(
null,
);

// unique values are expected as count is positive
let result = await client.srandmemberCount(key, 4);
expect(result.length).toEqual(3);
expect(new Set(result)).toEqual(new Set(members));

// duplicate values are expected as count is negative
result = await client.srandmemberCount(key, -4);
expect(result.length).toEqual(4);
result.forEach((member) => {
expect(members).toContain(member);
});

// empty return values for non-existing or empty keys
result = await client.srandmemberCount(key, 0);
expect(result.length).toEqual(0);
expect(result).toEqual([]);
expect(
await client.srandmemberCount("nonExistingKey", 0),
).toEqual([]);

expect(await client.set(key, "value")).toBe("OK");
await expect(client.srandmember(key)).rejects.toThrow();
await expect(client.srandmemberCount(key, 2)).rejects.toThrow();
}, protocol);
},
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`exists with existing keys, an non existing key_%p`,
async (protocol) => {
Expand Down
6 changes: 6 additions & 0 deletions node/tests/TestUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,12 @@ export async function transactionTest(

baseTransaction.smembers(key7);
responseData.push(["smembers(key7)", new Set(["bar"])]);
baseTransaction.srandmember(key7);
responseData.push(["srandmember(key7)", "bar"]);
baseTransaction.srandmemberCount(key7, 2);
responseData.push(["srandmemberCount(key7, 2)", ["bar"]]);
baseTransaction.srandmemberCount(key7, -2);
responseData.push(["srandmemberCount(key7, -2)", ["bar", "bar"]]);
baseTransaction.spop(key7);
responseData.push(["spop(key7)", "bar"]);
baseTransaction.spopCount(key7, 2);
Expand Down

0 comments on commit 1b5c73b

Please sign in to comment.