Skip to content

Commit

Permalink
Node: Add binary support to RPUSH RPOP RPOPCOUNT BLPOP BRPOP (valkey-…
Browse files Browse the repository at this point in the history
…io#2153)

* add binary support to rpush rpop rpopcount blpop brpop

* updated decoder docs for all functions where binary variant was added 

---------

Signed-off-by: lior sventitzky <[email protected]>
  • Loading branch information
liorsve authored Aug 21, 2024
1 parent 2683edc commit 908032e
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 31 deletions.
65 changes: 47 additions & 18 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -937,7 +937,8 @@ export class BaseClient {
* @see {@link https://valkey.io/commands/get/|valkey.io} for details.
*
* @param key - The key to retrieve from the database.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns If `key` exists, returns the value of `key`. Otherwise, return null.
*
* @example
Expand Down Expand Up @@ -988,7 +989,8 @@ export class BaseClient {
* @see {@link https://valkey.io/commands/getdel/|valkey.io} for details.
*
* @param key - The key to retrieve from the database.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns If `key` exists, returns the `value` of `key`. Otherwise, return `null`.
*
* @example
Expand Down Expand Up @@ -1018,7 +1020,8 @@ export class BaseClient {
* @param key - The key of the string.
* @param start - The starting offset.
* @param end - The ending offset.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns A substring extracted from the value stored at `key`.
*
* @example
Expand Down Expand Up @@ -1190,7 +1193,8 @@ export class BaseClient {
* @remarks When in cluster mode, the command may route to multiple nodes when `keys` map to different hash slots.
*
* @param keys - A list of keys to retrieve values for.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns A list of values corresponding to the provided keys. If a key is not found,
* its corresponding value in the list will be null.
*
Expand Down Expand Up @@ -1578,7 +1582,8 @@ export class BaseClient {
*
* @param key - The key of the hash.
* @param field - The field in the hash stored at `key` to retrieve from the database.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns the value associated with `field`, or null when `field` is not present in the hash or `key` does not exist.
*
* @example
Expand Down Expand Up @@ -1854,7 +1859,8 @@ export class BaseClient {
* @see {@link https://valkey.io/commands/hvals/|valkey.io} for more details.
*
* @param key - The key of the hash.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns a list of values in the hash, or an empty list when the key does not exist.
*
* @example
Expand Down Expand Up @@ -2389,7 +2395,10 @@ export class BaseClient {
* console.log(result); // Output: 1
* ```
*/
public async rpush(key: string, elements: string[]): Promise<number> {
public async rpush(
key: GlideString,
elements: GlideString[],
): Promise<number> {
return this.createWritePromise(createRPush(key, elements));
}

Expand Down Expand Up @@ -2418,6 +2427,8 @@ export class BaseClient {
* @see {@link https://valkey.io/commands/rpop/|valkey.io} for details.
*
* @param key - The key of the list.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns The value of the last element.
* If `key` does not exist null will be returned.
*
Expand All @@ -2435,8 +2446,11 @@ export class BaseClient {
* console.log(result); // Output: null
* ```
*/
public async rpop(key: string): Promise<string | null> {
return this.createWritePromise(createRPop(key));
public async rpop(
key: GlideString,
decoder?: Decoder,
): Promise<GlideString | null> {
return this.createWritePromise(createRPop(key), { decoder: decoder });
}

/** Removes and returns up to `count` elements from the list stored at `key`, depending on the list's length.
Expand All @@ -2445,6 +2459,8 @@ export class BaseClient {
*
* @param key - The key of the list.
* @param count - The count of the elements to pop from the list.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns A list of popped elements will be returned depending on the list's length.
* If `key` does not exist null will be returned.
*
Expand All @@ -2463,10 +2479,13 @@ export class BaseClient {
* ```
*/
public async rpopCount(
key: string,
key: GlideString,
count: number,
): Promise<string[] | null> {
return this.createWritePromise(createRPop(key, count));
decoder?: Decoder,
): Promise<GlideString[] | null> {
return this.createWritePromise(createRPop(key, count), {
decoder: decoder,
});
}

/** Adds the specified members to the set stored at `key`. Specified members that are already a member of this set are ignored.
Expand Down Expand Up @@ -5402,6 +5421,8 @@ export class BaseClient {
*
* @param keys - The `keys` of the lists to pop from.
* @param timeout - The `timeout` in seconds.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns - An `array` containing the `key` from which the element was popped and the value of the popped element,
* formatted as [key, value]. If no element could be popped and the timeout expired, returns `null`.
*
Expand All @@ -5413,10 +5434,13 @@ export class BaseClient {
* ```
*/
public async brpop(
keys: string[],
keys: GlideString[],
timeout: number,
): Promise<[string, string] | null> {
return this.createWritePromise(createBRPop(keys, timeout));
decoder?: Decoder,
): Promise<[GlideString, GlideString] | null> {
return this.createWritePromise(createBRPop(keys, timeout), {
decoder: decoder,
});
}

/** Blocking list pop primitive.
Expand All @@ -5430,6 +5454,8 @@ export class BaseClient {
*
* @param keys - The `keys` of the lists to pop from.
* @param timeout - The `timeout` in seconds.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns - An `array` containing the `key` from which the element was popped and the value of the popped element,
* formatted as [key, value]. If no element could be popped and the timeout expired, returns `null`.
*
Expand All @@ -5440,10 +5466,13 @@ export class BaseClient {
* ```
*/
public async blpop(
keys: string[],
keys: GlideString[],
timeout: number,
): Promise<[string, string] | null> {
return this.createWritePromise(createBLPop(keys, timeout));
decoder?: Decoder,
): Promise<[GlideString, GlideString] | null> {
return this.createWritePromise(createBLPop(keys, timeout), {
decoder: decoder,
});
}

/** Adds all elements to the HyperLogLog data structure stored at the specified `key`.
Expand Down
13 changes: 7 additions & 6 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -979,8 +979,8 @@ export function createLRem(
* @internal
*/
export function createRPush(
key: string,
elements: string[],
key: GlideString,
elements: GlideString[],
): command_request.Command {
return createCommand(RequestType.RPush, [key].concat(elements));
}
Expand All @@ -999,10 +999,11 @@ export function createRPushX(
* @internal
*/
export function createRPop(
key: string,
key: GlideString,
count?: number,
): command_request.Command {
const args: string[] = count == undefined ? [key] : [key, count.toString()];
const args: GlideString[] =
count == undefined ? [key] : [key, count.toString()];
return createCommand(RequestType.RPop, args);
}

Expand Down Expand Up @@ -2215,7 +2216,7 @@ export function createPublish(
* @internal
*/
export function createBRPop(
keys: string[],
keys: GlideString[],
timeout: number,
): command_request.Command {
const args = [...keys, timeout.toString()];
Expand All @@ -2226,7 +2227,7 @@ export function createBRPop(
* @internal
*/
export function createBLPop(
keys: string[],
keys: GlideString[],
timeout: number,
): command_request.Command {
const args = [...keys, timeout.toString()];
Expand Down
3 changes: 2 additions & 1 deletion node/src/GlideClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ export class GlideClient extends BaseClient {
* @param message - An optional message to include in the PING command.
* If not provided, the server will respond with "PONG".
* If provided, the server will respond with a copy of the message.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns - "PONG" if `message` is not provided, otherwise return a copy of `message`.
*
* @example
Expand Down
3 changes: 2 additions & 1 deletion node/src/GlideClusterClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,8 @@ export class GlideClusterClient extends BaseClient {
* If provided, the server will respond with a copy of the message.
* @param route - The command will be routed to all primaries, unless `route` is provided, in which
* case the client will route the command to the nodes defined by `route`.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response. If not set, the default decoder from the client config will be used.
* @param decoder - (Optional) {@link Decoder} type which defines how to handle the response.
* If not set, the {@link BaseClientConfiguration.defaultDecoder|default decoder} will be used.
* @returns - "PONG" if `message` is not provided, otherwise return a copy of `message`.
*
* @example
Expand Down
35 changes: 30 additions & 5 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2494,15 +2494,32 @@ export function runBaseTests(config: {
`rpush and rpop with existing and non existing key_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key = uuidv4();
const valueList = ["value1", "value2", "value3", "value4"];
expect(await client.rpush(key, valueList)).toEqual(4);
expect(await client.rpop(key)).toEqual("value4");
expect(await client.rpopCount(key, 2)).toEqual([
const key1 = uuidv4();
const key2 = Buffer.from(uuidv4());
const valueList1 = ["value1", "value2", "value3", "value4"];
const valueList2 = ["value5", "value6", "value7"];
expect(await client.rpush(key1, valueList1)).toEqual(4);
expect(await client.rpop(key1)).toEqual("value4");
expect(await client.rpopCount(key1, 2)).toEqual([
"value3",
"value2",
]);
expect(await client.rpop("nonExistingKey")).toEqual(null);

expect(await client.rpush(key2, valueList2)).toEqual(3);
expect(await client.rpop(key2, Decoder.Bytes)).toEqual(
Buffer.from("value7"),
);
expect(await client.rpopCount(key2, 2, Decoder.Bytes)).toEqual([
Buffer.from("value6"),
Buffer.from("value5"),
]);
expect(
await client.rpush(key2, [Buffer.from("value8")]),
).toEqual(1);
expect(await client.rpop(key2, Decoder.Bytes)).toEqual(
Buffer.from("value8"),
);
}, protocol);
},
config.timeout,
Expand Down Expand Up @@ -5750,6 +5767,10 @@ export function runBaseTests(config: {
"brpop-test",
"baz",
]);
// Test encoded value
expect(
await client.brpop(["brpop-test"], 0.1, Decoder.Bytes),
).toEqual([Buffer.from("brpop-test"), Buffer.from("bar")]);
// Delete all values from list
expect(await client.del(["brpop-test"])).toEqual(1);
// Test null return when key doesn't exist
Expand Down Expand Up @@ -5787,6 +5808,10 @@ export function runBaseTests(config: {
"blpop-test",
"foo",
]);
// Test decoded value
expect(
await client.blpop(["blpop-test"], 0.1, Decoder.Bytes),
).toEqual([Buffer.from("blpop-test"), Buffer.from("bar")]);
// Delete all values from list
expect(await client.del(["blpop-test"])).toEqual(1);
// Test null return when key doesn't exist
Expand Down

0 comments on commit 908032e

Please sign in to comment.