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 SRANDMEMBER command #1938

Closed
wants to merge 1 commit into from
Closed
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 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))
* Node: Added SRANDMEMBER command ([#1938](https://github.com/valkey-io/valkey-glide/pull/1938))

## 1.0.0 (2024-07-09)

Expand Down
58 changes: 57 additions & 1 deletion node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as net from "net";
import { Buffer, BufferWriter, Reader, Writer } from "protobufjs";
import {
AggregationType,
BulkString,
ExpireOptions,
InsertPosition,
KeyWeight,
Expand Down Expand Up @@ -80,7 +81,9 @@ import {
createSMembers,
createSMove,
createSPop,
createSRandMember,
createSRem,
createSUnion,
createSUnionStore,
createSet,
createStrlen,
Expand All @@ -105,7 +108,6 @@ import {
createZRemRangeByRank,
createZRemRangeByScore,
createZScore,
createSUnion,
} from "./Commands";
import {
ClosingError,
Expand Down Expand Up @@ -1491,6 +1493,60 @@ 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* @returns a random element from the set, or null if `key` does not exist.
* @returns A random element from the set, or null if `key` does not exist.

Should we capitalize? If not, please ignore

*
* @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: BulkString): Promise<BulkString | 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* @returns a list of members from the set. If the set does not exist or is empty, an empty list will be returned.
* @returns A list of members from the set. If the set does not exist or is empty, an empty list will be returned.

Same here

*
* @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: BulkString,
count: number,
): Promise<BulkString[]> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we need to merge #1953 ahead of this

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
14 changes: 13 additions & 1 deletion node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function isLargeCommand(args: BulkString[]) {
return false;
}

type BulkString = string | Uint8Array;
export type BulkString = string | Uint8Array;

/**
* Convert a string array into Uint8Array[]
Expand Down Expand Up @@ -669,6 +669,18 @@ export function createSPop(
return createCommand(RequestType.SPop, args);
}

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

/**
* @internal
*/
Expand Down
27 changes: 26 additions & 1 deletion node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {
AggregationType,
BulkString,
ExpireOptions,
InfoOptions,
InsertPosition,
Expand Down Expand Up @@ -83,7 +84,9 @@ import {
createSMembers,
createSMove,
createSPop,
createSRandMember,
createSRem,
createSUnion,
createSUnionStore,
createSelect,
createSet,
Expand All @@ -110,7 +113,6 @@ import {
createZRemRangeByRank,
createZRemRangeByScore,
createZScore,
createSUnion,
} from "./Commands";
import { command_request } from "./ProtobufMessage";

Expand Down Expand Up @@ -831,6 +833,29 @@ 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* Command Response - a random element from the set, or null if `key` does not exist.
* Command Response - A random element from the set, or null if `key` does not exist.

*/
public srandmember(key: BulkString): 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
* Command Response - a list of members from the set. If the set does not exist or is empty, an empty list will be returned.
* 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: BulkString, 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 @@ -1428,6 +1428,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(intoString(result2));
expect(await client.srandmember("nonExistingKey")).toEqual(
null,
);

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

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

// empty return values for non-existing or empty keys
result = await client.srandmemberCount(key, 0);
checkSimple(result.length).toEqual(0);
checkSimple(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 @@ -404,6 +404,12 @@ export async function transactionTest(
args.push(true);
baseTransaction.smembers(key7);
args.push(new Set(["bar"]));
baseTransaction.srandmember(key7);
args.push("bar");
baseTransaction.srandmemberCount(key7, 2);
args.push(["bar"]);
baseTransaction.srandmemberCount(key7, -2);
args.push(["bar", "bar"]);
baseTransaction.spop(key7);
args.push("bar");
baseTransaction.spopCount(key7, 2);
Expand Down
Loading