Skip to content

Commit

Permalink
Node: add BITPOS command (valkey-io#1998)
Browse files Browse the repository at this point in the history
  • Loading branch information
aaron-congo authored Jul 25, 2024
1 parent 1c70afb commit 4e7e7c3
Show file tree
Hide file tree
Showing 8 changed files with 315 additions and 23 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
* Node: Added LMOVE command ([#2002](https://github.com/valkey-io/valkey-glide/pull/2002))
* Node: Added GEOPOS command ([#1991](https://github.com/valkey-io/valkey-glide/pull/1991))
* 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 BITOP command ([#2012](https://github.com/valkey-io/valkey-glide/pull/2012))
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,
BitwiseOperation,
ConditionalChange,
GeoAddOptions,
Expand Down Expand Up @@ -130,8 +130,8 @@ function initialize() {
} = nativeBinding;

module.exports = {
BitOffsetOptions,
BitmapIndexType,
BitOffsetOptions,
BitwiseOperation,
ConditionalChange,
GeoAddOptions,
Expand Down
79 changes: 79 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as net from "net";
import { Buffer, BufferWriter, Reader, Writer } from "protobufjs";
import {
AggregationType,
BitmapIndexType,
BitwiseOperation,
ExpireOptions,
GeoUnit,
Expand All @@ -32,6 +33,7 @@ import {
createBRPop,
createBitCount,
createBitOp,
createBitPos,
createDecr,
createDecrBy,
createDel,
Expand Down Expand Up @@ -1062,6 +1064,83 @@ 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 async 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 async bitposInterval(
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
41 changes: 41 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1706,6 +1706,47 @@ 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
*/
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);
}

export type StreamReadOptions = {
/**
* If set, the read request will block for the set amount of milliseconds or
Expand Down
55 changes: 55 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {
AggregationType,
BitmapIndexType,
BitwiseOperation,
ExpireOptions,
GeoUnit,
Expand All @@ -26,6 +27,7 @@ import {
createBRPop,
createBitCount,
createBitOp,
createBitPos,
createClientGetName,
createClientId,
createConfigGet,
Expand Down Expand Up @@ -455,6 +457,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(
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 "src/Commands";

/**
* Represents offsets specifying a string interval to analyze in the {@link BaseClient.bitcount|bitcount} command. The offsets are
Expand Down
Loading

0 comments on commit 4e7e7c3

Please sign in to comment.