From a317310573e60f59ffd3db593cae4e68bf3ccedb Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Mon, 22 Jul 2024 16:54:26 -0700 Subject: [PATCH 1/8] Node: add BITPOS command Signed-off-by: aaron-congo --- CHANGELOG.md | 1 + node/npm/glide/index.ts | 4 +- node/src/BaseClient.ts | 76 +++++++++++++++ node/src/Commands.ts | 37 ++++++++ node/src/Transaction.ts | 58 ++++++++++++ node/src/commands/BitOffsetOptions.ts | 14 +-- node/src/commands/BitmapIndexType.ts | 17 ++++ node/tests/SharedTests.ts | 131 +++++++++++++++++++++++++- node/tests/TestUtilities.ts | 10 +- 9 files changed, 325 insertions(+), 23 deletions(-) create mode 100644 node/src/commands/BitmapIndexType.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1146b4a2a1..061bf034a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ #### Changes * Node: Added BITCOUNT command ([#1982](https://github.com/valkey-io/valkey-glide/pull/1982)) +* Node: Added BITPOS command ([#1998](https://github.com/valkey-io/valkey-glide/pull/1998)) * Node: Added FLUSHDB command ([#1986](https://github.com/valkey-io/valkey-glide/pull/1986)) * Node: Added GETDEL command ([#1968](https://github.com/valkey-io/valkey-glide/pull/1968)) * Node: Added GETBIT command ([#1989](https://github.com/valkey-io/valkey-glide/pull/1989)) diff --git a/node/npm/glide/index.ts b/node/npm/glide/index.ts index 513e6198f5..fdf0860a1a 100644 --- a/node/npm/glide/index.ts +++ b/node/npm/glide/index.ts @@ -74,8 +74,8 @@ function loadNativeBinding() { function initialize() { const nativeBinding = loadNativeBinding(); const { - BitOffsetOptions, BitmapIndexType, + BitOffsetOptions, ConditionalChange, GeoAddOptions, GeospatialData, @@ -126,8 +126,8 @@ function initialize() { } = nativeBinding; module.exports = { - BitOffsetOptions, BitmapIndexType, + BitOffsetOptions, ConditionalChange, GeoAddOptions, GeospatialData, diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 3464809038..3f41ffc5f1 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -27,6 +27,8 @@ import { createBLPop, createBRPop, createBitCount, + createBitPos, + createBitPosInterval, createDecr, createDecrBy, createDel, @@ -125,6 +127,7 @@ import { createZRevRankWithScore, createZScore, } from "./Commands"; +import { BitmapIndexType } from "./commands/BitmapIndexType"; import { BitOffsetOptions } from "./commands/BitOffsetOptions"; import { LPosOptions } from "./commands/LPosOptions"; import { @@ -1017,6 +1020,79 @@ export class BaseClient { return this.createWritePromise(createSetBit(key, offset, value)); } + /** + * Returns the position of the first bit matching the given `bit` value. The optional starting offset + * `start` is a zero-based index, with `0` being the first byte of the list, `1` being the next byte and so on. + * 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 https://valkey.io/commands/bitpos/ 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. + * @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. + * ``` + */ + public bitpos(key: string, 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 `index_type` can also be provided to specify whether the + * `start` and `end` offsets specify BIT or BYTE offsets. If `index_type` 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 https://valkey.io/commands/bitpos/ 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 - The index offset type. This option can only be specified if you are using Valkey version + * 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `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 bitposInterval( + key: string, + bit: number, + start: number, + end: number, + indexType?: BitmapIndexType, + ): Promise { + return this.createWritePromise( + createBitPosInterval(key, bit, start, end, indexType), + ); + } + /** Retrieve the value associated with `field` in the hash stored at `key`. * See https://valkey.io/commands/hget/ for details. * diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 2743d95918..143158d078 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -8,6 +8,7 @@ import { FlushMode } from "./commands/FlushMode"; import { LPosOptions } from "./commands/LPosOptions"; import { command_request } from "./ProtobufMessage"; +import { BitmapIndexType } from "./commands/BitmapIndexType"; import { BitOffsetOptions } from "./commands/BitOffsetOptions"; import { GeoAddOptions } from "./commands/geospatial/GeoAddOptions"; import { GeospatialData } from "./commands/geospatial/GeospatialData"; @@ -1608,6 +1609,42 @@ export function createBitCount( return createCommand(RequestType.BitCount, args); } +/** + * @internal + */ +export function createBitPos( + key: string, + bit: number, + start?: number, +): command_request.Command { + const args = [key, bit.toString()]; + + if (start) { + args.push(start.toString()); + } + + return createCommand(RequestType.BitPos, args); +} + +/** + * @internal + */ +export function createBitPosInterval( + key: string, + bit: number, + start: number, + end: number, + indexType?: BitmapIndexType, +): command_request.Command { + const args = [key, bit.toString(), start.toString(), end.toString()]; + + if (indexType) { + args.push(indexType); + } + + return createCommand(RequestType.BitPos, args); +} + /** * @internal */ diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 02e859d840..07b1e2e8d9 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -21,6 +21,8 @@ import { createBLPop, createBRPop, createBitCount, + createBitPos, + createBitPosInterval, createClientGetName, createClientId, createConfigGet, @@ -139,6 +141,7 @@ import { createZScore, } from "./Commands"; import { command_request } from "./ProtobufMessage"; +import { BitmapIndexType } from "./commands/BitmapIndexType"; import { BitOffsetOptions } from "./commands/BitOffsetOptions"; import { FlushMode } from "./commands/FlushMode"; import { LPosOptions } from "./commands/LPosOptions"; @@ -423,6 +426,61 @@ export class BaseTransaction> { return this.addAndReturn(createSetBit(key, offset, value)); } + /** + * Returns the position of the first bit matching the given `bit` value. The optional starting offset + * `start` is a zero-based index, with `0` being the first byte of the list, `1` being the next byte and so on. + * 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 https://valkey.io/commands/bitpos/ 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. + * + * 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: string, 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 `index_type` can also be provided to specify whether the + * `start` and `end` offsets specify BIT or BYTE offsets. If `index_type` 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 https://valkey.io/commands/bitpos/ 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 - The index offset type. This option can only be specified if you are using Valkey version + * 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `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( + key: string, + bit: number, + start: number, + end: number, + indexType?: BitmapIndexType, + ): T { + return this.addAndReturn( + createBitPosInterval(key, bit, start, end, indexType), + ); + } + /** Reads the configuration parameters of a running Redis server. * See https://valkey.io/commands/config-get/ for details. * diff --git a/node/src/commands/BitOffsetOptions.ts b/node/src/commands/BitOffsetOptions.ts index 64f6f8a82e..9fc94779f9 100644 --- a/node/src/commands/BitOffsetOptions.ts +++ b/node/src/commands/BitOffsetOptions.ts @@ -5,19 +5,7 @@ // Import below added to fix up the TSdoc link, but eslint blames for unused import. /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ import { BaseClient } from "src/BaseClient"; - -/** - * Enumeration specifying if index arguments are BYTE indexes or BIT indexes. - * Can be specified in {@link BitOffsetOptions}, which is an optional argument to the {@link BaseClient.bitcount|bitcount} command. - * - * since - Valkey version 7.0.0. - */ -export enum BitmapIndexType { - /** Specifies that indexes provided to {@link BitOffsetOptions} are byte indexes. */ - BYTE = "BYTE", - /** Specifies that indexes provided to {@link BitOffsetOptions} are bit indexes. */ - BIT = "BIT", -} +import { BitmapIndexType } from "./BitmapIndexType"; /** * Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount|bitcount} command. The offsets are diff --git a/node/src/commands/BitmapIndexType.ts b/node/src/commands/BitmapIndexType.ts new file mode 100644 index 0000000000..9a9c58a0cc --- /dev/null +++ b/node/src/commands/BitmapIndexType.ts @@ -0,0 +1,17 @@ +/** + * Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 + */ + +/** + * Enumeration specifying if index arguments are BYTE indexes or BIT indexes. + * Can be specified in {@link BitOffsetOptions}, which is an optional argument to the {@link BaseClient.bitcount|bitcount} command. + * Can also be specified as an optional argument to the {@link BaseClient.bitposInverval|bitposInterval} command. + * + * since - Valkey version 7.0.0. + */ +export enum BitmapIndexType { + /** Specifies that provided indexes are byte indexes. */ + BYTE = "BYTE", + /** Specifies that provided indexes are bit indexes. */ + BIT = "BIT", +} diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index bab16def9a..e1a0997035 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -27,10 +27,8 @@ import { intoString, } from "./TestUtilities"; import { SingleNodeRoute } from "../build-ts/src/GlideClusterClient"; -import { - BitmapIndexType, - BitOffsetOptions, -} from "../build-ts/src/commands/BitOffsetOptions"; +import { BitmapIndexType } from "../build-ts/src/commands/BitmapIndexType"; +import { BitOffsetOptions } from "../build-ts/src/commands/BitOffsetOptions"; import { LPosOptions } from "../build-ts/src/commands/LPosOptions"; import { GeospatialData } from "../build-ts/src/commands/geospatial/GeospatialData"; import { GeoAddOptions } from "../build-ts/src/commands/geospatial/GeoAddOptions"; @@ -556,6 +554,131 @@ export function runBaseTests(config: { config.timeout, ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `bitpos and bitposInterval test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + const key = `{key}-${uuidv4()}`; + const nonExistingKey = `{key}-${uuidv4()}`; + const setKey = `{key}-${uuidv4()}`; + const value = "?f0obar"; // 00111111 01100110 00110000 01101111 01100010 01100001 01110010 + + checkSimple(await client.set(key, value)).toEqual("OK"); + expect(await client.bitpos(key, 0)).toEqual(0); + expect(await client.bitpos(key, 1)).toEqual(2); + expect(await client.bitpos(key, 1, 1)).toEqual(9); + expect(await client.bitposInterval(key, 0, 3, 5)).toEqual(24); + + // -1 is returned if start > end + expect(await client.bitposInterval(key, 0, 1, 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), + ).toEqual(-1); + + // invalid argument - bit value must be 0 or 1 + await expect(client.bitpos(key, 2)).rejects.toThrow( + RequestError, + ); + await expect( + client.bitposInterval(key, 2, 3, 5), + ).rejects.toThrow(RequestError); + + // key exists, but it is not a string + expect(await client.sadd(setKey, ["foo"])).toEqual(1); + await expect(client.bitpos(setKey, 1)).rejects.toThrow( + RequestError, + ); + await expect( + client.bitposInterval(setKey, 1, 1, -1), + ).rejects.toThrow(RequestError); + + if (await checkIfServerVersionLessThan("7.0.0")) { + await expect( + client.bitposInterval( + key, + 1, + 1, + -1, + BitmapIndexType.BYTE, + ), + ).rejects.toThrow(RequestError); + await expect( + client.bitposInterval( + key, + 1, + 1, + -1, + BitmapIndexType.BIT, + ), + ).rejects.toThrow(RequestError); + } else { + expect( + await client.bitposInterval( + key, + 0, + 3, + 5, + BitmapIndexType.BYTE, + ), + ).toEqual(24); + expect( + await client.bitposInterval( + key, + 1, + 43, + -2, + BitmapIndexType.BIT, + ), + ).toEqual(47); + expect( + await client.bitposInterval( + nonExistingKey, + 1, + 3, + 5, + BitmapIndexType.BYTE, + ), + ).toEqual(-1); + expect( + await client.bitposInterval( + nonExistingKey, + 1, + 3, + 5, + BitmapIndexType.BIT, + ), + ).toEqual(-1); + + // -1 is returned if the bit value wasn't found + expect( + await client.bitposInterval( + key, + 1, + -1, + -1, + BitmapIndexType.BIT, + ), + ).toEqual(-1); + + // key exists, but it is not a string + await expect( + client.bitposInterval( + setKey, + 1, + 1, + -1, + BitmapIndexType.BIT, + ), + ).rejects.toThrow(RequestError); + } + }, protocol); + }, + config.timeout, + ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `config get and config set with timeout parameter_%p`, async (protocol) => { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index bb292de4ee..8b4278d3dd 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -18,10 +18,8 @@ import { ReturnType, Transaction, } from ".."; -import { - BitmapIndexType, - BitOffsetOptions, -} from "../build-ts/src/commands/BitOffsetOptions"; +import { BitmapIndexType } from "../build-ts/src/commands/BitmapIndexType"; +import { BitOffsetOptions } from "../build-ts/src/commands/BitOffsetOptions"; import { FlushMode } from "../build-ts/src/commands/FlushMode"; import { GeospatialData } from "../build-ts/src/commands/geospatial/GeospatialData"; import { LPosOptions } from "../build-ts/src/commands/LPosOptions"; @@ -641,6 +639,8 @@ export async function transactionTest( args.push(26); baseTransaction.bitcount(key17, new BitOffsetOptions(1, 1)); args.push(6); + baseTransaction.bitpos(key17, 1); + args.push(1); if (!(await checkIfServerVersionLessThan("7.0.0"))) { baseTransaction.bitcount( @@ -648,6 +648,8 @@ export async function transactionTest( new BitOffsetOptions(5, 30, BitmapIndexType.BIT), ); args.push(17); + baseTransaction.bitposInterval(key17, 1, 44, 50, BitmapIndexType.BIT); + args.push(46); } baseTransaction.pfadd(key11, ["a", "b", "c"]); From f0a6a37670a0c04a251bc96a2eaa55950836b065 Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Tue, 23 Jul 2024 10:07:49 -0700 Subject: [PATCH 2/8] PR suggestions Signed-off-by: aaron-congo --- node/src/BaseClient.ts | 8 ++++---- node/src/Transaction.ts | 8 ++++---- node/src/commands/BitmapIndexType.ts | 6 ++++++ 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 3f41ffc5f1..0802aa1b73 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1054,8 +1054,8 @@ export class BaseClient { * 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 `index_type` can also be provided to specify whether the - * `start` and `end` offsets specify BIT or BYTE offsets. If `index_type` is not provided, BYTE offsets + * 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. * @@ -1066,8 +1066,8 @@ export class BaseClient { * @param start - The starting offset. * @param end - The ending offset. * @param indexType - The index offset type. This option can only be specified if you are using Valkey version - * 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. If no index type is - * provided, the indexes will be assumed to be byte indexes. + * 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`. * diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 07b1e2e8d9..c8e9e8f828 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -451,8 +451,8 @@ export class BaseTransaction> { * 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 `index_type` can also be provided to specify whether the - * `start` and `end` offsets specify BIT or BYTE offsets. If `index_type` is not provided, BYTE offsets + * 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. * @@ -463,8 +463,8 @@ export class BaseTransaction> { * @param start - The starting offset. * @param end - The ending offset. * @param indexType - The index offset type. This option can only be specified if you are using Valkey version - * 7.0.0 or above. Could be either `BitmapIndexType.BYTE` or `BitmapIndexType.BIT`. If no index type is - * provided, the indexes will be assumed to be byte indexes. + * 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`. diff --git a/node/src/commands/BitmapIndexType.ts b/node/src/commands/BitmapIndexType.ts index 9a9c58a0cc..137c1d79f4 100644 --- a/node/src/commands/BitmapIndexType.ts +++ b/node/src/commands/BitmapIndexType.ts @@ -2,6 +2,12 @@ * Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 */ +// Imports below added to fix up the TSdoc links, but eslint complains about unused imports. +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +import { BaseClient } from "src/BaseClient"; +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +import { BitOffsetOptions } from "src/commands/BitOffsetOptions"; + /** * Enumeration specifying if index arguments are BYTE indexes or BIT indexes. * Can be specified in {@link BitOffsetOptions}, which is an optional argument to the {@link BaseClient.bitcount|bitcount} command. From 151a839b9bc94321c17b1b2a3c4b5d1c9c9ccb9f Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Wed, 24 Jul 2024 09:31:01 -0700 Subject: [PATCH 3/8] PR suggestions Signed-off-by: aaron-congo --- node/src/BaseClient.ts | 12 ++++++------ node/src/Transaction.ts | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 0802aa1b73..db82a6c0da 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1030,9 +1030,9 @@ export class BaseClient { * * @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 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`. + * If `start` was provided, the search begins at the offset indicated by `start`. * * @example * ```typescript @@ -1065,9 +1065,9 @@ export class BaseClient { * @param bit - The bit value to match. Must be `0` or `1`. * @param start - The starting offset. * @param end - The ending offset. - * @param indexType - 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. + * @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`. * @@ -1081,7 +1081,7 @@ export class BaseClient { * 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 bitposInterval( + public bitpos( key: string, bit: number, start: number, diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index c8e9e8f828..b6d9b1bb47 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -436,10 +436,10 @@ export class BaseTransaction> { * * @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 start - (Optional) The starting offset. If not supplied, the search will start at the beginning of the string. * * 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`. + * If `start` was provided, the search begins at the offset indicated by `start`. */ public bitpos(key: string, bit: number, start?: number): T { return this.addAndReturn(createBitPos(key, bit, start)); @@ -462,14 +462,14 @@ export class BaseTransaction> { * @param bit - The bit value to match. Must be `0` or `1`. * @param start - The starting offset. * @param end - The ending offset. - * @param indexType - 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. + * @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: string, bit: number, start: number, From 4bb26ccfd9c098282db197b7cd01ea4d25c908f3 Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Wed, 24 Jul 2024 09:35:49 -0700 Subject: [PATCH 4/8] Undo function rename Signed-off-by: aaron-congo --- node/src/BaseClient.ts | 2 +- node/src/Transaction.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index db82a6c0da..f4d87613a5 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1081,7 +1081,7 @@ export class BaseClient { * 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 bitpos( + public bitposInterval( key: string, bit: number, start: number, diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index b6d9b1bb47..64a3ee078a 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -469,7 +469,7 @@ export class BaseTransaction> { * 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 bitpos( + public bitposInterval( key: string, bit: number, start: number, From 308180e16ea619ac2713f9bd6055a4201b61525e Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Wed, 24 Jul 2024 14:32:59 -0700 Subject: [PATCH 5/8] Merge createBitPos and createBitPosInterval Signed-off-by: aaron-congo --- node/src/BaseClient.ts | 3 +-- node/src/Commands.ts | 21 ++++++--------------- node/src/Transaction.ts | 5 +---- 3 files changed, 8 insertions(+), 21 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index f4d87613a5..8afa717506 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -28,7 +28,6 @@ import { createBRPop, createBitCount, createBitPos, - createBitPosInterval, createDecr, createDecrBy, createDel, @@ -1089,7 +1088,7 @@ export class BaseClient { indexType?: BitmapIndexType, ): Promise { return this.createWritePromise( - createBitPosInterval(key, bit, start, end, indexType), + createBitPos(key, bit, start, end, indexType), ); } diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 143158d078..453a9d558b 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1616,27 +1616,18 @@ export function createBitPos( key: string, bit: number, start?: number, + end?: number, + indexType?: BitmapIndexType, ): command_request.Command { const args = [key, bit.toString()]; - if (start) { + if (start !== undefined) { args.push(start.toString()); } - return createCommand(RequestType.BitPos, args); -} - -/** - * @internal - */ -export function createBitPosInterval( - key: string, - bit: number, - start: number, - end: number, - indexType?: BitmapIndexType, -): command_request.Command { - const args = [key, bit.toString(), start.toString(), end.toString()]; + if (end !== undefined) { + args.push(end.toString()); + } if (indexType) { args.push(indexType); diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 64a3ee078a..eb9c51b8cc 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -22,7 +22,6 @@ import { createBRPop, createBitCount, createBitPos, - createBitPosInterval, createClientGetName, createClientId, createConfigGet, @@ -476,9 +475,7 @@ export class BaseTransaction> { end: number, indexType?: BitmapIndexType, ): T { - return this.addAndReturn( - createBitPosInterval(key, bit, start, end, indexType), - ); + return this.addAndReturn(createBitPos(key, bit, start, end, indexType)); } /** Reads the configuration parameters of a running Redis server. From f796a81975ee4444d62d831c616e589c0a2d1423 Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Wed, 24 Jul 2024 14:58:54 -0700 Subject: [PATCH 6/8] Update checkIfServerVersionLessThan call Signed-off-by: aaron-congo --- 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 f4107c0dbe..f32d9b93d0 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -535,7 +535,7 @@ export function runBaseTests(config: { it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `bitpos and bitposInterval test_%p`, async (protocol) => { - await runTest(async (client: BaseClient) => { + await runTest(async (client: BaseClient, cluster) => { const key = `{key}-${uuidv4()}`; const nonExistingKey = `{key}-${uuidv4()}`; const setKey = `{key}-${uuidv4()}`; @@ -573,7 +573,7 @@ export function runBaseTests(config: { client.bitposInterval(setKey, 1, 1, -1), ).rejects.toThrow(RequestError); - if (await checkIfServerVersionLessThan("7.0.0")) { + if (cluster.checkIfServerVersionLessThan("7.0.0")) { await expect( client.bitposInterval( key, From 5c5ca725fc6a6c72841bf5b1743462eca6ee8a48 Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Wed, 24 Jul 2024 16:06:13 -0700 Subject: [PATCH 7/8] Move BitmapIndexType to Commands.ts Signed-off-by: aaron-congo --- node/src/BaseClient.ts | 2 +- node/src/Commands.ts | 15 ++++++++++++++- node/src/Transaction.ts | 2 +- node/src/commands/BitOffsetOptions.ts | 2 +- node/src/commands/BitmapIndexType.ts | 23 ----------------------- node/tests/SharedTests.ts | 2 +- node/tests/TestUtilities.ts | 2 +- 7 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 node/src/commands/BitmapIndexType.ts diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 843369f55b..9bece7d084 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -12,6 +12,7 @@ import * as net from "net"; import { Buffer, BufferWriter, Reader, Writer } from "protobufjs"; import { AggregationType, + BitmapIndexType, ExpireOptions, InsertPosition, KeyWeight, @@ -132,7 +133,6 @@ import { createZScore, GeoUnit, } from "./Commands"; -import { BitmapIndexType } from "./commands/BitmapIndexType"; import { BitOffsetOptions } from "./commands/BitOffsetOptions"; import { GeoAddOptions } from "./commands/geospatial/GeoAddOptions"; import { GeospatialData } from "./commands/geospatial/GeospatialData"; diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 51db369ab5..49f000fa1b 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -8,7 +8,6 @@ import { FlushMode } from "./commands/FlushMode"; import { LPosOptions } from "./commands/LPosOptions"; import { command_request } from "./ProtobufMessage"; -import { BitmapIndexType } from "./commands/BitmapIndexType"; import { BitOffsetOptions } from "./commands/BitOffsetOptions"; import { GeoAddOptions } from "./commands/geospatial/GeoAddOptions"; import { GeospatialData } from "./commands/geospatial/GeospatialData"; @@ -1617,6 +1616,20 @@ export function createBitCount( return createCommand(RequestType.BitCount, args); } +/** + * Enumeration specifying if index arguments are BYTE indexes or BIT indexes. + * Can be specified in {@link BitOffsetOptions}, which is an optional argument to the {@link BaseClient.bitcount|bitcount} command. + * Can also be specified as an optional argument to the {@link BaseClient.bitposInverval|bitposInterval} command. + * + * since - Valkey version 7.0.0. + */ +export enum BitmapIndexType { + /** Specifies that provided indexes are byte indexes. */ + BYTE = "BYTE", + /** Specifies that provided indexes are bit indexes. */ + BIT = "BIT", +} + /** * @internal */ diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index cbf928e4b1..c04dab33e2 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -4,6 +4,7 @@ import { AggregationType, + BitmapIndexType, ExpireOptions, InfoOptions, InsertPosition, @@ -146,7 +147,6 @@ import { GeoUnit, } from "./Commands"; import { command_request } from "./ProtobufMessage"; -import { BitmapIndexType } from "./commands/BitmapIndexType"; import { BitOffsetOptions } from "./commands/BitOffsetOptions"; import { FlushMode } from "./commands/FlushMode"; import { LPosOptions } from "./commands/LPosOptions"; diff --git a/node/src/commands/BitOffsetOptions.ts b/node/src/commands/BitOffsetOptions.ts index 9fc94779f9..5f5d6800e6 100644 --- a/node/src/commands/BitOffsetOptions.ts +++ b/node/src/commands/BitOffsetOptions.ts @@ -5,7 +5,7 @@ // Import below added to fix up the TSdoc link, but eslint blames for unused import. /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ import { BaseClient } from "src/BaseClient"; -import { BitmapIndexType } from "./BitmapIndexType"; +import { BitmapIndexType } from "src/Commands"; /** * Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount|bitcount} command. The offsets are diff --git a/node/src/commands/BitmapIndexType.ts b/node/src/commands/BitmapIndexType.ts deleted file mode 100644 index 137c1d79f4..0000000000 --- a/node/src/commands/BitmapIndexType.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0 - */ - -// Imports below added to fix up the TSdoc links, but eslint complains about unused imports. -/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ -import { BaseClient } from "src/BaseClient"; -/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ -import { BitOffsetOptions } from "src/commands/BitOffsetOptions"; - -/** - * Enumeration specifying if index arguments are BYTE indexes or BIT indexes. - * Can be specified in {@link BitOffsetOptions}, which is an optional argument to the {@link BaseClient.bitcount|bitcount} command. - * Can also be specified as an optional argument to the {@link BaseClient.bitposInverval|bitposInterval} command. - * - * since - Valkey version 7.0.0. - */ -export enum BitmapIndexType { - /** Specifies that provided indexes are byte indexes. */ - BYTE = "BYTE", - /** Specifies that provided indexes are bit indexes. */ - BIT = "BIT", -} diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index f32d9b93d0..9738b31bd0 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -10,6 +10,7 @@ import { expect, it } from "@jest/globals"; import { v4 as uuidv4 } from "uuid"; import { + BitmapIndexType, ClosingError, ExpireOptions, GlideClient, @@ -33,7 +34,6 @@ import { intoString, } from "./TestUtilities"; import { SingleNodeRoute } from "../build-ts/src/GlideClusterClient"; -import { BitmapIndexType } from "../build-ts/src/commands/BitmapIndexType"; import { BitOffsetOptions } from "../build-ts/src/commands/BitOffsetOptions"; import { LPosOptions } from "../build-ts/src/commands/LPosOptions"; import { GeospatialData } from "../build-ts/src/commands/geospatial/GeospatialData"; diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index a2fbdd3799..d75e9debda 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -10,6 +10,7 @@ import { gte } from "semver"; import { BaseClient, BaseClientConfiguration, + BitmapIndexType, ClusterTransaction, GeoUnit, GlideClient, @@ -21,7 +22,6 @@ import { ScoreFilter, Transaction, } from ".."; -import { BitmapIndexType } from "../build-ts/src/commands/BitmapIndexType"; import { BitOffsetOptions } from "../build-ts/src/commands/BitOffsetOptions"; import { FlushMode } from "../build-ts/src/commands/FlushMode"; import { GeospatialData } from "../build-ts/src/commands/geospatial/GeospatialData"; From e554b8e3ec697492fa62e4439f254c53d05dcf1c Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Thu, 25 Jul 2024 10:52:44 -0700 Subject: [PATCH 8/8] Add async keyword to command API Signed-off-by: aaron-congo --- node/src/BaseClient.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 9b84bb0d29..b6074ff00c 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1086,7 +1086,11 @@ export class BaseClient { * 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. * ``` */ - public bitpos(key: string, bit: number, start?: number): Promise { + public async bitpos( + key: string, + bit: number, + start?: number, + ): Promise { return this.createWritePromise(createBitPos(key, bit, start)); } @@ -1123,7 +1127,7 @@ export class BaseClient { * 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 bitposInterval( + public async bitposInterval( key: string, bit: number, start: number,