Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Node: add BITPOS command #1998

Merged
merged 11 commits into from
Jul 25, 2024
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#### Changes
* Node: Added GEOPOS command ([#1991](https:/valkey-io/valkey-glide/pull/1991))
* Node: Added BITCOUNT command ([#1982](https:/valkey-io/valkey-glide/pull/1982))
* Node: Added BITPOS command ([#1998](https:/valkey-io/valkey-glide/pull/1998))
* Node: Added FLUSHDB command ([#1986](https:/valkey-io/valkey-glide/pull/1986))
* Node: Added GETDEL command ([#1968](https:/valkey-io/valkey-glide/pull/1968))
* Node: Added GETBIT command ([#1989](https:/valkey-io/valkey-glide/pull/1989))
Expand Down
4 changes: 2 additions & 2 deletions node/npm/glide/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ function loadNativeBinding() {
function initialize() {
const nativeBinding = loadNativeBinding();
const {
BitOffsetOptions,
BitmapIndexType,
BitOffsetOptions,
aaron-congo marked this conversation as resolved.
Show resolved Hide resolved
ConditionalChange,
GeoAddOptions,
GeospatialData,
Expand Down Expand Up @@ -128,8 +128,8 @@ function initialize() {
} = nativeBinding;

module.exports = {
BitOffsetOptions,
BitmapIndexType,
BitOffsetOptions,
ConditionalChange,
GeoAddOptions,
GeospatialData,
Expand Down
75 changes: 75 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
createBLPop,
createBRPop,
createBitCount,
createBitPos,
createDecr,
createDecrBy,
createDel,
Expand Down Expand Up @@ -131,6 +132,7 @@ 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";
Expand Down Expand Up @@ -1023,6 +1025,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 - (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.
*
* 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<number> {
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 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 - (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 bitposInterval(
aaron-congo marked this conversation as resolved.
Show resolved Hide resolved
Yury-Fridlyand marked this conversation as resolved.
Show resolved Hide resolved
key: string,
bit: number,
start: number,
end: number,
indexType?: BitmapIndexType,
): Promise<number> {
return this.createWritePromise(
createBitPos(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.
*
Expand Down
28 changes: 28 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -1616,6 +1617,33 @@ export function createBitCount(
return createCommand(RequestType.BitCount, args);
}

/**
* @internal
*/
export function createBitPos(
key: string,
bit: number,
start?: number,
end?: number,
indexType?: BitmapIndexType,
): command_request.Command {
const args = [key, bit.toString()];

if (start !== undefined) {
args.push(start.toString());
}

if (end !== undefined) {
args.push(end.toString());
}

if (indexType) {
args.push(indexType);
}

return createCommand(RequestType.BitPos, args);
}

/**
* @internal
*/
Expand Down
55 changes: 55 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
createBLPop,
createBRPop,
createBitCount,
createBitPos,
createClientGetName,
createClientId,
createConfigGet,
Expand Down Expand Up @@ -145,6 +146,7 @@ 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";
Expand Down Expand Up @@ -429,6 +431,59 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
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 - (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`.
*/
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 `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 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 - (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(
aaron-congo marked this conversation as resolved.
Show resolved Hide resolved
key: string,
bit: number,
start: number,
end: number,
indexType?: BitmapIndexType,
): T {
return this.addAndReturn(createBitPos(key, bit, start, end, indexType));
}

/** Reads the configuration parameters of a running Redis server.
* See https://valkey.io/commands/config-get/ for details.
*
Expand Down
14 changes: 1 addition & 13 deletions node/src/commands/BitOffsetOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 23 additions & 0 deletions node/src/commands/BitmapIndexType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* 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.
aaron-congo marked this conversation as resolved.
Show resolved Hide resolved
* 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",
}
Loading
Loading