Skip to content
Merged
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 @@ -19,6 +19,7 @@
* Python: Added PFADD command ([#1315](https://github.com/aws/glide-for-redis/pull/1315))
* Python: Added ZMSCORE command ([#1357](https://github.com/aws/glide-for-redis/pull/1357))
* Python: Added HRANDFIELD command ([#1334](https://github.com/aws/glide-for-redis/pull/1334))
* Node: Added BLPOP command ([#1223](https://github.com/aws/glide-for-redis/pull/1223))
* Python: Added XADD, XTRIM commands ([#1320](https://github.com/aws/glide-for-redis/pull/1320))

#### Fixes
Expand Down
37 changes: 35 additions & 2 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
StreamReadOptions,
StreamTrimOptions,
ZaddOptions,
createBlpop,
createBrpop,
createDecr,
createDecrBy,
Expand Down Expand Up @@ -2190,13 +2191,16 @@ export class BaseClient {
* with the given keys being checked in the order that they are given.
* Blocks the connection when there are no elements to pop from any of the given lists.
* See https://redis.io/commands/brpop/ for more details.
* Note: BRPOP is a blocking command,
*
* Notes:
* 1. `BRPOP` is a blocking command,
* see [Blocking Commands](https://github.com/aws/glide-for-redis/wiki/General-Concepts#blocking-commands) for more details and best practices.
* 2. When in cluster mode, all `keys` must map to the same `hash slot`.
*
* @param keys - The `keys` of the lists to pop from.
* @param timeout - The `timeout` in seconds.
* @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.
* formatted as [key, value]. If no element could be popped and the timeout expired, returns `null`.
*
* @example
* ```typescript
Expand All @@ -2212,6 +2216,35 @@ export class BaseClient {
return this.createWritePromise(createBrpop(keys, timeout));
}

/** Blocking list pop primitive.
* Pop an element from the head of the first list that is non-empty,
* with the given `keys` being checked in the order that they are given.
* Blocks the connection when there are no elements to pop from any of the given lists.
* See https://redis.io/commands/blpop/ for more details.
*
* Notes:
* 1. `BLPOP` is a blocking command,
* see [Blocking Commands](https://github.com/aws/glide-for-redis/wiki/General-Concepts#blocking-commands) for more details and best practices.
* 2. When in cluster mode, all `keys` must map to the same `hash slot`.
*
* @param keys - The `keys` of the lists to pop from.
* @param timeout - The `timeout` in seconds.
* @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`.
*
* @example
* ```typescript
* const result = await client.blpop(["list1", "list2"], 5);
* console.log(result); // Output: ['list1', 'element']
* ```
*/
public blpop(
keys: string[],
timeout: number,
): Promise<[string, string] | null> {
return this.createWritePromise(createBlpop(keys, timeout));
}

/** Adds all elements to the HyperLogLog data structure stored at the specified `key`.
* Creates a new structure if the `key` does not exist.
* When no elements are provided, and `key` exists and is a HyperLogLog, then no operation is performed.
Expand Down
11 changes: 11 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1221,6 +1221,17 @@ export function createBrpop(
return createCommand(RequestType.Brpop, args);
}

/**
* @internal
*/
export function createBlpop(
keys: string[],
timeout: number,
): redis_request.Command {
const args = [...keys, timeout.toString()];
return createCommand(RequestType.Blpop, args);
}

export type StreamReadOptions = {
/**
* If set, the read request will block for the set amount of milliseconds or until the server has the required number of entries.
Expand Down
22 changes: 20 additions & 2 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
StreamReadOptions,
StreamTrimOptions,
ZaddOptions,
createBlpop,
createBrpop,
createClientGetName,
createClientId,
Expand Down Expand Up @@ -1243,18 +1244,35 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* with the given keys being checked in the order that they are given.
* Blocks the connection when there are no elements to pop from any of the given lists.
* See https://redis.io/commands/brpop/ for more details.
* Note: BRPOP is a blocking command,
* Note: `BRPOP` is a blocking command,
* see [Blocking Commands](https://github.com/aws/glide-for-redis/wiki/General-Concepts#blocking-commands) for more details and best practices.
*
* @param keys - The `keys` of the lists to pop from.
* @param timeout - The `timeout` in seconds.
* Command Response - 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.
* formatted as [key, value]. If no element could be popped and the timeout expired, returns `null`.
*/
public brpop(keys: string[], timeout: number): T {
return this.addAndReturn(createBrpop(keys, timeout));
}

/** Blocking list pop primitive.
* Pop an element from the head of the first list that is non-empty,
* with the given `keys` being checked in the order that they are given.
* Blocks the connection when there are no elements to pop from any of the given lists.
* See https://redis.io/commands/blpop/ for more details.
* Note: `BLPOP` is a blocking command,
* see [Blocking Commands](https://github.com/aws/glide-for-redis/wiki/General-Concepts#blocking-commands) for more details and best practices.
*
* @param keys - The `keys` of the lists to pop from.
* @param timeout - The `timeout` in seconds.
* Command Response - 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`.
*/
public blpop(keys: string[], timeout: number): T {
return this.addAndReturn(createBlpop(keys, timeout));
}

/** Adds all elements to the HyperLogLog data structure stored at the specified `key`.
* Creates a new structure if the `key` does not exist.
* When no elements are provided, and `key` exists and is a HyperLogLog, then no operation is performed.
Expand Down
53 changes: 53 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2049,6 +2049,59 @@ export function runBaseTests<Context>(config: {
expect(await client.del(["brpop-test"])).toEqual(1);
// Test null return when key doesn't exist
expect(await client.brpop(["brpop-test"], 0.1)).toEqual(null);
// key exists, but it is not a list
await client.set("foo", "bar");
await expect(client.brpop(["foo"], 0.1)).rejects.toThrow();

// Same-slot requirement
if (client instanceof RedisClusterClient) {
try {
expect(
await client.brpop(["abc", "zxy", "lkn"], 0.1),
).toThrow();
} catch (e) {
expect((e as Error).message.toLowerCase()).toMatch(
"crossslot",
);
}
}
}, protocol);
},
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`test blpop test_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
expect(
await client.rpush("blpop-test", ["foo", "bar", "baz"]),
).toEqual(3);
// Test basic usage
expect(await client.blpop(["blpop-test"], 0.1)).toEqual([
"blpop-test",
"foo",
]);
// Delete all values from list
expect(await client.del(["blpop-test"])).toEqual(1);
// Test null return when key doesn't exist
expect(await client.blpop(["blpop-test"], 0.1)).toEqual(null);
// key exists, but it is not a list
await client.set("foo", "bar");
await expect(client.blpop(["foo"], 0.1)).rejects.toThrow();

// Same-slot requirement
if (client instanceof RedisClusterClient) {
try {
expect(
await client.blpop(["abc", "zxy", "lkn"], 0.1),
).toThrow();
} catch (e) {
expect((e as Error).message.toLowerCase()).toMatch(
"crossslot",
);
}
}
}, protocol);
},
config.timeout,
Expand Down
2 changes: 2 additions & 0 deletions node/tests/TestUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ export async function transactionTest(
args.push(3);
baseTransaction.brpop([key6], 0.1);
args.push([key6, field + "3"]);
baseTransaction.blpop([key6], 0.1);
args.push([key6, field + "1"]);
baseTransaction.pfadd(key11, ["a", "b", "c"]);
args.push(1);
return args;
Expand Down