From 5c2555e733e47b1e33d8e8e6b0075afb17b3c622 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 4 Sep 2024 11:49:46 -0700 Subject: [PATCH 01/14] implement node bitcount change Signed-off-by: Chloe Yip --- node/src/BaseClient.ts | 66 ++----------------- node/src/Commands.ts | 21 ++---- node/src/Transaction.ts | 38 ++--------- node/tests/SharedTests.ts | 123 +++++++++++++++++------------------- node/tests/TestUtilities.ts | 8 ++- 5 files changed, 81 insertions(+), 175 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 2bfb9a3bbd..3edbff09af 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1755,75 +1755,21 @@ export class BaseClient { * The offset can also be a negative number indicating an offset starting at the end of the list, with `-1` being * the last byte of the list, `-2` being the penultimate, and so on. * - * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for more details. + * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for details. * * @param key - The key of the string. * @param bit - The bit value to match. Must be `0` or `1`. - * @param start - (Optional) The starting offset. If not supplied, the search will start at the beginning of the string. - * @returns The position of the first occurrence of `bit` in the binary value of the string held at `key`. - * If `start` was provided, the search begins at the offset indicated by `start`. - * - * @example - * ```typescript - * await client.set("key1", "A1"); // "A1" has binary value 01000001 00110001 - * const result1 = await client.bitpos("key1", 1); - * console.log(result1); // Output: 1 - The first occurrence of bit value 1 in the string stored at "key1" is at the second position. + * @param options - (Optional) The {@link BitOffsetOptions}. * - * const result2 = await client.bitpos("key1", 1, -1); - * console.log(result2); // Output: 10 - The first occurrence of bit value 1, starting at the last byte in the string stored at "key1", is at the eleventh position. - * ``` + * @returns The position of the first occurrence of `bit` in the binary value of the string held at `key`. + * If `start` was provided, the search begins at the offset indicated by `start`. */ public async bitpos( key: GlideString, bit: number, - start?: number, - ): Promise { - return this.createWritePromise(createBitPos(key, bit, start)); - } - - /** - * Returns the position of the first bit matching the given `bit` value. The offsets are zero-based indexes, with - * `0` being the first element of the list, `1` being the next, and so on. These offsets can also be negative - * numbers indicating offsets starting at the end of the list, with `-1` being the last element of the list, `-2` - * being the penultimate, and so on. - * - * If you are using Valkey 7.0.0 or above, the optional `indexType` can also be provided to specify whether the - * `start` and `end` offsets specify BIT or BYTE offsets. If `indexType` is not provided, BYTE offsets - * are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is - * specified, `start=0` and `end=2` means to look at the first three bytes. - * - * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for more details. - * - * @param key - The key of the string. - * @param bit - The bit value to match. Must be `0` or `1`. - * @param start - The starting offset. - * @param end - The ending offset. - * @param indexType - (Optional) The index offset type. This option can only be specified if you are using Valkey - * version 7.0.0 or above. Could be either {@link BitmapIndexType.BYTE} or {@link BitmapIndexType.BIT}. If no - * index type is provided, the indexes will be assumed to be byte indexes. - * @returns The position of the first occurrence from the `start` to the `end` offsets of the `bit` in the binary - * value of the string held at `key`. - * - * @example - * ```typescript - * await client.set("key1", "A12"); // "A12" has binary value 01000001 00110001 00110010 - * const result1 = await client.bitposInterval("key1", 1, 1, -1); - * console.log(result1); // Output: 10 - The first occurrence of bit value 1 in the second byte to the last byte of the string stored at "key1" is at the eleventh position. - * - * const result2 = await client.bitposInterval("key1", 1, 2, 9, BitmapIndexType.BIT); - * console.log(result2); // Output: 7 - The first occurrence of bit value 1 in the third to tenth bits of the string stored at "key1" is at the eighth position. - * ``` - */ - public async bitposInterval( - key: GlideString, - bit: number, - start: number, - end: number, - indexType?: BitmapIndexType, + options?: BitOffsetOptions, ): Promise { - return this.createWritePromise( - createBitPos(key, bit, start, end, indexType), - ); + return this.createWritePromise(createBitPos(key, bit, options)); } /** diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 8411cf212d..385e33f735 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2475,7 +2475,7 @@ export function createFunctionRestore( } /** - * Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount|bitcount} command. The offsets are + * Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount|bitcount and @link BaseClient.bitpos} command. The offsets are * zero-based indexes, with `0` being the first index of the string, `1` being the next index and so on. * The offsets can also be negative numbers indicating offsets starting at the end of the string, with `-1` being * the last index of the string, `-2` being the penultimate, and so on. @@ -2535,24 +2535,15 @@ export enum BitmapIndexType { export function createBitPos( key: GlideString, bit: number, - start?: number, - end?: number, - indexType?: BitmapIndexType, + options?: BitOffsetOptions, ): command_request.Command { const args: GlideString[] = [key, bit.toString()]; - if (start !== undefined) { - args.push(start.toString()); - } - - if (end !== undefined) { - args.push(end.toString()); - } - - if (indexType) { - args.push(indexType); + if (options) { + if (options.start != undefined) args.push(options.start.toString()); + if (options.end != undefined) args.push(options.end.toString()); + if (options.indexType) args.push(options.indexType); } - return createCommand(RequestType.BitPos, args); } diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 485d7f06d0..73806be2d6 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -686,47 +686,17 @@ export class BaseTransaction> { * * @param key - The key of the string. * @param bit - The bit value to match. Must be `0` or `1`. - * @param start - (Optional) The starting offset. If not supplied, the search will start at the beginning of the string. + * @param options - (Optional) The {@link BitOffsetOptions}. * * Command Response - The position of the first occurrence of `bit` in the binary value of the string held at `key`. * If `start` was provided, the search begins at the offset indicated by `start`. */ - public bitpos(key: GlideString, bit: number, start?: number): T { - return this.addAndReturn(createBitPos(key, bit, start)); - } - - /** - * Returns the position of the first bit matching the given `bit` value. The offsets are zero-based indexes, with - * `0` being the first element of the list, `1` being the next, and so on. These offsets can also be negative - * numbers indicating offsets starting at the end of the list, with `-1` being the last element of the list, `-2` - * being the penultimate, and so on. - * - * If you are using Valkey 7.0.0 or above, the optional `indexType` can also be provided to specify whether the - * `start` and `end` offsets specify BIT or BYTE offsets. If `indexType` is not provided, BYTE offsets - * are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is - * specified, `start=0` and `end=2` means to look at the first three bytes. - * - * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for details. - * - * @param key - The key of the string. - * @param bit - The bit value to match. Must be `0` or `1`. - * @param start - The starting offset. - * @param end - The ending offset. - * @param indexType - (Optional) The index offset type. This option can only be specified if you are using Valkey - * version 7.0.0 or above. Could be either {@link BitmapIndexType.BYTE} or {@link BitmapIndexType.BIT}. If no - * index type is provided, the indexes will be assumed to be byte indexes. - * - * Command Response - The position of the first occurrence from the `start` to the `end` offsets of the `bit` in the - * binary value of the string held at `key`. - */ - public bitposInterval( + public bitpos( key: GlideString, bit: number, - start: number, - end: number, - indexType?: BitmapIndexType, + options?: BitOffsetOptions, ): T { - return this.addAndReturn(createBitPos(key, bit, start, end, indexType)); + return this.addAndReturn(createBitPos(key, bit, options)); } /** diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 51aebc03e1..3e9cb52153 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -835,7 +835,7 @@ export function runBaseTests(config: { ); it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( - `bitpos and bitposInterval test_%p`, + `bitpos test_%p`, async (protocol) => { await runTest(async (client: BaseClient, cluster) => { const key = `{key}-${uuidv4()}`; @@ -846,19 +846,30 @@ export function runBaseTests(config: { expect(await client.set(key, value)).toEqual("OK"); expect(await client.bitpos(key, 0)).toEqual(0); expect(await client.bitpos(Buffer.from(key), 1)).toEqual(2); - expect(await client.bitpos(key, 1, 1)).toEqual(9); - expect(await client.bitposInterval(key, 0, 3, 5)).toEqual(24); + expect(await client.bitpos(key, 1, { start: 1 })).toEqual(9); expect( - await client.bitposInterval(Buffer.from(key), 0, 3, 5), + await client.bitpos(key, 0, { start: 3, end: 5 }), + ).toEqual(24); + + expect( + await client.bitpos(Buffer.from(key), 0, { + start: 3, + end: 5, + }), ).toEqual(24); // -1 is returned if start > end - expect(await client.bitposInterval(key, 0, 1, 0)).toEqual(-1); + expect( + await client.bitpos(key, 0, { start: 1, end: 0 }), + ).toEqual(-1); // `BITPOS` returns -1 for non-existing strings expect(await client.bitpos(nonExistingKey, 1)).toEqual(-1); expect( - await client.bitposInterval(nonExistingKey, 1, 3, 5), + await client.bitpos(nonExistingKey, 1, { + start: 3, + end: 5, + }), ).toEqual(-1); // invalid argument - bit value must be 0 or 1 @@ -866,7 +877,7 @@ export function runBaseTests(config: { RequestError, ); await expect( - client.bitposInterval(key, 2, 3, 5), + client.bitpos(key, 2, { start: 3, end: 5 }), ).rejects.toThrow(RequestError); // key exists, but it is not a string @@ -875,86 +886,70 @@ export function runBaseTests(config: { RequestError, ); await expect( - client.bitposInterval(setKey, 1, 1, -1), + client.bitpos(setKey, 1, { start: 1, end: -1 }), ).rejects.toThrow(RequestError); if (cluster.checkIfServerVersionLessThan("7.0.0")) { await expect( - client.bitposInterval( - key, - 1, - 1, - -1, - BitmapIndexType.BYTE, - ), + client.bitpos(key, 1, { + start: 1, + end: -1, + indexType: BitmapIndexType.BYTE, + }), ).rejects.toThrow(RequestError); await expect( - client.bitposInterval( - key, - 1, - 1, - -1, - BitmapIndexType.BIT, - ), + client.bitpos(key, 1, { + start: 1, + end: -1, + indexType: BitmapIndexType.BIT, + }), ).rejects.toThrow(RequestError); } else { expect( - await client.bitposInterval( - key, - 0, - 3, - 5, - BitmapIndexType.BYTE, - ), + await client.bitpos(key, 0, { + start: 3, + end: 5, + indexType: BitmapIndexType.BYTE, + }), ).toEqual(24); expect( - await client.bitposInterval( - key, - 1, - 43, - -2, - BitmapIndexType.BIT, - ), + await client.bitpos(key, 1, { + start: 43, + end: -2, + indexType: BitmapIndexType.BIT, + }), ).toEqual(47); expect( - await client.bitposInterval( - nonExistingKey, - 1, - 3, - 5, - BitmapIndexType.BYTE, - ), + await client.bitpos(nonExistingKey, 1, { + start: 3, + end: 5, + indexType: BitmapIndexType.BYTE, + }), ).toEqual(-1); expect( - await client.bitposInterval( - nonExistingKey, - 1, - 3, - 5, - BitmapIndexType.BIT, - ), + await client.bitpos(nonExistingKey, 1, { + start: 3, + end: 5, + indexType: BitmapIndexType.BIT, + }), ).toEqual(-1); // -1 is returned if the bit value wasn't found expect( - await client.bitposInterval( - key, - 1, - -1, - -1, - BitmapIndexType.BIT, - ), + await client.bitpos(key, 1, { + start: -1, + end: -1, + indexType: BitmapIndexType.BIT, + }), ).toEqual(-1); // key exists, but it is not a string await expect( - client.bitposInterval( - setKey, - 1, - 1, - -1, - BitmapIndexType.BIT, - ), + client.bitpos(setKey, 1, { + start: 1, + end: -1, + indexType: BitmapIndexType.BIT, + }), ).rejects.toThrow(RequestError); } }, protocol); diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index d83fb56d98..88aa69cfa4 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -1410,9 +1410,13 @@ export async function transactionTest( "bitcount(key17, new BitOffsetOptions(5, 30, BitmapIndexType.BIT))", 17, ]); - baseTransaction.bitposInterval(key17, 1, 44, 50, BitmapIndexType.BIT); + baseTransaction.bitpos(key17, 1, { + start: 44, + end: 50, + indexType: BitmapIndexType.BIT, + }); responseData.push([ - "bitposInterval(key17, 1, 44, 50, BitmapIndexType.BIT)", + "bitpos(key17, 1, {start: 44, end: 50, indexType: BitmapIndexType.BIT})", 46, ]); } From bdf169e1f8ee510fe67a409b3f3d3f477a93ff2c Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 4 Sep 2024 12:02:24 -0700 Subject: [PATCH 02/14] added in examples in base client Signed-off-by: Chloe Yip --- node/src/BaseClient.ts | 21 +++++++++++++++++++++ node/src/Transaction.ts | 5 +++++ 2 files changed, 26 insertions(+) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 3edbff09af..82b266a615 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1755,6 +1755,11 @@ export class BaseClient { * The offset can also be a negative number indicating an offset starting at the end of the list, with `-1` being * the last byte of the list, `-2` being the penultimate, and so on. * + * If you are using Valkey 7.0.0 or above, the optional `indexType` can also be provided to specify whether the + * `start` and `end` offsets specify BIT or BYTE offsets. If `indexType` is not provided, BYTE offsets + * are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is + * specified, `start=0` and `end=2` means to look at the first three bytes. + * * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for details. * * @param key - The key of the string. @@ -1763,6 +1768,22 @@ export class BaseClient { * * @returns The position of the first occurrence of `bit` in the binary value of the string held at `key`. * If `start` was provided, the search begins at the offset indicated by `start`. + * @example + * ```typescript + * await client.set("key1", "A1"); // "A1" has binary value 01000001 00110001 + * const result1 = await client.bitpos("key1", 1); + * console.log(result1); // Output: 1 - The first occurrence of bit value 1 in the string stored at "key1" is at the second position. + * + * const result2 = await client.bitpos("key1", 1, -1); + * console.log(result2); // Output: 10 - The first occurrence of bit value 1, starting at the last byte in the string stored at "key1", is at the eleventh position. + * + * await client.set("key1", "A12"); // "A12" has binary value 01000001 00110001 00110010 + * const result3 = await client.bitpos("key1", 1, {start: 1, end: -1}); + * console.log(result3); // Output: 10 - The first occurrence of bit value 1 in the second byte to the last byte of the string stored at "key1" is at the eleventh position. + * + * const result4 = await client.bitpos("key1", 1, {start: 2, end: 9, indexType: BitmapIndexType.BIT}); + * console.log(result4); // Output: 7 - The first occurrence of bit value 1 in the third to tenth bits of the string stored at "key1" is at the eighth position. + * ``` */ public async bitpos( key: GlideString, diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 73806be2d6..9120491abc 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -682,6 +682,11 @@ export class BaseTransaction> { * The offset can also be a negative number indicating an offset starting at the end of the list, with `-1` being * the last byte of the list, `-2` being the penultimate, and so on. * + * If you are using Valkey 7.0.0 or above, the optional `indexType` can also be provided to specify whether the + * `start` and `end` offsets specify BIT or BYTE offsets. If `indexType` is not provided, BYTE offsets + * are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is + * specified, `start=0` and `end=2` means to look at the first three bytes. + * * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for details. * * @param key - The key of the string. From ef7d8ccbfa74a4d25a554e7026618cfe5b963b52 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Wed, 4 Sep 2024 12:10:30 -0700 Subject: [PATCH 03/14] fix lint errors Signed-off-by: Chloe Yip --- node/src/BaseClient.ts | 2 +- node/src/Commands.ts | 1 + node/src/Transaction.ts | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 82b266a615..b08f6d2d21 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -21,7 +21,6 @@ import { BitOffset, // eslint-disable-line @typescript-eslint/no-unused-vars BitOffsetMultiplier, // eslint-disable-line @typescript-eslint/no-unused-vars BitOffsetOptions, - BitmapIndexType, BitwiseOperation, Boundary, CoordOrigin, // eslint-disable-line @typescript-eslint/no-unused-vars @@ -1768,6 +1767,7 @@ export class BaseClient { * * @returns The position of the first occurrence of `bit` in the binary value of the string held at `key`. * If `start` was provided, the search begins at the offset indicated by `start`. + * * @example * ```typescript * await client.set("key1", "A1"); // "A1" has binary value 01000001 00110001 diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 385e33f735..ed43d36ffd 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2544,6 +2544,7 @@ export function createBitPos( if (options.end != undefined) args.push(options.end.toString()); if (options.indexType) args.push(options.indexType); } + return createCommand(RequestType.BitPos, args); } diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 9120491abc..c20828568f 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -23,7 +23,6 @@ import { BitOffset, // eslint-disable-line @typescript-eslint/no-unused-vars BitOffsetMultiplier, // eslint-disable-line @typescript-eslint/no-unused-vars BitOffsetOptions, - BitmapIndexType, BitwiseOperation, Boundary, CoordOrigin, // eslint-disable-line @typescript-eslint/no-unused-vars From 2d7b8841b6fb969fb9b256b0e11f6d29fe185611 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Thu, 5 Sep 2024 22:45:59 -0700 Subject: [PATCH 04/14] fix linter issue Signed-off-by: Chloe Yip --- node/src/Commands.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index ed43d36ffd..2c761b9243 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2525,6 +2525,7 @@ export function createBitCount( export enum BitmapIndexType { /** Specifies that provided indexes are byte indexes. */ BYTE = "BYTE", + /** Specifies that provided indexes are bit indexes. */ BIT = "BIT", } From 6cb81777ae10d2d1ec96a3cd0ca70753c0d8f1f5 Mon Sep 17 00:00:00 2001 From: Chloe Yip <168601573+cyip10@users.noreply.github.com> Date: Fri, 6 Sep 2024 14:53:29 -0700 Subject: [PATCH 05/14] fix spacing Co-authored-by: Andrew Carbonetto Signed-off-by: Chloe Yip <168601573+cyip10@users.noreply.github.com> --- 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 b08f6d2d21..895ee7ce71 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1765,7 +1765,7 @@ export class BaseClient { * @param bit - The bit value to match. Must be `0` or `1`. * @param options - (Optional) The {@link BitOffsetOptions}. * - * @returns The position of the first occurrence of `bit` in the binary value of the string held at `key`. + * @returns The position of the first occurrence of `bit` in the binary value of the string held at `key`. * If `start` was provided, the search begins at the offset indicated by `start`. * * @example From 357b376318c4bb54a97ed8f99c80fd3f105b8211 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Mon, 9 Sep 2024 08:31:38 -0700 Subject: [PATCH 06/14] add function Signed-off-by: Chloe Yip --- node/src/Commands.ts | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 2c761b9243..2718982278 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2495,6 +2495,18 @@ export interface BitOffsetOptions { * If no index type is provided, the indexes will be assumed to be byte indexes. */ indexType?: BitmapIndexType; +}; + +/** + * @internal + */ +function joinBitOptions(options: BitOffsetOptions): GlideString[] { + let args: GlideString[] = []; + if (options.start != undefined) args.push(options.start.toString()); + if (options.end != undefined) args.push(options.end.toString()); + if (options.indexType) args.push(options.indexType); + + return args; } /** @@ -2504,12 +2516,11 @@ export function createBitCount( key: GlideString, options?: BitOffsetOptions, ): command_request.Command { - const args = [key]; + let args: GlideString[] = [key]; if (options) { - args.push(options.start.toString()); - if (options.end !== undefined) args.push(options.end.toString()); - if (options.indexType) args.push(options.indexType); + let optionResults: GlideString[] = joinBitOptions(options); + args = args.concat(optionResults); } return createCommand(RequestType.BitCount, args); @@ -2541,9 +2552,8 @@ export function createBitPos( const args: GlideString[] = [key, bit.toString()]; if (options) { - if (options.start != undefined) args.push(options.start.toString()); - if (options.end != undefined) args.push(options.end.toString()); - if (options.indexType) args.push(options.indexType); + let optionResults: GlideString[] = joinBitOptions(options); + args = args.concat(optionResults); } return createCommand(RequestType.BitPos, args); From 7efe372d55c2d6d053fc1300895ffba389a807c5 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Mon, 9 Sep 2024 08:34:16 -0700 Subject: [PATCH 07/14] fix lint errors Signed-off-by: Chloe Yip --- node/src/Commands.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 2718982278..069df776d7 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2501,7 +2501,7 @@ export interface BitOffsetOptions { * @internal */ function joinBitOptions(options: BitOffsetOptions): GlideString[] { - let args: GlideString[] = []; + const args: GlideString[] = []; if (options.start != undefined) args.push(options.start.toString()); if (options.end != undefined) args.push(options.end.toString()); if (options.indexType) args.push(options.indexType); @@ -2519,7 +2519,7 @@ export function createBitCount( let args: GlideString[] = [key]; if (options) { - let optionResults: GlideString[] = joinBitOptions(options); + const optionResults: GlideString[] = joinBitOptions(options); args = args.concat(optionResults); } @@ -2552,7 +2552,7 @@ export function createBitPos( const args: GlideString[] = [key, bit.toString()]; if (options) { - let optionResults: GlideString[] = joinBitOptions(options); + const optionResults: GlideString[] = joinBitOptions(options); args = args.concat(optionResults); } From 5f4d3c6a5ec581e95b4dcdccd2a18c52b1630b46 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Mon, 9 Sep 2024 08:47:34 -0700 Subject: [PATCH 08/14] fix createbitpos Signed-off-by: Chloe Yip --- node/src/Commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 069df776d7..f7959cba2b 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2549,7 +2549,7 @@ export function createBitPos( bit: number, options?: BitOffsetOptions, ): command_request.Command { - const args: GlideString[] = [key, bit.toString()]; + let args: GlideString[] = [key, bit.toString()]; if (options) { const optionResults: GlideString[] = joinBitOptions(options); From 22b2c7433f7f64fdd686fa3d8bdbc7e04664f666 Mon Sep 17 00:00:00 2001 From: Chloe Yip Date: Mon, 9 Sep 2024 09:25:55 -0700 Subject: [PATCH 09/14] add changelog Signed-off-by: Chloe Yip --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ee5dda24f..928d066051 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ * Node: Replace instances of Redis with Valkey ([#2260](https://github.com/valkey-io/valkey-glide/pull/2260)) * Node: Added binary variant for commands which have `Record` as input or output ([#2207](https://github.com/valkey-io/valkey-glide/pull/2207)) * Node: Renamed `ReturnType` to `GlideReturnType` ([#2241](https://github.com/valkey-io/valkey-glide/pull/2241)) +* Node: Fix BITPOS for Valkey8 ([#2227](https://github.com/valkey-io/valkey-glide/pull/2227)) * Node, Python: Rename `stop` to `end` in sorted set queries ([#2214](https://github.com/valkey-io/valkey-glide/pull/2214)) * Node: Added binary variant to sorted set commands - part 1 ([#2190](https://github.com/valkey-io/valkey-glide/pull/2190)) * Node: Added binary variant to HSCAN command ([#2240](https://github.com/valkey-io/valkey-glide/pull/2240)) From d83ccd6e39070a51d820b85f27b0efcdd3efcfee Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 12 Sep 2024 16:33:25 -0700 Subject: [PATCH 10/14] rebase Signed-off-by: Yury-Fridlyand --- node/src/BaseClient.ts | 13 ++++--------- node/src/Commands.ts | 22 +++++++++++++--------- node/src/Transaction.ts | 7 +------ 3 files changed, 18 insertions(+), 24 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 895ee7ce71..6b09e30e98 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1754,11 +1754,6 @@ export class BaseClient { * The offset can also be a negative number indicating an offset starting at the end of the list, with `-1` being * the last byte of the list, `-2` being the penultimate, and so on. * - * If you are using Valkey 7.0.0 or above, the optional `indexType` can also be provided to specify whether the - * `start` and `end` offsets specify BIT or BYTE offsets. If `indexType` is not provided, BYTE offsets - * are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is - * specified, `start=0` and `end=2` means to look at the first three bytes. - * * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for details. * * @param key - The key of the string. @@ -1774,14 +1769,14 @@ export class BaseClient { * const result1 = await client.bitpos("key1", 1); * console.log(result1); // Output: 1 - The first occurrence of bit value 1 in the string stored at "key1" is at the second position. * - * const result2 = await client.bitpos("key1", 1, -1); + * const result2 = await client.bitpos("key1", 1, { start: -1 }); * console.log(result2); // Output: 10 - The first occurrence of bit value 1, starting at the last byte in the string stored at "key1", is at the eleventh position. * * await client.set("key1", "A12"); // "A12" has binary value 01000001 00110001 00110010 - * const result3 = await client.bitpos("key1", 1, {start: 1, end: -1}); + * const result3 = await client.bitpos("key1", 1, { start: 1, end: -1 }); * console.log(result3); // Output: 10 - The first occurrence of bit value 1 in the second byte to the last byte of the string stored at "key1" is at the eleventh position. * - * const result4 = await client.bitpos("key1", 1, {start: 2, end: 9, indexType: BitmapIndexType.BIT}); + * const result4 = await client.bitpos("key1", 1, { start: 2, end: 9, indexType: BitmapIndexType.BIT }); * console.log(result4); // Output: 7 - The first occurrence of bit value 1 in the third to tenth bits of the string stored at "key1" is at the eighth position. * ``` */ @@ -6411,7 +6406,7 @@ export class BaseClient { * @see {@link https://valkey.io/commands/bitcount/|valkey.io} for more details. * * @param key - The key for the string to count the set bits of. - * @param options - The offset options. + * @param options - The offset options - see {@link BitOffsetOptions}. * @returns If `options` is provided, returns the number of set bits in the string interval specified by `options`. * If `options` is not provided, returns the number of set bits in the string stored at `key`. * Otherwise, if `key` is missing, returns `0` as it is treated as an empty string. diff --git a/node/src/Commands.ts b/node/src/Commands.ts index f7959cba2b..11b784113d 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2475,12 +2475,17 @@ export function createFunctionRestore( } /** - * Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount|bitcount and @link BaseClient.bitpos} command. The offsets are - * zero-based indexes, with `0` being the first index of the string, `1` being the next index and so on. + * Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount | bitcount} and {@link BaseClient.bitpos | bitpos} commands. + * The offsets are zero-based indexes, with `0` being the first index of the string, `1` being the next index and so on. * The offsets can also be negative numbers indicating offsets starting at the end of the string, with `-1` being * the last index of the string, `-2` being the penultimate, and so on. * - * See https://valkey.io/commands/bitcount/ for more details. + * If you are using Valkey 7.0.0 or above, the optional `indexType` can also be provided to specify whether the + * `start` and `end` offsets specify `BIT` or `BYTE` offsets. If `indexType` is not provided, `BYTE` offsets + * are assumed. If `BIT` is specified, `start=0` and `end=2` means to look at the first three bits. If `BYTE` is + * specified, `start=0` and `end=2` means to look at the first three bytes. + * + * @see {@link https://valkey.io/commands/bitcount/ | bitcount} and {@link https://valkey.io/commands/bitpos/ | bitpos} for more details. */ export interface BitOffsetOptions { /** The starting offset index. */ @@ -2549,12 +2554,11 @@ export function createBitPos( bit: number, options?: BitOffsetOptions, ): command_request.Command { - let args: GlideString[] = [key, bit.toString()]; - - if (options) { - const optionResults: GlideString[] = joinBitOptions(options); - args = args.concat(optionResults); - } + const args: GlideString[] = [ + key, + bit.toString(), + ...convertBitOptionsToArgs(options), + ]; return createCommand(RequestType.BitPos, args); } diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index c20828568f..bdccbe151f 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -681,11 +681,6 @@ export class BaseTransaction> { * The offset can also be a negative number indicating an offset starting at the end of the list, with `-1` being * the last byte of the list, `-2` being the penultimate, and so on. * - * If you are using Valkey 7.0.0 or above, the optional `indexType` can also be provided to specify whether the - * `start` and `end` offsets specify BIT or BYTE offsets. If `indexType` is not provided, BYTE offsets - * are assumed. If BIT is specified, `start=0` and `end=2` means to look at the first three bits. If BYTE is - * specified, `start=0` and `end=2` means to look at the first three bytes. - * * @see {@link https://valkey.io/commands/bitpos/|valkey.io} for details. * * @param key - The key of the string. @@ -3490,7 +3485,7 @@ export class BaseTransaction> { * @see {@link https://valkey.io/commands/bitcount/|valkey.io} for more details. * * @param key - The key for the string to count the set bits of. - * @param options - The offset options. + * @param options - The offset options - see {@link BitOffsetOptions}. * * Command Response - If `options` is provided, returns the number of set bits in the string interval specified by `options`. * If `options` is not provided, returns the number of set bits in the string stored at `key`. From 8a58d08784fefe37262ae4853b5122ba13226b51 Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 12 Sep 2024 16:35:41 -0700 Subject: [PATCH 11/14] rebase Signed-off-by: Yury-Fridlyand --- node/src/Commands.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 11b784113d..2e1c5530a0 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2507,9 +2507,17 @@ export interface BitOffsetOptions { */ function joinBitOptions(options: BitOffsetOptions): GlideString[] { const args: GlideString[] = []; - if (options.start != undefined) args.push(options.start.toString()); - if (options.end != undefined) args.push(options.end.toString()); - if (options.indexType) args.push(options.indexType); + if (!options) return args; + + if (options.start !== undefined) { + args.push(options.start.toString()); + + if (options.end !== undefined) { + args.push(options.end.toString()); + + if (options.indexType) args.push(options.indexType); + } + } return args; } From bab0c11228e151e388aa20811feb640a3bd0b05f Mon Sep 17 00:00:00 2001 From: Yury-Fridlyand Date: Thu, 12 Sep 2024 16:47:08 -0700 Subject: [PATCH 12/14] Signed-off-by: Yury-Fridlyand --- node/src/Commands.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 2e1c5530a0..52b78edd88 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2514,7 +2514,7 @@ function joinBitOptions(options: BitOffsetOptions): GlideString[] { if (options.end !== undefined) { args.push(options.end.toString()); - + if (options.indexType) args.push(options.indexType); } } From c5bef0ce785bade1a735dc91e74adefb7fb1aeea Mon Sep 17 00:00:00 2001 From: James Xin Date: Thu, 26 Sep 2024 10:18:45 -0700 Subject: [PATCH 13/14] make 'start' required for BitOffsetOptions Signed-off-by: James Xin --- node/src/Commands.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 52b78edd88..f7e8cca114 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2490,8 +2490,10 @@ export function createFunctionRestore( export interface BitOffsetOptions { /** The starting offset index. */ start: number; - /** The ending offset index. Optional since Valkey version 8.0 and above. - * If not provided, it will default to the end of the string + /** + * The ending offset index. Optional since Valkey version 8.0 and above for the BITCOUNT command. + * If not provided, it will default to the end of the string. + * Could be defined only if `start` is defined. */ end?: number; /** From 687b72f63ba506b46ccc41418484cb1c1e7052d2 Mon Sep 17 00:00:00 2001 From: James Xin Date: Thu, 26 Sep 2024 11:58:21 -0700 Subject: [PATCH 14/14] post rebase clean up Signed-off-by: James Xin --- node/src/Commands.ts | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/node/src/Commands.ts b/node/src/Commands.ts index f7e8cca114..e7e10d7e5f 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2502,23 +2502,21 @@ export interface BitOffsetOptions { * If no index type is provided, the indexes will be assumed to be byte indexes. */ indexType?: BitmapIndexType; -}; +} /** * @internal */ -function joinBitOptions(options: BitOffsetOptions): GlideString[] { +function convertBitOptionsToArgs(options?: BitOffsetOptions): GlideString[] { const args: GlideString[] = []; if (!options) return args; - if (options.start !== undefined) { - args.push(options.start.toString()); + args.push(options.start.toString()); - if (options.end !== undefined) { - args.push(options.end.toString()); + if (options.end !== undefined) { + args.push(options.end.toString()); - if (options.indexType) args.push(options.indexType); - } + if (options.indexType) args.push(options.indexType); } return args; @@ -2534,7 +2532,7 @@ export function createBitCount( let args: GlideString[] = [key]; if (options) { - const optionResults: GlideString[] = joinBitOptions(options); + const optionResults: GlideString[] = convertBitOptionsToArgs(options); args = args.concat(optionResults); }