From bf37285b0dc9dd69695f0ec60167ef80294cb8fa Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Wed, 31 Jul 2024 14:38:58 -0700 Subject: [PATCH 01/18] Update changelog Signed-off-by: Jonathan Louie --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10e2e3cf99..9e20c14e2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ * Node: Added ZMPOP command ([#1994](https://github.com/valkey-io/valkey-glide/pull/1994)) * Node: Added ZINCRBY command ([#2009](https://github.com/valkey-io/valkey-glide/pull/2009)) * Node: Added BZMPOP command ([#2018](https://github.com/valkey-io/valkey-glide/pull/2018)) +* Node: Added XRANGE command ([](https://github.com/valkey-io/valkey-glide/pull/)) #### Breaking Changes * Node: (Refactor) Convert classes to types ([#2005](https://github.com/valkey-io/valkey-glide/pull/2005)) From 1eb96b1851a70375147b9b3bf40f439691b658ff Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Thu, 1 Aug 2024 00:32:01 -0700 Subject: [PATCH 02/18] Implement XRANGE command Signed-off-by: Jonathan Louie --- node/src/BaseClient.ts | 40 ++++++++++++++++++++++ node/src/Commands.ts | 55 ++++++++++++++++++++++++++++++ node/src/Transaction.ts | 29 ++++++++++++++++ node/tests/SharedTests.ts | 67 +++++++++++++++++++++++++++++++++++++ node/tests/TestUtilities.ts | 2 ++ 5 files changed, 193 insertions(+) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index ef25d8be0e..07c6712f18 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -30,6 +30,7 @@ import { ScoreFilter, SetOptions, StreamAddOptions, + StreamRangeBound, StreamReadOptions, StreamTrimOptions, ZAddOptions, @@ -120,6 +121,7 @@ import { createUnlink, createXAdd, createXLen, + createXRange, createXRead, createXTrim, createZAdd, @@ -2369,6 +2371,44 @@ export class BaseClient { return this.createWritePromise(scriptInvocation); } + /** + * Returns stream entries matching a given range of IDs. + * + * See https://valkey.io/commands/xrange for more details. + * + * @param key - The key of the stream. + * @param start - The starting stream ID bound for the range. + * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `-` to start with the minimum available ID. + * @param end - The ending stream ID bound for the range. + * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `+` to end with the maximum available ID. + * @param count - An optional argument specifying the maximum count of stream entries to return. + * If `count` is not provided, all stream entries in the range will be returned. + * @returns A mapping of stream IDs to stream entry data, where entry data is a + * list of pairings with format `[[field, entry], [field, entry], ...]`. + * + * @example + * ```typescript + * await client.xadd("mystream", [["field1", "value1"]], {id: "0-1"}); + * await client.xadd("mystream", [["field2", "value2"], ["field2", "value3"]], {id: "0-2"}); + * const result = await client.xrange("mystream", "-", "+"); + * // Output: + * // { + * // "0-1": [["field1", "value1"]], + * // "0-2": [["field2", "value2"], ["field2", "value3"]], + * // } // Indicates the stream IDs and their associated field-value pairs for all stream entries in "mystream". + * ``` + */ + public async xrange( + key: string, + start: StreamRangeBound, + end: StreamRangeBound, + count?: number + ): Promise | null> { + return this.createWritePromise(createXRange(key, start, end, count)); + } + /** Adds members with their scores to the sorted set stored at `key`. * If a member is already a part of the sorted set, its score is updated. * See https://valkey.io/commands/zadd/ for more details. diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 4c1c6254c3..7f0bb5a411 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1601,6 +1601,61 @@ export function createXTrim( return createCommand(RequestType.XTrim, args); } +export type StreamRangeBound = ( + /** + * Stream ID boundary used to specify the minimum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands + * to get the first stream ID. + */ + | "-" + /** + * Stream ID boundary used to specify the maximum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands + * to get the last stream ID. + */ + | "+" + /** + * Stream ID boundary used to specify a range of IDs to search. Stream ID bounds can be complete with + * a timestamp and sequence number separated by a dash ("-"), for example "1526985054069-0". Stream ID bounds can also + * be incomplete, with just a timestamp. Can be specified as inclusive or exclusive, where inclusive is the default. + */ + | { + exclusive?: "("; + id: string | number; + } +); + +function addRangeBound(rangeBound: StreamRangeBound, args: string[]) { + if (rangeBound === "-" || rangeBound === "+") { + args.push(rangeBound); + return; + } + + if (rangeBound.exclusive) { + args.push(rangeBound.exclusive + rangeBound.id.toString()); + } else { + args.push(rangeBound.id.toString()); + } +} + +/** + * @internal + */ +export function createXRange( + key: string, + start: StreamRangeBound, + end: StreamRangeBound, + count?: number +): command_request.Command { + const args = [key]; + addRangeBound(start, args); + addRangeBound(end, args); + if (count !== undefined) { + args.push("COUNT"); + args.push(count.toString()); + } + return createCommand(RequestType.XRange, args); +} + + /** * @internal */ diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index b945655cbb..34ac6c31f5 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -25,6 +25,7 @@ import { ScoreFilter, SetOptions, StreamAddOptions, + StreamRangeBound, StreamReadOptions, StreamTrimOptions, ZAddOptions, @@ -134,6 +135,7 @@ import { createUnlink, createXAdd, createXLen, + createXRange, createXRead, createXTrim, createZAdd, @@ -1780,6 +1782,33 @@ export class BaseTransaction> { return this.addAndReturn(createTime()); } + /** + * Returns stream entries matching a given range of IDs. + * + * See https://valkey.io/commands/xrange for more details. + * + * @param key - The key of the stream. + * @param start - The starting stream ID bound for the range. + * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `-` to start with the minimum available ID. + * @param end - The ending stream ID bound for the range. + * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `+` to end with the maximum available ID. + * @param count - An optional argument specifying the maximum count of stream entries to return. + * If `count` is not provided, all stream entries in the range will be returned. + * + * Command Response - A mapping of stream IDs to stream entry data, where entry data is a + * list of pairings with format `[[field, entry], [field, entry], ...]`. + */ + public xrange( + key: string, + start: StreamRangeBound, + end: StreamRangeBound, + count?: number + ): T { + return this.addAndReturn(createXRange(key, start, end, count)); + } + /** * Reads entries from the given streams. * See https://valkey.io/commands/xread/ for more details. diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 81fb10e214..e2c9e997e4 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -3789,6 +3789,73 @@ export function runBaseTests(config: { config.timeout, ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `xrange test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + const key = uuidv4(); + const nonExistingKey = uuidv4(); + const stringKey = uuidv4(); + const streamId1 = "0-1"; + const streamId2 = "0-2"; + const streamId3 = "0-3"; + + expect( + await client.xadd( + key, [["f1", "v1"]], {id: streamId1} + ) + ).toEqual(streamId1); + expect( + await client.xadd( + key, [["f2", "v2"]], {id: streamId2} + ) + ).toEqual(streamId2); + expect(await client.xlen(key)).toEqual(2) + + // get everything from the stream + expect(await client.xrange(key, "-", "+")).toEqual({ + streamId1: [["f1", "v1"]], + streamId2: [["f2", "v2"]], + }); + + // returns empty mapping if + before - + expect(await client.xrange(key, "+", "-")).toEqual({}) + + expect( + await client.xadd( + key, [["f3", "v3"]], {id: streamId3} + ) + ).toEqual(streamId3); + + // get the newest entry + expect(await client.xrange( + key, {exclusive: "(", id: streamId2}, {id: 5}, 1 + )).toEqual({streamId3: [["f3", "v3"]]}); + + // xrange against an emptied stream + expect(await client.customCommand(["XDEL", key, streamId1, streamId2, streamId3])).toEqual(3); + expect(await client.xrange(key, "-", "+", 10)).toEqual({}); + + expect(await client.xrange(nonExistingKey, "-", "+")).toEqual({}); + + // count value < 1 returns null + expect(await client.xrange(key, "-", "+", 0)).toEqual(null); + expect(await client.xrange(key, "-", "+", -1)).toEqual(null); + + // key exists, but it is not a stream + expect(await client.set(stringKey, "foo")); + await expect(client.xrange(stringKey, "-", "+")).rejects.toThrow(RequestError); + + // invalid start bound + await expect(client.xrange(key, {id: "not_a_stream_id"}, "+")).rejects.toThrow(RequestError); + + // invalid end bound + await expect(client.xrange(key, "-", {id: "not_a_stream_id"})).rejects.toThrow(RequestError); + }, protocol); + }, + config.timeout, + ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `zremRangeByScore test_%p`, async (protocol) => { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 17ce37c6f6..b3d32e7719 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -698,6 +698,8 @@ export async function transactionTest( ]); baseTransaction.xlen(key9); responseData.push(["xlen(key9)", 3]); + baseTransaction.xrange(key9, {id: "0-1"}, {id: "0-1"}); + responseData.push(["xrange(key9)", {"0-1": [["field", "value1"]]}]); baseTransaction.xread({ [key9]: "0-1" }); responseData.push([ 'xread({ [key9]: "0-1" })', From 66f7d9d46fd2cbbcb213e50cc7512e383dbe0641 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Thu, 1 Aug 2024 00:54:02 -0700 Subject: [PATCH 03/18] Update CHANGELOG.md Signed-off-by: Jonathan Louie --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 095d961bd2..0d41cd8d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,7 +42,7 @@ * Node: Added ZMPOP command ([#1994](https://github.com/valkey-io/valkey-glide/pull/1994)) * Node: Added ZINCRBY command ([#2009](https://github.com/valkey-io/valkey-glide/pull/2009)) * Node: Added BZMPOP command ([#2018](https://github.com/valkey-io/valkey-glide/pull/2018)) -* Node: Added XRANGE command ([](https://github.com/valkey-io/valkey-glide/pull/)) +* Node: Added XRANGE command ([#2069](https://github.com/valkey-io/valkey-glide/pull/2069)) * Node: Added PFMERGE command ([#2053](https://github.com/valkey-io/valkey-glide/pull/2053)) * 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)) From c54db23b788182b034d1b4d447f9a770d2914f82 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Thu, 1 Aug 2024 01:23:14 -0700 Subject: [PATCH 04/18] Apply prettier Signed-off-by: Jonathan Louie --- node/src/BaseClient.ts | 6 ++--- node/src/Commands.ts | 14 +++++----- node/src/Transaction.ts | 6 ++--- node/tests/SharedTests.ts | 53 ++++++++++++++++++++++++------------- node/tests/TestUtilities.ts | 4 +-- 5 files changed, 48 insertions(+), 35 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index e66b1fef63..e74e98d975 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -2564,7 +2564,7 @@ export class BaseClient { /** * Returns stream entries matching a given range of IDs. - * + * * See https://valkey.io/commands/xrange for more details. * * @param key - The key of the stream. @@ -2578,7 +2578,7 @@ export class BaseClient { * If `count` is not provided, all stream entries in the range will be returned. * @returns A mapping of stream IDs to stream entry data, where entry data is a * list of pairings with format `[[field, entry], [field, entry], ...]`. - * + * * @example * ```typescript * await client.xadd("mystream", [["field1", "value1"]], {id: "0-1"}); @@ -2595,7 +2595,7 @@ export class BaseClient { key: string, start: StreamRangeBound, end: StreamRangeBound, - count?: number + count?: number, ): Promise | null> { return this.createWritePromise(createXRange(key, start, end, count)); } diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 7b8eaf2708..1ccfc11388 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1974,10 +1974,10 @@ export function createXTrim( return createCommand(RequestType.XTrim, args); } -export type StreamRangeBound = ( +export type StreamRangeBound = /** * Stream ID boundary used to specify the minimum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands - * to get the first stream ID. + * to get the first stream ID. */ | "-" /** @@ -1991,10 +1991,9 @@ export type StreamRangeBound = ( * be incomplete, with just a timestamp. Can be specified as inclusive or exclusive, where inclusive is the default. */ | { - exclusive?: "("; - id: string | number; - } -); + exclusive?: "("; + id: string | number; + }; function addRangeBound(rangeBound: StreamRangeBound, args: string[]) { if (rangeBound === "-" || rangeBound === "+") { @@ -2016,7 +2015,7 @@ export function createXRange( key: string, start: StreamRangeBound, end: StreamRangeBound, - count?: number + count?: number, ): command_request.Command { const args = [key]; addRangeBound(start, args); @@ -2028,7 +2027,6 @@ export function createXRange( return createCommand(RequestType.XRange, args); } - /** * @internal */ diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 3daf52eac2..8d2d86f160 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -2017,7 +2017,7 @@ export class BaseTransaction> { /** * Returns stream entries matching a given range of IDs. - * + * * See https://valkey.io/commands/xrange for more details. * * @param key - The key of the stream. @@ -2029,7 +2029,7 @@ export class BaseTransaction> { * - Use `+` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. * If `count` is not provided, all stream entries in the range will be returned. - * + * * Command Response - A mapping of stream IDs to stream entry data, where entry data is a * list of pairings with format `[[field, entry], [field, entry], ...]`. */ @@ -2037,7 +2037,7 @@ export class BaseTransaction> { key: string, start: StreamRangeBound, end: StreamRangeBound, - count?: number + count?: number, ): T { return this.addAndReturn(createXRange(key, start, end, count)); } diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index b6a990fd91..901d19a6de 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -4275,16 +4275,12 @@ export function runBaseTests(config: { const streamId3 = "0-3"; expect( - await client.xadd( - key, [["f1", "v1"]], {id: streamId1} - ) + await client.xadd(key, [["f1", "v1"]], { id: streamId1 }), ).toEqual(streamId1); expect( - await client.xadd( - key, [["f2", "v2"]], {id: streamId2} - ) + await client.xadd(key, [["f2", "v2"]], { id: streamId2 }), ).toEqual(streamId2); - expect(await client.xlen(key)).toEqual(2) + expect(await client.xlen(key)).toEqual(2); // get everything from the stream expect(await client.xrange(key, "-", "+")).toEqual({ @@ -4293,24 +4289,37 @@ export function runBaseTests(config: { }); // returns empty mapping if + before - - expect(await client.xrange(key, "+", "-")).toEqual({}) + expect(await client.xrange(key, "+", "-")).toEqual({}); expect( - await client.xadd( - key, [["f3", "v3"]], {id: streamId3} - ) + await client.xadd(key, [["f3", "v3"]], { id: streamId3 }), ).toEqual(streamId3); // get the newest entry - expect(await client.xrange( - key, {exclusive: "(", id: streamId2}, {id: 5}, 1 - )).toEqual({streamId3: [["f3", "v3"]]}); + expect( + await client.xrange( + key, + { exclusive: "(", id: streamId2 }, + { id: 5 }, + 1, + ), + ).toEqual({ streamId3: [["f3", "v3"]] }); // xrange against an emptied stream - expect(await client.customCommand(["XDEL", key, streamId1, streamId2, streamId3])).toEqual(3); + expect( + await client.customCommand([ + "XDEL", + key, + streamId1, + streamId2, + streamId3, + ]), + ).toEqual(3); expect(await client.xrange(key, "-", "+", 10)).toEqual({}); - expect(await client.xrange(nonExistingKey, "-", "+")).toEqual({}); + expect(await client.xrange(nonExistingKey, "-", "+")).toEqual( + {}, + ); // count value < 1 returns null expect(await client.xrange(key, "-", "+", 0)).toEqual(null); @@ -4318,13 +4327,19 @@ export function runBaseTests(config: { // key exists, but it is not a stream expect(await client.set(stringKey, "foo")); - await expect(client.xrange(stringKey, "-", "+")).rejects.toThrow(RequestError); + await expect( + client.xrange(stringKey, "-", "+"), + ).rejects.toThrow(RequestError); // invalid start bound - await expect(client.xrange(key, {id: "not_a_stream_id"}, "+")).rejects.toThrow(RequestError); + await expect( + client.xrange(key, { id: "not_a_stream_id" }, "+"), + ).rejects.toThrow(RequestError); // invalid end bound - await expect(client.xrange(key, "-", {id: "not_a_stream_id"})).rejects.toThrow(RequestError); + await expect( + client.xrange(key, "-", { id: "not_a_stream_id" }), + ).rejects.toThrow(RequestError); }, protocol); }, config.timeout, diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 155b04f40b..6dfd9f2240 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -809,8 +809,8 @@ export async function transactionTest( ]); baseTransaction.xlen(key9); responseData.push(["xlen(key9)", 3]); - baseTransaction.xrange(key9, {id: "0-1"}, {id: "0-1"}); - responseData.push(["xrange(key9)", {"0-1": [["field", "value1"]]}]); + baseTransaction.xrange(key9, { id: "0-1" }, { id: "0-1" }); + responseData.push(["xrange(key9)", { "0-1": [["field", "value1"]] }]); baseTransaction.xread({ [key9]: "0-1" }); responseData.push([ 'xread({ [key9]: "0-1" })', From a412111b74880496943b055241f5a7c33e116682 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Thu, 1 Aug 2024 01:47:54 -0700 Subject: [PATCH 05/18] Fix style issue Signed-off-by: Jonathan Louie --- node/src/Commands.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 1ccfc11388..30f019c0aa 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2020,10 +2020,12 @@ export function createXRange( const args = [key]; addRangeBound(start, args); addRangeBound(end, args); + if (count !== undefined) { args.push("COUNT"); args.push(count.toString()); } + return createCommand(RequestType.XRange, args); } From 0f7bb75646a96ebc11ba6e11252b828b5168944b Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Thu, 1 Aug 2024 09:53:27 -0700 Subject: [PATCH 06/18] Fix failing test Signed-off-by: Jonathan Louie --- node/tests/SharedTests.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 901d19a6de..ea4f21c3b3 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -4284,8 +4284,8 @@ export function runBaseTests(config: { // get everything from the stream expect(await client.xrange(key, "-", "+")).toEqual({ - streamId1: [["f1", "v1"]], - streamId2: [["f2", "v2"]], + [streamId1]: [["f1", "v1"]], + [streamId2]: [["f2", "v2"]], }); // returns empty mapping if + before - From bf8235d668fb49a6a8502e6c118722ffd966ca80 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Thu, 1 Aug 2024 10:06:22 -0700 Subject: [PATCH 07/18] Fix another failing test Signed-off-by: Jonathan Louie --- node/tests/SharedTests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index ea4f21c3b3..26812bd3f5 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -4303,7 +4303,7 @@ export function runBaseTests(config: { { id: 5 }, 1, ), - ).toEqual({ streamId3: [["f3", "v3"]] }); + ).toEqual({ [streamId3]: [["f3", "v3"]] }); // xrange against an emptied stream expect( From a75827e3c50f31cac94046dd05e36cf59d292a88 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Fri, 2 Aug 2024 00:21:34 -0700 Subject: [PATCH 08/18] Address PR comments Signed-off-by: Jonathan Louie --- node/npm/glide/index.ts | 2 ++ node/src/BaseClient.ts | 8 +++++--- node/src/Commands.ts | 18 +++++++----------- node/src/Transaction.ts | 2 ++ 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/node/npm/glide/index.ts b/node/npm/glide/index.ts index f881d7c054..34066eb7a2 100644 --- a/node/npm/glide/index.ts +++ b/node/npm/glide/index.ts @@ -135,6 +135,7 @@ function initialize() { SortedSetRange, StreamTrimOptions, StreamAddOptions, + StreamRangeBound, StreamReadOptions, ScriptOptions, ClosingError, @@ -221,6 +222,7 @@ function initialize() { SortedSetRange, StreamTrimOptions, StreamAddOptions, + StreamRangeBound, StreamReadOptions, ScriptOptions, ClosingError, diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 295b6dc9db..4f9fc9d249 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -2569,10 +2569,12 @@ export class BaseClient { * * @param key - The key of the stream. * @param start - The starting stream ID bound for the range. - * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `id` to specify a stream ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream ID. * - Use `-` to start with the minimum available ID. * @param end - The ending stream ID bound for the range. - * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `id` to specify a stream ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream ID. * - Use `+` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. * If `count` is not provided, all stream entries in the range will be returned. @@ -2583,7 +2585,7 @@ export class BaseClient { * ```typescript * await client.xadd("mystream", [["field1", "value1"]], {id: "0-1"}); * await client.xadd("mystream", [["field2", "value2"], ["field2", "value3"]], {id: "0-2"}); - * const result = await client.xrange("mystream", "-", "+"); + * console.log(await client.xrange("mystream", "-", "+")); * // Output: * // { * // "0-1": [["field1", "value1"]], diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 30f019c0aa..14c9e3601d 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1991,21 +1991,19 @@ export type StreamRangeBound = * be incomplete, with just a timestamp. Can be specified as inclusive or exclusive, where inclusive is the default. */ | { - exclusive?: "("; + isInclusive?: boolean; id: string | number; }; -function addRangeBound(rangeBound: StreamRangeBound, args: string[]) { +function addRangeBound(rangeBound: StreamRangeBound): string { if (rangeBound === "-" || rangeBound === "+") { - args.push(rangeBound); - return; + return rangeBound; } - if (rangeBound.exclusive) { - args.push(rangeBound.exclusive + rangeBound.id.toString()); - } else { - args.push(rangeBound.id.toString()); + if (rangeBound.isInclusive == false) { + return "(" + rangeBound.id.toString(); } + return rangeBound.id.toString(); } /** @@ -2017,9 +2015,7 @@ export function createXRange( end: StreamRangeBound, count?: number, ): command_request.Command { - const args = [key]; - addRangeBound(start, args); - addRangeBound(end, args); + const args = [key, addRangeBound(start), addRangeBound(end)]; if (count !== undefined) { args.push("COUNT"); diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index a6174d471d..56cf43018a 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -2023,9 +2023,11 @@ export class BaseTransaction> { * * @param key - The key of the stream. * @param start - The starting stream ID bound for the range. + * - Use `id` to specify a stream ID. * - Use `exclusive: "("` to specify an exclusive bounded stream ID. * - Use `-` to start with the minimum available ID. * @param end - The ending stream ID bound for the range. + * - Use `id` to specify a stream ID. * - Use `exclusive: "("` to specify an exclusive bounded stream ID. * - Use `+` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. From 5f880c6ea60ca81a1f2520dceab7fb53c7272d65 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Fri, 2 Aug 2024 15:33:00 -0700 Subject: [PATCH 09/18] Change return type for xrange Signed-off-by: Jonathan Louie --- node/src/BaseClient.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 4f9fc9d249..13656709f7 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -2598,7 +2598,7 @@ export class BaseClient { start: StreamRangeBound, end: StreamRangeBound, count?: number, - ): Promise | null> { + ): Promise | null> { return this.createWritePromise(createXRange(key, start, end, count)); } From 08310e8a8d00e8a0a6d2007b93a0d5196ea83e76 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Fri, 2 Aug 2024 18:11:48 -0700 Subject: [PATCH 10/18] Try to address remaining PR comments Signed-off-by: Jonathan Louie --- node/npm/glide/index.ts | 1 + node/src/Commands.ts | 20 ++++++++++++-------- node/tests/SharedTests.ts | 27 ++++++++++----------------- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/node/npm/glide/index.ts b/node/npm/glide/index.ts index 34066eb7a2..c9a8f24be7 100644 --- a/node/npm/glide/index.ts +++ b/node/npm/glide/index.ts @@ -222,6 +222,7 @@ function initialize() { SortedSetRange, StreamTrimOptions, StreamAddOptions, + StreamIdBoundary, StreamRangeBound, StreamReadOptions, ScriptOptions, diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 14c9e3601d..e2c66cd499 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1974,17 +1974,21 @@ export function createXTrim( return createCommand(RequestType.XTrim, args); } -export type StreamRangeBound = - /** - * Stream ID boundary used to specify the minimum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands - * to get the first stream ID. - */ - | "-" +export enum StreamIdBoundary { /** * Stream ID boundary used to specify the maximum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands * to get the last stream ID. */ - | "+" + MaxId = "+", + /** + * Stream ID boundary used to specify the minimum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands + * to get the first stream ID. + */ + MinId = "-", +} + +export type StreamRangeBound = + | StreamIdBoundary /** * Stream ID boundary used to specify a range of IDs to search. Stream ID bounds can be complete with * a timestamp and sequence number separated by a dash ("-"), for example "1526985054069-0". Stream ID bounds can also @@ -1996,7 +2000,7 @@ export type StreamRangeBound = }; function addRangeBound(rangeBound: StreamRangeBound): string { - if (rangeBound === "-" || rangeBound === "+") { + if (rangeBound === StreamIdBoundary.MinId || rangeBound === StreamIdBoundary.MaxId) { return rangeBound; } diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 26812bd3f5..f8bde438f9 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -38,6 +38,7 @@ import { Script, SignedEncoding, SortOrder, + StreamIdBoundary, Transaction, UnsignedEncoding, UpdateByScore, @@ -4283,13 +4284,13 @@ export function runBaseTests(config: { expect(await client.xlen(key)).toEqual(2); // get everything from the stream - expect(await client.xrange(key, "-", "+")).toEqual({ + expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId)).toEqual({ [streamId1]: [["f1", "v1"]], [streamId2]: [["f2", "v2"]], }); // returns empty mapping if + before - - expect(await client.xrange(key, "+", "-")).toEqual({}); + expect(await client.xrange(key, StreamIdBoundary.MaxId, StreamIdBoundary.MinId)).toEqual({}); expect( await client.xadd(key, [["f3", "v3"]], { id: streamId3 }), @@ -4306,39 +4307,31 @@ export function runBaseTests(config: { ).toEqual({ [streamId3]: [["f3", "v3"]] }); // xrange against an emptied stream - expect( - await client.customCommand([ - "XDEL", - key, - streamId1, - streamId2, - streamId3, - ]), - ).toEqual(3); - expect(await client.xrange(key, "-", "+", 10)).toEqual({}); + expect(await client.xdel(key, [streamId1, streamId2, streamId3])).toEqual(3); + expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId, 10)).toEqual({}); expect(await client.xrange(nonExistingKey, "-", "+")).toEqual( {}, ); // count value < 1 returns null - expect(await client.xrange(key, "-", "+", 0)).toEqual(null); - expect(await client.xrange(key, "-", "+", -1)).toEqual(null); + expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId, 0)).toEqual(null); + expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId, -1)).toEqual(null); // key exists, but it is not a stream expect(await client.set(stringKey, "foo")); await expect( - client.xrange(stringKey, "-", "+"), + client.xrange(stringKey, StreamIdBoundary.MinId, StreamIdBoundary.MaxId), ).rejects.toThrow(RequestError); // invalid start bound await expect( - client.xrange(key, { id: "not_a_stream_id" }, "+"), + client.xrange(key, { id: "not_a_stream_id" }, StreamIdBoundary.MaxId), ).rejects.toThrow(RequestError); // invalid end bound await expect( - client.xrange(key, "-", { id: "not_a_stream_id" }), + client.xrange(key, StreamIdBoundary.MinId, { id: "not_a_stream_id" }), ).rejects.toThrow(RequestError); }, protocol); }, From a57f029c9d88ecf4211b056772d0492bcd2aa4e3 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Mon, 12 Aug 2024 14:54:21 -0700 Subject: [PATCH 11/18] Switch to ScoreBoundary Signed-off-by: Jonathan Louie --- node/src/BaseClient.ts | 1 - node/src/Commands.ts | 42 +++---------------------------------- node/src/Transaction.ts | 1 - node/tests/SharedTests.ts | 23 ++++++++++---------- node/tests/TestUtilities.ts | 2 +- 5 files changed, 15 insertions(+), 54 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index b92ffdb7f3..a9a85b32e2 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -49,7 +49,6 @@ import { StreamClaimOptions, StreamGroupOptions, StreamPendingOptions, - StreamRangeBound, StreamReadOptions, StreamTrimOptions, ZAddOptions, diff --git a/node/src/Commands.ts b/node/src/Commands.ts index c42af3f0a1..c9cb75f478 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2065,52 +2065,16 @@ export function createXTrim( return createCommand(RequestType.XTrim, args); } -export enum StreamIdBoundary { - /** - * Stream ID boundary used to specify the maximum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands - * to get the last stream ID. - */ - MaxId = "+", - /** - * Stream ID boundary used to specify the minimum stream entry ID. Can be used in the `XRANGE` or `XREVRANGE` commands - * to get the first stream ID. - */ - MinId = "-", -} - -export type StreamRangeBound = - | StreamIdBoundary - /** - * Stream ID boundary used to specify a range of IDs to search. Stream ID bounds can be complete with - * a timestamp and sequence number separated by a dash ("-"), for example "1526985054069-0". Stream ID bounds can also - * be incomplete, with just a timestamp. Can be specified as inclusive or exclusive, where inclusive is the default. - */ - | { - isInclusive?: boolean; - id: string | number; - }; - -function addRangeBound(rangeBound: StreamRangeBound): string { - if (rangeBound === StreamIdBoundary.MinId || rangeBound === StreamIdBoundary.MaxId) { - return rangeBound; - } - - if (rangeBound.isInclusive == false) { - return "(" + rangeBound.id.toString(); - } - return rangeBound.id.toString(); -} - /** * @internal */ export function createXRange( key: string, - start: StreamRangeBound, - end: StreamRangeBound, + start: ScoreBoundary, + end: ScoreBoundary, count?: number, ): command_request.Command { - const args = [key, addRangeBound(start), addRangeBound(end)]; + const args = [key, getStreamBoundaryArg(start), getStreamBoundaryArg(end)]; if (count !== undefined) { args.push("COUNT"); diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index fd80974c9f..401b8a9c37 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -55,7 +55,6 @@ import { StreamClaimOptions, StreamGroupOptions, StreamPendingOptions, - StreamRangeBound, StreamReadOptions, StreamTrimOptions, ZAddOptions, diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 4295d6f7f7..5c0d02ca1d 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -38,7 +38,6 @@ import { Script, SignedEncoding, SortOrder, - StreamIdBoundary, Transaction, UnsignedEncoding, UpdateByScore, @@ -4774,13 +4773,13 @@ export function runBaseTests(config: { expect(await client.xlen(key)).toEqual(2); // get everything from the stream - expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId)).toEqual({ + expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity)).toEqual({ [streamId1]: [["f1", "v1"]], [streamId2]: [["f2", "v2"]], }); // returns empty mapping if + before - - expect(await client.xrange(key, StreamIdBoundary.MaxId, StreamIdBoundary.MinId)).toEqual({}); + expect(await client.xrange(key, InfScoreBoundary.PositiveInfinity, InfScoreBoundary.NegativeInfinity)).toEqual({}); expect( await client.xadd(key, [["f3", "v3"]], { id: streamId3 }), @@ -4790,38 +4789,38 @@ export function runBaseTests(config: { expect( await client.xrange( key, - { exclusive: "(", id: streamId2 }, - { id: 5 }, + { isInclusive: false, value: streamId2 }, + { value: 5 }, 1, ), ).toEqual({ [streamId3]: [["f3", "v3"]] }); // xrange against an emptied stream expect(await client.xdel(key, [streamId1, streamId2, streamId3])).toEqual(3); - expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId, 10)).toEqual({}); + expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity, 10)).toEqual({}); - expect(await client.xrange(nonExistingKey, "-", "+")).toEqual( + expect(await client.xrange(nonExistingKey, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity)).toEqual( {}, ); // count value < 1 returns null - expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId, 0)).toEqual(null); - expect(await client.xrange(key, StreamIdBoundary.MinId, StreamIdBoundary.MaxId, -1)).toEqual(null); + expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity, 0)).toEqual(null); + expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity, -1)).toEqual(null); // key exists, but it is not a stream expect(await client.set(stringKey, "foo")); await expect( - client.xrange(stringKey, StreamIdBoundary.MinId, StreamIdBoundary.MaxId), + client.xrange(stringKey, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity), ).rejects.toThrow(RequestError); // invalid start bound await expect( - client.xrange(key, { id: "not_a_stream_id" }, StreamIdBoundary.MaxId), + client.xrange(key, { value: "not_a_stream_id" }, InfScoreBoundary.PositiveInfinity), ).rejects.toThrow(RequestError); // invalid end bound await expect( - client.xrange(key, StreamIdBoundary.MinId, { id: "not_a_stream_id" }), + client.xrange(key, InfScoreBoundary.NegativeInfinity, { value: "not_a_stream_id" }), ).rejects.toThrow(RequestError); }, protocol); }, diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 058433b434..e964cd9400 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -932,7 +932,7 @@ export async function transactionTest( ]); baseTransaction.xlen(key9); responseData.push(["xlen(key9)", 3]); - baseTransaction.xrange(key9, { id: "0-1" }, { id: "0-1" }); + baseTransaction.xrange(key9, { value: "0-1" }, { value: "0-1" }); responseData.push(["xrange(key9)", { "0-1": [["field", "value1"]] }]); baseTransaction.xread({ [key9]: "0-1" }); responseData.push([ From de74df9b9281a5fba43fb900d9bb56585cb25bf3 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Mon, 12 Aug 2024 15:22:13 -0700 Subject: [PATCH 12/18] Remove merge conflict marker Signed-off-by: Jonathan Louie --- node/npm/glide/index.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/node/npm/glide/index.ts b/node/npm/glide/index.ts index bcfbb6efc6..a4686e774b 100644 --- a/node/npm/glide/index.ts +++ b/node/npm/glide/index.ts @@ -138,7 +138,6 @@ function initialize() { StreamGroupOptions, StreamTrimOptions, StreamAddOptions, - StreamRangeBound, StreamReadOptions, StreamClaimOptions, StreamPendingOptions, @@ -234,12 +233,7 @@ function initialize() { StreamGroupOptions, StreamTrimOptions, StreamAddOptions, -<<<<<<< HEAD - StreamIdBoundary, - StreamRangeBound, -======= StreamClaimOptions, ->>>>>>> main StreamReadOptions, StreamPendingOptions, ScriptOptions, From beab6f5b62757b311a135e9de30b69a86176036e Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Mon, 12 Aug 2024 15:31:13 -0700 Subject: [PATCH 13/18] Apply prettier for SharedTests Signed-off-by: Jonathan Louie --- node/tests/SharedTests.ts | 73 ++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 5c0d02ca1d..0dec1d6a22 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -4773,13 +4773,25 @@ export function runBaseTests(config: { expect(await client.xlen(key)).toEqual(2); // get everything from the stream - expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity)).toEqual({ + expect( + await client.xrange( + key, + InfScoreBoundary.NegativeInfinity, + InfScoreBoundary.PositiveInfinity, + ), + ).toEqual({ [streamId1]: [["f1", "v1"]], [streamId2]: [["f2", "v2"]], }); // returns empty mapping if + before - - expect(await client.xrange(key, InfScoreBoundary.PositiveInfinity, InfScoreBoundary.NegativeInfinity)).toEqual({}); + expect( + await client.xrange( + key, + InfScoreBoundary.PositiveInfinity, + InfScoreBoundary.NegativeInfinity, + ), + ).toEqual({}); expect( await client.xadd(key, [["f3", "v3"]], { id: streamId3 }), @@ -4796,31 +4808,68 @@ export function runBaseTests(config: { ).toEqual({ [streamId3]: [["f3", "v3"]] }); // xrange against an emptied stream - expect(await client.xdel(key, [streamId1, streamId2, streamId3])).toEqual(3); - expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity, 10)).toEqual({}); + expect( + await client.xdel(key, [streamId1, streamId2, streamId3]), + ).toEqual(3); + expect( + await client.xrange( + key, + InfScoreBoundary.NegativeInfinity, + InfScoreBoundary.PositiveInfinity, + 10, + ), + ).toEqual({}); - expect(await client.xrange(nonExistingKey, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity)).toEqual( - {}, - ); + expect( + await client.xrange( + nonExistingKey, + InfScoreBoundary.NegativeInfinity, + InfScoreBoundary.PositiveInfinity, + ), + ).toEqual({}); // count value < 1 returns null - expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity, 0)).toEqual(null); - expect(await client.xrange(key, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity, -1)).toEqual(null); + expect( + await client.xrange( + key, + InfScoreBoundary.NegativeInfinity, + InfScoreBoundary.PositiveInfinity, + 0, + ), + ).toEqual(null); + expect( + await client.xrange( + key, + InfScoreBoundary.NegativeInfinity, + InfScoreBoundary.PositiveInfinity, + -1, + ), + ).toEqual(null); // key exists, but it is not a stream expect(await client.set(stringKey, "foo")); await expect( - client.xrange(stringKey, InfScoreBoundary.NegativeInfinity, InfScoreBoundary.PositiveInfinity), + client.xrange( + stringKey, + InfScoreBoundary.NegativeInfinity, + InfScoreBoundary.PositiveInfinity, + ), ).rejects.toThrow(RequestError); // invalid start bound await expect( - client.xrange(key, { value: "not_a_stream_id" }, InfScoreBoundary.PositiveInfinity), + client.xrange( + key, + { value: "not_a_stream_id" }, + InfScoreBoundary.PositiveInfinity, + ), ).rejects.toThrow(RequestError); // invalid end bound await expect( - client.xrange(key, InfScoreBoundary.NegativeInfinity, { value: "not_a_stream_id" }), + client.xrange(key, InfScoreBoundary.NegativeInfinity, { + value: "not_a_stream_id", + }), ).rejects.toThrow(RequestError); }, protocol); }, From 84f0593a672f0263c8fa25e04c475b6e92ffc09c Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Mon, 12 Aug 2024 15:57:11 -0700 Subject: [PATCH 14/18] Replace remaining instances of StreamRangeBound with ScoreBoundary Signed-off-by: Jonathan Louie --- node/src/BaseClient.ts | 8 ++++---- node/src/Transaction.ts | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index a9a85b32e2..9b9ec497a8 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -2826,11 +2826,11 @@ export class BaseClient { * * @param key - The key of the stream. * @param start - The starting stream ID bound for the range. - * - Use `id` to specify a stream ID. + * - Use `value` to specify a stream ID. * - Use `isInclusive: false` to specify an exclusive bounded stream ID. * - Use `-` to start with the minimum available ID. * @param end - The ending stream ID bound for the range. - * - Use `id` to specify a stream ID. + * - Use `value` to specify a stream ID. * - Use `isInclusive: false` to specify an exclusive bounded stream ID. * - Use `+` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. @@ -2852,8 +2852,8 @@ export class BaseClient { */ public async xrange( key: string, - start: StreamRangeBound, - end: StreamRangeBound, + start: ScoreBoundary, + end: ScoreBoundary, count?: number, ): Promise | null> { return this.createWritePromise(createXRange(key, start, end, count)); diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 401b8a9c37..6c888365b8 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -2292,12 +2292,12 @@ export class BaseTransaction> { * * @param key - The key of the stream. * @param start - The starting stream ID bound for the range. - * - Use `id` to specify a stream ID. - * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `value` to specify a stream ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream ID. * - Use `-` to start with the minimum available ID. * @param end - The ending stream ID bound for the range. - * - Use `id` to specify a stream ID. - * - Use `exclusive: "("` to specify an exclusive bounded stream ID. + * - Use `value` to specify a stream ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream ID. * - Use `+` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. * If `count` is not provided, all stream entries in the range will be returned. @@ -2307,8 +2307,8 @@ export class BaseTransaction> { */ public xrange( key: string, - start: StreamRangeBound, - end: StreamRangeBound, + start: ScoreBoundary, + end: ScoreBoundary, count?: number, ): T { return this.addAndReturn(createXRange(key, start, end, count)); From d8ec960a6f02c67dc734b90e9e98303a9a1ed583 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Mon, 12 Aug 2024 16:25:55 -0700 Subject: [PATCH 15/18] Update test to use string instead of number Signed-off-by: Jonathan Louie --- node/tests/SharedTests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 0dec1d6a22..dd3e123fe0 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -4802,7 +4802,7 @@ export function runBaseTests(config: { await client.xrange( key, { isInclusive: false, value: streamId2 }, - { value: 5 }, + { value: "5" }, 1, ), ).toEqual({ [streamId3]: [["f3", "v3"]] }); From 7fe560f1117827d9b24eae1b76604274e172a87b Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Tue, 13 Aug 2024 16:23:59 -0700 Subject: [PATCH 16/18] Change ScoreBoundary to generic Boundary and add check for Redis version to xrange tests Signed-off-by: Jonathan Louie --- node/npm/glide/index.ts | 8 +- node/src/BaseClient.ts | 38 ++++----- node/src/Commands.ts | 70 +++++++-------- node/src/Transaction.ts | 22 ++--- node/tests/SharedTests.ts | 164 ++++++++++++++++++------------------ node/tests/TestUtilities.ts | 22 ++--- 6 files changed, 163 insertions(+), 161 deletions(-) diff --git a/node/npm/glide/index.ts b/node/npm/glide/index.ts index a4686e774b..c3ea68d794 100644 --- a/node/npm/glide/index.ts +++ b/node/npm/glide/index.ts @@ -123,8 +123,8 @@ function initialize() { InsertPosition, SetOptions, ZaddOptions, - InfScoreBoundary, - ScoreBoundary, + InfBoundary, + Boundary, UpdateOptions, ProtocolVersion, RangeByIndex, @@ -218,8 +218,8 @@ function initialize() { InsertPosition, SetOptions, ZaddOptions, - InfScoreBoundary, - ScoreBoundary, + InfBoundary, + Boundary, UpdateOptions, ProtocolVersion, RangeByIndex, diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 9b9ec497a8..6d2c71a0d4 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -22,6 +22,7 @@ import { BitOffsetOptions, BitmapIndexType, BitwiseOperation, + Boundary, CoordOrigin, // eslint-disable-line @typescript-eslint/no-unused-vars ExpireOptions, GeoAddOptions, @@ -41,7 +42,6 @@ import { RangeByLex, RangeByScore, ReturnTypeXinfoStream, - ScoreBoundary, ScoreFilter, SearchOrigin, SetOptions, @@ -2852,8 +2852,8 @@ export class BaseClient { */ public async xrange( key: string, - start: ScoreBoundary, - end: ScoreBoundary, + start: Boundary, + end: Boundary, count?: number, ): Promise | null> { return this.createWritePromise(createXRange(key, start, end, count)); @@ -3156,7 +3156,7 @@ export class BaseClient { * @example * ```typescript * // Example usage of the zcount method to count members in a sorted set within a score range - * const result = await client.zcount("my_sorted_set", { value: 5.0, isInclusive: true }, InfScoreBoundary.PositiveInfinity); + * const result = await client.zcount("my_sorted_set", { value: 5.0, isInclusive: true }, InfBoundary.PositiveInfinity); * console.log(result); // Output: 2 - Indicates that there are 2 members with scores between 5.0 (inclusive) and +inf in the sorted set "my_sorted_set". * ``` * @@ -3169,8 +3169,8 @@ export class BaseClient { */ public zcount( key: string, - minScore: ScoreBoundary, - maxScore: ScoreBoundary, + minScore: Boundary, + maxScore: Boundary, ): Promise { return this.createWritePromise(createZCount(key, minScore, maxScore)); } @@ -3200,7 +3200,7 @@ export class BaseClient { * ```typescript * // Example usage of zrange method to retrieve members within a score range in ascending order * const result = await client.zrange("my_sorted_set", { - * start: InfScoreBoundary.NegativeInfinity, + * start: InfBoundary.NegativeInfinity, * stop: { value: 3, isInclusive: false }, * type: "byScore", * }); @@ -3242,7 +3242,7 @@ export class BaseClient { * ```typescript * // Example usage of zrangeWithScores method to retrieve members within a score range with their scores * const result = await client.zrangeWithScores("my_sorted_set", { - * start: InfScoreBoundary.NegativeInfinity, + * start: InfBoundary.NegativeInfinity, * stop: { value: 3, isInclusive: false }, * type: "byScore", * }); @@ -3288,7 +3288,7 @@ export class BaseClient { * ```typescript * // Example usage of zrangeStore method to retrieve members within a score range in ascending order and store in "destination_key" * const result = await client.zrangeStore("destination_key", "my_sorted_set", { - * start: InfScoreBoundary.NegativeInfinity, + * start: InfBoundary.NegativeInfinity, * stop: { value: 3, isInclusive: false }, * type: "byScore", * }); @@ -3684,14 +3684,14 @@ export class BaseClient { * @example * ```typescript * // Example usage of zremRangeByLex method when the sorted set does not exist - * const result = await client.zremRangeByLex("non_existing_sorted_set", InfScoreBoundary.NegativeInfinity, { value: "e" }); + * const result = await client.zremRangeByLex("non_existing_sorted_set", InfBoundary.NegativeInfinity, { value: "e" }); * console.log(result); // Output: 0 - Indicates that no elements were removed. * ``` */ public zremRangeByLex( key: string, - minLex: ScoreBoundary, - maxLex: ScoreBoundary, + minLex: Boundary, + maxLex: Boundary, ): Promise { return this.createWritePromise( createZRemRangeByLex(key, minLex, maxLex), @@ -3711,7 +3711,7 @@ export class BaseClient { * @example * ```typescript * // Example usage of zremRangeByScore method to remove members from a sorted set based on score range - * const result = await client.zremRangeByScore("my_sorted_set", { value: 5.0, isInclusive: true }, InfScoreBoundary.PositiveInfinity); + * const result = await client.zremRangeByScore("my_sorted_set", { value: 5.0, isInclusive: true }, InfBoundary.PositiveInfinity); * console.log(result); // Output: 2 - Indicates that 2 members with scores between 5.0 (inclusive) and +inf have been removed from the sorted set "my_sorted_set". * ``` * @@ -3724,8 +3724,8 @@ export class BaseClient { */ public zremRangeByScore( key: string, - minScore: ScoreBoundary, - maxScore: ScoreBoundary, + minScore: Boundary, + maxScore: Boundary, ): Promise { return this.createWritePromise( createZRemRangeByScore(key, minScore, maxScore), @@ -3746,7 +3746,7 @@ export class BaseClient { * * @example * ```typescript - * const result = await client.zlexcount("my_sorted_set", {value: "c"}, InfScoreBoundary.PositiveInfinity); + * const result = await client.zlexcount("my_sorted_set", {value: "c"}, InfBoundary.PositiveInfinity); * console.log(result); // Output: 2 - Indicates that there are 2 members with lex scores between "c" (inclusive) and positive infinity in the sorted set "my_sorted_set". * ``` * @@ -3758,8 +3758,8 @@ export class BaseClient { */ public async zlexcount( key: string, - minLex: ScoreBoundary, - maxLex: ScoreBoundary, + minLex: Boundary, + maxLex: Boundary, ): Promise { return this.createWritePromise(createZLexCount(key, minLex, maxLex)); } @@ -4011,7 +4011,7 @@ export class BaseClient { * ```typescript * console.log(await client.xpending("my_stream", "my_group"), { * start: { value: "0-1", isInclusive: true }, - * end: InfScoreBoundary.PositiveInfinity, + * end: InfBoundary.PositiveInfinity, * count: 2, * consumer: "consumer1" * }); // Output: diff --git a/node/src/Commands.ts b/node/src/Commands.ts index c9cb75f478..84f04e3401 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1543,35 +1543,35 @@ export function createZMScore( return createCommand(RequestType.ZMScore, [key, ...members]); } -export enum InfScoreBoundary { +export enum InfBoundary { /** - * Positive infinity bound for sorted set. + * Positive infinity bound. */ PositiveInfinity = "+", /** - * Negative infinity bound for sorted set. + * Negative infinity bound. */ NegativeInfinity = "-", } /** - * Defines where to insert new elements into a list. + * Defines the boundaries of a range. */ -export type ScoreBoundary = +export type Boundary = /** - * Represents an lower/upper boundary in a sorted set. + * Represents an lower/upper boundary. */ - | InfScoreBoundary + | InfBoundary /** - * Represents a specific numeric score boundary in a sorted set. + * Represents a specific boundary. */ | { /** - * The score value. + * The comparison value. */ value: T; /** - * Whether the score value is inclusive. Defaults to True. + * Whether the value is inclusive. Defaults to `true`. */ isInclusive?: boolean; }; @@ -1599,11 +1599,11 @@ type SortedSetRange = { /** * The start boundary. */ - start: ScoreBoundary; + start: Boundary; /** * The stop boundary. */ - stop: ScoreBoundary; + stop: Boundary; /** * The limit argument for a range query. * Represents a limit argument for a range query in a sorted set to @@ -1630,10 +1630,10 @@ export type RangeByLex = SortedSetRange & { type: "byLex" }; /** Returns a string representation of a score boundary as a command argument. */ function getScoreBoundaryArg( - score: ScoreBoundary | ScoreBoundary, + score: Boundary | Boundary, ): string { if (typeof score === "string") { - // InfScoreBoundary + // InfBoundary return score + "inf"; } @@ -1646,10 +1646,10 @@ function getScoreBoundaryArg( /** Returns a string representation of a lex boundary as a command argument. */ function getLexBoundaryArg( - score: ScoreBoundary | ScoreBoundary, + score: Boundary | Boundary, ): string { if (typeof score === "string") { - // InfScoreBoundary + // InfBoundary return score; } @@ -1662,18 +1662,18 @@ function getLexBoundaryArg( /** Returns a string representation of a stream boundary as a command argument. */ function getStreamBoundaryArg( - score: ScoreBoundary | ScoreBoundary, + boundary: Boundary | Boundary, ): string { - if (typeof score === "string") { - // InfScoreBoundary - return score; + if (typeof boundary === "string") { + // InfBoundary + return boundary; } - if (score.isInclusive == false) { - return "(" + score.value.toString(); + if (boundary.isInclusive == false) { + return "(" + boundary.value.toString(); } - return score.value.toString(); + return boundary.value.toString(); } function createZRangeArgs( @@ -1729,8 +1729,8 @@ function createZRangeArgs( */ export function createZCount( key: string, - minScore: ScoreBoundary, - maxScore: ScoreBoundary, + minScore: Boundary, + maxScore: Boundary, ): command_request.Command { const args = [ key, @@ -1886,8 +1886,8 @@ export function createZRemRangeByRank( */ export function createZRemRangeByLex( key: string, - minLex: ScoreBoundary, - maxLex: ScoreBoundary, + minLex: Boundary, + maxLex: Boundary, ): command_request.Command { const args = [key, getLexBoundaryArg(minLex), getLexBoundaryArg(maxLex)]; return createCommand(RequestType.ZRemRangeByLex, args); @@ -1898,8 +1898,8 @@ export function createZRemRangeByLex( */ export function createZRemRangeByScore( key: string, - minScore: ScoreBoundary, - maxScore: ScoreBoundary, + minScore: Boundary, + maxScore: Boundary, ): command_request.Command { const args = [ key, @@ -1919,8 +1919,8 @@ export function createPersist(key: string): command_request.Command { */ export function createZLexCount( key: string, - minLex: ScoreBoundary, - maxLex: ScoreBoundary, + minLex: Boundary, + maxLex: Boundary, ): command_request.Command { const args = [key, getLexBoundaryArg(minLex), getLexBoundaryArg(maxLex)]; return createCommand(RequestType.ZLexCount, args); @@ -2070,8 +2070,8 @@ export function createXTrim( */ export function createXRange( key: string, - start: ScoreBoundary, - end: ScoreBoundary, + start: Boundary, + end: Boundary, count?: number, ): command_request.Command { const args = [key, getStreamBoundaryArg(start), getStreamBoundaryArg(end)]; @@ -2463,9 +2463,9 @@ export type StreamPendingOptions = { /** Filter pending entries by their idle time - in milliseconds */ minIdleTime?: number; /** Starting stream ID bound for range. */ - start: ScoreBoundary; + start: Boundary; /** Ending stream ID bound for range. */ - end: ScoreBoundary; + end: Boundary; /** Limit the number of messages returned. */ count: number; /** Filter pending entries by consumer. */ diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 6c888365b8..d4c345bdf1 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -20,6 +20,7 @@ import { BitOffsetOptions, BitmapIndexType, BitwiseOperation, + Boundary, CoordOrigin, // eslint-disable-line @typescript-eslint/no-unused-vars ExpireOptions, FlushMode, @@ -45,7 +46,6 @@ import { RangeByLex, RangeByScore, ReturnTypeXinfoStream, // eslint-disable-line @typescript-eslint/no-unused-vars - ScoreBoundary, ScoreFilter, SearchOrigin, SetOptions, @@ -1734,8 +1734,8 @@ export class BaseTransaction> { */ public zcount( key: string, - minScore: ScoreBoundary, - maxScore: ScoreBoundary, + minScore: Boundary, + maxScore: Boundary, ): T { return this.addAndReturn(createZCount(key, minScore, maxScore)); } @@ -2037,8 +2037,8 @@ export class BaseTransaction> { */ public zremRangeByLex( key: string, - minLex: ScoreBoundary, - maxLex: ScoreBoundary, + minLex: Boundary, + maxLex: Boundary, ): T { return this.addAndReturn(createZRemRangeByLex(key, minLex, maxLex)); } @@ -2056,8 +2056,8 @@ export class BaseTransaction> { */ public zremRangeByScore( key: string, - minScore: ScoreBoundary, - maxScore: ScoreBoundary, + minScore: Boundary, + maxScore: Boundary, ): T { return this.addAndReturn( createZRemRangeByScore(key, minScore, maxScore), @@ -2079,8 +2079,8 @@ export class BaseTransaction> { */ public zlexcount( key: string, - minLex: ScoreBoundary, - maxLex: ScoreBoundary, + minLex: Boundary, + maxLex: Boundary, ): T { return this.addAndReturn(createZLexCount(key, minLex, maxLex)); } @@ -2307,8 +2307,8 @@ export class BaseTransaction> { */ public xrange( key: string, - start: ScoreBoundary, - end: ScoreBoundary, + start: Boundary, + end: Boundary, count?: number, ): T { return this.addAndReturn(createXRange(key, start, end, count)); diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index dd3e123fe0..6caf2a4d11 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -28,7 +28,7 @@ import { GeospatialData, GlideClient, GlideClusterClient, - InfScoreBoundary, + InfBoundary, InfoOptions, InsertPosition, ListDirection, @@ -3453,8 +3453,8 @@ export function runBaseTests(config: { expect( await client.zcount( key1, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(3); expect( @@ -3474,7 +3474,7 @@ export function runBaseTests(config: { expect( await client.zcount( key1, - InfScoreBoundary.NegativeInfinity, + InfBoundary.NegativeInfinity, { value: 3, }, @@ -3483,7 +3483,7 @@ export function runBaseTests(config: { expect( await client.zcount( key1, - InfScoreBoundary.PositiveInfinity, + InfBoundary.PositiveInfinity, { value: 3, }, @@ -3492,8 +3492,8 @@ export function runBaseTests(config: { expect( await client.zcount( "nonExistingKey", - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(0); @@ -3501,8 +3501,8 @@ export function runBaseTests(config: { await expect( client.zcount( key2, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).rejects.toThrow(); }, protocol); @@ -3557,14 +3557,14 @@ export function runBaseTests(config: { expect( await client.zrange(key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }), ).toEqual(["one", "two"]); const result = await client.zrangeWithScores(key, { - start: InfScoreBoundary.NegativeInfinity, - stop: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.NegativeInfinity, + stop: InfBoundary.PositiveInfinity, type: "byScore", }); @@ -3580,7 +3580,7 @@ export function runBaseTests(config: { key, { start: { value: 3, isInclusive: false }, - stop: InfScoreBoundary.NegativeInfinity, + stop: InfBoundary.NegativeInfinity, type: "byScore", }, true, @@ -3589,8 +3589,8 @@ export function runBaseTests(config: { expect( await client.zrange(key, { - start: InfScoreBoundary.NegativeInfinity, - stop: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.NegativeInfinity, + stop: InfBoundary.PositiveInfinity, limit: { offset: 1, count: 2 }, type: "byScore", }), @@ -3600,7 +3600,7 @@ export function runBaseTests(config: { await client.zrange( key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }, @@ -3610,7 +3610,7 @@ export function runBaseTests(config: { expect( await client.zrange(key, { - start: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.PositiveInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }), @@ -3620,7 +3620,7 @@ export function runBaseTests(config: { await client.zrangeWithScores( key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }, @@ -3630,7 +3630,7 @@ export function runBaseTests(config: { expect( await client.zrangeWithScores(key, { - start: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.PositiveInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }), @@ -3650,7 +3650,7 @@ export function runBaseTests(config: { expect( await client.zrange(key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: "c", isInclusive: false }, type: "byLex", }), @@ -3658,8 +3658,8 @@ export function runBaseTests(config: { expect( await client.zrange(key, { - start: InfScoreBoundary.NegativeInfinity, - stop: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.NegativeInfinity, + stop: InfBoundary.PositiveInfinity, limit: { offset: 1, count: 2 }, type: "byLex", }), @@ -3670,7 +3670,7 @@ export function runBaseTests(config: { key, { start: { value: "c", isInclusive: false }, - stop: InfScoreBoundary.NegativeInfinity, + stop: InfBoundary.NegativeInfinity, type: "byLex", }, true, @@ -3681,7 +3681,7 @@ export function runBaseTests(config: { await client.zrange( key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: "c", isInclusive: false }, type: "byLex", }, @@ -3691,7 +3691,7 @@ export function runBaseTests(config: { expect( await client.zrange(key, { - start: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.PositiveInfinity, stop: { value: "c", isInclusive: false }, type: "byLex", }), @@ -3767,7 +3767,7 @@ export function runBaseTests(config: { expect( await client.zrangeStore(destkey, key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }), @@ -3785,7 +3785,7 @@ export function runBaseTests(config: { key, { start: { value: 3, isInclusive: false }, - stop: InfScoreBoundary.NegativeInfinity, + stop: InfBoundary.NegativeInfinity, type: "byScore", }, true, @@ -3804,8 +3804,8 @@ export function runBaseTests(config: { expect( await client.zrangeStore(destkey, key, { - start: InfScoreBoundary.NegativeInfinity, - stop: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.NegativeInfinity, + stop: InfBoundary.PositiveInfinity, limit: { offset: 1, count: 2 }, type: "byScore", }), @@ -3822,7 +3822,7 @@ export function runBaseTests(config: { destkey, key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }, @@ -3832,7 +3832,7 @@ export function runBaseTests(config: { expect( await client.zrangeStore(destkey, key, { - start: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.PositiveInfinity, stop: { value: 3, isInclusive: false }, type: "byScore", }), @@ -3854,7 +3854,7 @@ export function runBaseTests(config: { expect( await client.zrangeStore(destkey, key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: "c", isInclusive: false }, type: "byLex", }), @@ -3868,8 +3868,8 @@ export function runBaseTests(config: { expect( await client.zrangeStore(destkey, key, { - start: InfScoreBoundary.NegativeInfinity, - stop: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.NegativeInfinity, + stop: InfBoundary.PositiveInfinity, limit: { offset: 1, count: 2 }, type: "byLex", }), @@ -3887,7 +3887,7 @@ export function runBaseTests(config: { key, { start: { value: "c", isInclusive: false }, - stop: InfScoreBoundary.NegativeInfinity, + stop: InfBoundary.NegativeInfinity, type: "byLex", }, true, @@ -3909,7 +3909,7 @@ export function runBaseTests(config: { destkey, key, { - start: InfScoreBoundary.NegativeInfinity, + start: InfBoundary.NegativeInfinity, stop: { value: "c", isInclusive: false }, type: "byLex", }, @@ -3919,7 +3919,7 @@ export function runBaseTests(config: { expect( await client.zrangeStore(destkey, key, { - start: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.PositiveInfinity, stop: { value: "c", isInclusive: false }, type: "byLex", }), @@ -4776,8 +4776,8 @@ export function runBaseTests(config: { expect( await client.xrange( key, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual({ [streamId1]: [["f1", "v1"]], @@ -4788,8 +4788,8 @@ export function runBaseTests(config: { expect( await client.xrange( key, - InfScoreBoundary.PositiveInfinity, - InfScoreBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, ), ).toEqual({}); @@ -4798,14 +4798,16 @@ export function runBaseTests(config: { ).toEqual(streamId3); // get the newest entry - expect( - await client.xrange( - key, - { isInclusive: false, value: streamId2 }, - { value: "5" }, - 1, - ), - ).toEqual({ [streamId3]: [["f3", "v3"]] }); + if (!client.checkIfServerVersionLessThan("6.2.0")) { + expect( + await client.xrange( + key, + { isInclusive: false, value: streamId2 }, + { value: "5" }, + 1, + ), + ).toEqual({ [streamId3]: [["f3", "v3"]] }); + } // xrange against an emptied stream expect( @@ -4814,8 +4816,8 @@ export function runBaseTests(config: { expect( await client.xrange( key, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, 10, ), ).toEqual({}); @@ -4823,8 +4825,8 @@ export function runBaseTests(config: { expect( await client.xrange( nonExistingKey, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual({}); @@ -4832,16 +4834,16 @@ export function runBaseTests(config: { expect( await client.xrange( key, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, 0, ), ).toEqual(null); expect( await client.xrange( key, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, -1, ), ).toEqual(null); @@ -4851,8 +4853,8 @@ export function runBaseTests(config: { await expect( client.xrange( stringKey, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).rejects.toThrow(RequestError); @@ -4861,13 +4863,13 @@ export function runBaseTests(config: { client.xrange( key, { value: "not_a_stream_id" }, - InfScoreBoundary.PositiveInfinity, + InfBoundary.PositiveInfinity, ), ).rejects.toThrow(RequestError); // invalid end bound await expect( - client.xrange(key, InfScoreBoundary.NegativeInfinity, { + client.xrange(key, InfBoundary.NegativeInfinity, { value: "not_a_stream_id", }), ).rejects.toThrow(RequestError); @@ -4897,7 +4899,7 @@ export function runBaseTests(config: { await client.zremRangeByLex( key, { value: "d" }, - InfScoreBoundary.PositiveInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(1); @@ -4906,15 +4908,15 @@ export function runBaseTests(config: { await client.zremRangeByLex( key, { value: "a" }, - InfScoreBoundary.NegativeInfinity, + InfBoundary.NegativeInfinity, ), ).toEqual(0); expect( await client.zremRangeByLex( "nonExistingKey", - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(0); @@ -4923,8 +4925,8 @@ export function runBaseTests(config: { await expect( client.zremRangeByLex( stringKey, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).rejects.toThrow(RequestError); }, protocol); @@ -4952,15 +4954,15 @@ export function runBaseTests(config: { await client.zremRangeByScore( key, { value: 1 }, - InfScoreBoundary.NegativeInfinity, + InfBoundary.NegativeInfinity, ), ).toEqual(0); expect( await client.zremRangeByScore( "nonExistingKey", - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(0); }, protocol); @@ -4981,8 +4983,8 @@ export function runBaseTests(config: { expect( await client.zlexcount( key, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(3); @@ -4991,7 +4993,7 @@ export function runBaseTests(config: { await client.zlexcount( key, { value: "a", isInclusive: false }, - InfScoreBoundary.PositiveInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(2); @@ -4999,7 +5001,7 @@ export function runBaseTests(config: { expect( await client.zlexcount( key, - InfScoreBoundary.NegativeInfinity, + InfBoundary.NegativeInfinity, { value: "c", isInclusive: true, @@ -5011,7 +5013,7 @@ export function runBaseTests(config: { expect( await client.zlexcount( key, - InfScoreBoundary.PositiveInfinity, + InfBoundary.PositiveInfinity, { value: "c", isInclusive: true, @@ -5023,8 +5025,8 @@ export function runBaseTests(config: { expect( await client.zlexcount( "non_existing_key", - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).toEqual(0); @@ -5033,8 +5035,8 @@ export function runBaseTests(config: { await expect( client.zlexcount( stringKey, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ), ).rejects.toThrow(RequestError); }, protocol); @@ -7872,8 +7874,8 @@ export function runBaseTests(config: { ]); const result = await client.xpendingWithOptions(key, group, { - start: InfScoreBoundary.NegativeInfinity, - end: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.NegativeInfinity, + end: InfBoundary.PositiveInfinity, count: 1, minIdleTime: 42, }); diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index e964cd9400..d3d5a373f7 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -24,7 +24,7 @@ import { GeospatialData, GlideClient, GlideClusterClient, - InfScoreBoundary, + InfBoundary, InsertPosition, ListDirection, ProtocolVersion, @@ -848,19 +848,19 @@ export async function transactionTest( baseTransaction.zcount( key8, { value: 2 }, - InfScoreBoundary.PositiveInfinity, + InfBoundary.PositiveInfinity, ); responseData.push([ - "zcount(key8, { value: 2 }, InfScoreBoundary.PositiveInfinity)", + "zcount(key8, { value: 2 }, InfBoundary.PositiveInfinity)", 4, ]); baseTransaction.zlexcount( key8, { value: "a" }, - InfScoreBoundary.PositiveInfinity, + InfBoundary.PositiveInfinity, ); responseData.push([ - 'zlexcount(key8, { value: "a" }, InfScoreBoundary.PositiveInfinity)', + 'zlexcount(key8, { value: "a" }, InfBoundary.PositiveInfinity)', 4, ]); baseTransaction.zpopmin(key8); @@ -879,14 +879,14 @@ export async function transactionTest( responseData.push(["zremRangeByRank(key8, 1, 1)", 1]); baseTransaction.zremRangeByScore( key8, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ); responseData.push(["zremRangeByScore(key8, -Inf, +Inf)", 1]); // key8 is now empty baseTransaction.zremRangeByLex( key8, - InfScoreBoundary.NegativeInfinity, - InfScoreBoundary.PositiveInfinity, + InfBoundary.NegativeInfinity, + InfBoundary.PositiveInfinity, ); responseData.push(["zremRangeByLex(key8, -Inf, +Inf)", 0]); // key8 is already empty @@ -991,8 +991,8 @@ export async function transactionTest( [1, "0-2", "0-2", [["consumer1", "1"]]], ]); baseTransaction.xpendingWithOptions(key9, groupName1, { - start: InfScoreBoundary.NegativeInfinity, - end: InfScoreBoundary.PositiveInfinity, + start: InfBoundary.NegativeInfinity, + end: InfBoundary.PositiveInfinity, count: 10, }); responseData.push([ From 0db28d924b8790857a08a360506539b214035fad Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Wed, 14 Aug 2024 13:38:49 -0700 Subject: [PATCH 17/18] Adjust documentation and fix linting and tests Signed-off-by: Jonathan Louie --- node/src/BaseClient.ts | 23 +++++++++--------- node/src/Commands.ts | 4 +--- node/src/Transaction.ts | 19 +++++++-------- node/tests/SharedTests.ts | 48 +++++++++++++------------------------ node/tests/TestUtilities.ts | 6 +---- 5 files changed, 38 insertions(+), 62 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 6d2c71a0d4..6a0fbb7dcd 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -2820,23 +2820,22 @@ export class BaseClient { } /** - * Returns stream entries matching a given range of IDs. + * Returns stream entries matching a given range of entry IDs. * * See https://valkey.io/commands/xrange for more details. * * @param key - The key of the stream. - * @param start - The starting stream ID bound for the range. - * - Use `value` to specify a stream ID. - * - Use `isInclusive: false` to specify an exclusive bounded stream ID. - * - Use `-` to start with the minimum available ID. - * @param end - The ending stream ID bound for the range. - * - Use `value` to specify a stream ID. - * - Use `isInclusive: false` to specify an exclusive bounded stream ID. - * - Use `+` to end with the maximum available ID. + * @param start - The starting stream entry ID bound for the range. + * - Use `value` to specify a stream entry ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream entry ID. This is only available starting with Valkey version 6.2.0. + * - Use `InfBoundary.NegativeInfinity` to start with the minimum available ID. + * @param end - The ending stream entry ID bound for the range. + * - Use `value` to specify a stream entry ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream entry ID. This is only available starting with Valkey version 6.2.0. + * - Use `InfBoundary.PositiveInfinity` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. * If `count` is not provided, all stream entries in the range will be returned. - * @returns A mapping of stream IDs to stream entry data, where entry data is a - * list of pairings with format `[[field, entry], [field, entry], ...]`. + * @returns A map of stream entry ids, to an array of entries. * * @example * ```typescript @@ -2847,7 +2846,7 @@ export class BaseClient { * // { * // "0-1": [["field1", "value1"]], * // "0-2": [["field2", "value2"], ["field2", "value3"]], - * // } // Indicates the stream IDs and their associated field-value pairs for all stream entries in "mystream". + * // } // Indicates the stream entry IDs and their associated field-value pairs for all stream entries in "mystream". * ``` */ public async xrange( diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 84f04e3401..d8d57c2f0a 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1645,9 +1645,7 @@ function getScoreBoundaryArg( } /** Returns a string representation of a lex boundary as a command argument. */ -function getLexBoundaryArg( - score: Boundary | Boundary, -): string { +function getLexBoundaryArg(score: Boundary | Boundary): string { if (typeof score === "string") { // InfBoundary return score; diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index d4c345bdf1..70c2c2ac8e 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -2286,24 +2286,23 @@ export class BaseTransaction> { } /** - * Returns stream entries matching a given range of IDs. + * Returns stream entries matching a given range of entry IDs. * * See https://valkey.io/commands/xrange for more details. * * @param key - The key of the stream. - * @param start - The starting stream ID bound for the range. - * - Use `value` to specify a stream ID. - * - Use `isInclusive: false` to specify an exclusive bounded stream ID. - * - Use `-` to start with the minimum available ID. + * @param start - The starting stream entry ID bound for the range. + * - Use `value` to specify a stream entry ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream entry ID. This is only available starting with Valkey version 6.2.0. + * - Use `InfBoundary.NegativeInfinity` to start with the minimum available ID. * @param end - The ending stream ID bound for the range. - * - Use `value` to specify a stream ID. - * - Use `isInclusive: false` to specify an exclusive bounded stream ID. - * - Use `+` to end with the maximum available ID. + * - Use `value` to specify a stream entry ID. + * - Use `isInclusive: false` to specify an exclusive bounded stream entry ID. This is only available starting with Valkey version 6.2.0. + * - Use `InfBoundary.PositiveInfinity` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. * If `count` is not provided, all stream entries in the range will be returned. * - * Command Response - A mapping of stream IDs to stream entry data, where entry data is a - * list of pairings with format `[[field, entry], [field, entry], ...]`. + * Command Response - A map of stream entry ids, to an array of entries. */ public xrange( key: string, diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 6caf2a4d11..f3809821f4 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -3472,22 +3472,14 @@ export function runBaseTests(config: { ), ).toEqual(2); expect( - await client.zcount( - key1, - InfBoundary.NegativeInfinity, - { - value: 3, - }, - ), + await client.zcount(key1, InfBoundary.NegativeInfinity, { + value: 3, + }), ).toEqual(3); expect( - await client.zcount( - key1, - InfBoundary.PositiveInfinity, - { - value: 3, - }, - ), + await client.zcount(key1, InfBoundary.PositiveInfinity, { + value: 3, + }), ).toEqual(0); expect( await client.zcount( @@ -4756,7 +4748,7 @@ export function runBaseTests(config: { it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `xrange test_%p`, async (protocol) => { - await runTest(async (client: BaseClient) => { + await runTest(async (client: BaseClient, cluster) => { const key = uuidv4(); const nonExistingKey = uuidv4(); const stringKey = uuidv4(); @@ -4798,7 +4790,7 @@ export function runBaseTests(config: { ).toEqual(streamId3); // get the newest entry - if (!client.checkIfServerVersionLessThan("6.2.0")) { + if (!cluster.checkIfServerVersionLessThan("6.2.0")) { expect( await client.xrange( key, @@ -4999,26 +4991,18 @@ export function runBaseTests(config: { // In range negative infinity to c (inclusive) expect( - await client.zlexcount( - key, - InfBoundary.NegativeInfinity, - { - value: "c", - isInclusive: true, - }, - ), + await client.zlexcount(key, InfBoundary.NegativeInfinity, { + value: "c", + isInclusive: true, + }), ).toEqual(3); // Incorrect range start > end expect( - await client.zlexcount( - key, - InfBoundary.PositiveInfinity, - { - value: "c", - isInclusive: true, - }, - ), + await client.zlexcount(key, InfBoundary.PositiveInfinity, { + value: "c", + isInclusive: true, + }), ).toEqual(0); // Non-existing key diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index d3d5a373f7..8363637ff1 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -845,11 +845,7 @@ export async function transactionTest( responseData.push(["zinterstore(key12, [key12, key13])", 2]); } - baseTransaction.zcount( - key8, - { value: 2 }, - InfBoundary.PositiveInfinity, - ); + baseTransaction.zcount(key8, { value: 2 }, InfBoundary.PositiveInfinity); responseData.push([ "zcount(key8, { value: 2 }, InfBoundary.PositiveInfinity)", 4, From 7b443743ad41fd9aa7ae3b5fbe8bb439348b11c9 Mon Sep 17 00:00:00 2001 From: Jonathan Louie Date: Wed, 14 Aug 2024 14:20:39 -0700 Subject: [PATCH 18/18] Adjust documentation Signed-off-by: Jonathan Louie --- node/src/BaseClient.ts | 4 ++-- node/src/Transaction.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 6a0fbb7dcd..29cffdb2a5 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -2835,13 +2835,13 @@ export class BaseClient { * - Use `InfBoundary.PositiveInfinity` to end with the maximum available ID. * @param count - An optional argument specifying the maximum count of stream entries to return. * If `count` is not provided, all stream entries in the range will be returned. - * @returns A map of stream entry ids, to an array of entries. + * @returns A map of stream entry ids, to an array of entries, or `null` if `count` is negative. * * @example * ```typescript * await client.xadd("mystream", [["field1", "value1"]], {id: "0-1"}); * await client.xadd("mystream", [["field2", "value2"], ["field2", "value3"]], {id: "0-2"}); - * console.log(await client.xrange("mystream", "-", "+")); + * console.log(await client.xrange("mystream", InfBoundary.NegativeInfinity, InfBoundary.PositiveInfinity)); * // Output: * // { * // "0-1": [["field1", "value1"]], diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 70c2c2ac8e..cfc4250fdd 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -2302,7 +2302,7 @@ export class BaseTransaction> { * @param count - An optional argument specifying the maximum count of stream entries to return. * If `count` is not provided, all stream entries in the range will be returned. * - * Command Response - A map of stream entry ids, to an array of entries. + * Command Response - A map of stream entry ids, to an array of entries, or `null` if `count` is negative. */ public xrange( key: string,