Skip to content

Commit

Permalink
Node: Add binary api for bitmap commands (#2178)
Browse files Browse the repository at this point in the history
* Node: Add binary api for bitmap commands

Signed-off-by: Andrew Carbonetto <[email protected]>
  • Loading branch information
acarbonetto authored Aug 23, 2024
1 parent 1bb9b13 commit 3131719
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 34 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#### Changes
* Node: Added binary variant to bitmap commands ([#2178](https://github.com/valkey-io/valkey-glide/pull/2178))
* Node: Added binary variant to generic commands ([#2158](https://github.com/valkey-io/valkey-glide/pull/2158))
* Node: Added binary variant to geo commands ([#2149](https://github.com/valkey-io/valkey-glide/pull/2149))
* Node: Added binary variant to HYPERLOGLOG commands ([#2176](https://github.com/valkey-io/valkey-glide/pull/2176))
Expand Down
18 changes: 9 additions & 9 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1383,8 +1383,8 @@ export class BaseClient {
*/
public async bitop(
operation: BitwiseOperation,
destination: string,
keys: string[],
destination: GlideString,
keys: GlideString[],
): Promise<number> {
return this.createWritePromise(
createBitOp(operation, destination, keys),
Expand All @@ -1408,7 +1408,7 @@ export class BaseClient {
* console.log(result); // Output: 1 - The second bit of the string stored at "key" is set to 1.
* ```
*/
public async getbit(key: string, offset: number): Promise<number> {
public async getbit(key: GlideString, offset: number): Promise<number> {
return this.createWritePromise(createGetBit(key, offset));
}

Expand All @@ -1432,7 +1432,7 @@ export class BaseClient {
* ```
*/
public async setbit(
key: string,
key: GlideString,
offset: number,
value: number,
): Promise<number> {
Expand Down Expand Up @@ -1464,7 +1464,7 @@ export class BaseClient {
* ```
*/
public async bitpos(
key: string,
key: GlideString,
bit: number,
start?: number,
): Promise<number> {
Expand Down Expand Up @@ -1505,7 +1505,7 @@ export class BaseClient {
* ```
*/
public async bitposInterval(
key: string,
key: GlideString,
bit: number,
start: number,
end: number,
Expand Down Expand Up @@ -1548,7 +1548,7 @@ export class BaseClient {
* ```
*/
public async bitfield(
key: string,
key: GlideString,
subcommands: BitFieldSubCommands[],
): Promise<(number | null)[]> {
return this.createWritePromise(createBitField(key, subcommands));
Expand All @@ -1572,7 +1572,7 @@ export class BaseClient {
* ```
*/
public async bitfieldReadOnly(
key: string,
key: GlideString,
subcommands: BitFieldGet[],
): Promise<number[]> {
return this.createWritePromise(createBitField(key, subcommands, true));
Expand Down Expand Up @@ -5750,7 +5750,7 @@ export class BaseClient {
* ```
*/
public async bitcount(
key: string,
key: GlideString,
options?: BitOffsetOptions,
): Promise<number> {
return this.createWritePromise(createBitCount(key, options));
Expand Down
18 changes: 9 additions & 9 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,8 @@ export enum BitwiseOperation {
*/
export function createBitOp(
operation: BitwiseOperation,
destination: string,
keys: string[],
destination: GlideString,
keys: GlideString[],
): command_request.Command {
return createCommand(RequestType.BitOp, [operation, destination, ...keys]);
}
Expand All @@ -500,7 +500,7 @@ export function createBitOp(
* @internal
*/
export function createGetBit(
key: string,
key: GlideString,
offset: number,
): command_request.Command {
return createCommand(RequestType.GetBit, [key, offset.toString()]);
Expand All @@ -510,7 +510,7 @@ export function createGetBit(
* @internal
*/
export function createSetBit(
key: string,
key: GlideString,
offset: number,
value: number,
): command_request.Command {
Expand Down Expand Up @@ -799,14 +799,14 @@ export class BitFieldOverflow implements BitFieldSubCommands {
* @internal
*/
export function createBitField(
key: string,
key: GlideString,
subcommands: BitFieldSubCommands[],
readOnly: boolean = false,
): command_request.Command {
const requestType = readOnly
? RequestType.BitFieldReadOnly
: RequestType.BitField;
let args: string[] = [key];
let args: GlideString[] = [key];

for (const subcommand of subcommands) {
args = args.concat(subcommand.toArgs());
Expand Down Expand Up @@ -2438,7 +2438,7 @@ export type BitOffsetOptions = {
* @internal
*/
export function createBitCount(
key: string,
key: GlideString,
options?: BitOffsetOptions,
): command_request.Command {
const args = [key];
Expand Down Expand Up @@ -2470,13 +2470,13 @@ export enum BitmapIndexType {
* @internal
*/
export function createBitPos(
key: string,
key: GlideString,
bit: number,
start?: number,
end?: number,
indexType?: BitmapIndexType,
): command_request.Command {
const args = [key, bit.toString()];
const args: GlideString[] = [key, bit.toString()];

if (start !== undefined) {
args.push(start.toString());
Expand Down
18 changes: 9 additions & 9 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,8 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
*/
public bitop(
operation: BitwiseOperation,
destination: string,
keys: string[],
destination: GlideString,
keys: GlideString[],
): T {
return this.addAndReturn(createBitOp(operation, destination, keys));
}
Expand All @@ -630,7 +630,7 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* Command Response - The bit at the given `offset` of the string. Returns `0` if the key is empty or if the
* `offset` exceeds the length of the string.
*/
public getbit(key: string, offset: number): T {
public getbit(key: GlideString, offset: number): T {
return this.addAndReturn(createGetBit(key, offset));
}

Expand All @@ -648,7 +648,7 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
*
* Command Response - The bit value that was previously stored at `offset`.
*/
public setbit(key: string, offset: number, value: number): T {
public setbit(key: GlideString, offset: number, value: number): T {
return this.addAndReturn(createSetBit(key, offset, value));
}

Expand All @@ -667,7 +667,7 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* 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 {
public bitpos(key: GlideString, bit: number, start?: number): T {
return this.addAndReturn(createBitPos(key, bit, start));
}

Expand Down Expand Up @@ -696,7 +696,7 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* binary value of the string held at `key`.
*/
public bitposInterval(
key: string,
key: GlideString,
bit: number,
start: number,
end: number,
Expand Down Expand Up @@ -729,7 +729,7 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* subcommands when an overflow or underflow occurs. {@link BitFieldOverflow} does not return a value and
* does not contribute a value to the array response.
*/
public bitfield(key: string, subcommands: BitFieldSubCommands[]): T {
public bitfield(key: GlideString, subcommands: BitFieldSubCommands[]): T {
return this.addAndReturn(createBitField(key, subcommands));
}

Expand All @@ -745,7 +745,7 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* Command Response - An array of results from the {@link BitFieldGet} subcommands.
*
*/
public bitfieldReadOnly(key: string, subcommands: BitFieldGet[]): T {
public bitfieldReadOnly(key: GlideString, subcommands: BitFieldGet[]): T {
return this.addAndReturn(createBitField(key, subcommands, true));
}

Expand Down Expand Up @@ -3364,7 +3364,7 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
* 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.
*/
public bitcount(key: string, options?: BitOffsetOptions): T {
public bitcount(key: GlideString, options?: BitOffsetOptions): T {
return this.addAndReturn(createBitCount(key, options));
}

Expand Down
25 changes: 18 additions & 7 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ export function runBaseTests(config: {
const key2 = `{key}-${uuidv4()}`;
const key3 = `{key}-${uuidv4()}`;
const keys = [key1, key2];
const keysEncoded = [Buffer.from(key1), Buffer.from(key2)];
const destination = `{key}-${uuidv4()}`;
const nonExistingKey1 = `{key}-${uuidv4()}`;
const nonExistingKey2 = `{key}-${uuidv4()}`;
Expand All @@ -611,7 +612,11 @@ export function runBaseTests(config: {
).toEqual(6);
expect(await client.get(destination)).toEqual("`bc`ab");
expect(
await client.bitop(BitwiseOperation.OR, destination, keys),
await client.bitop(
BitwiseOperation.OR,
destination,
keysEncoded,
),
).toEqual(6);
expect(await client.get(destination)).toEqual("goofev");

Expand Down Expand Up @@ -725,7 +730,7 @@ export function runBaseTests(config: {
expect(await client.set(key, "foo")).toEqual("OK");
expect(await client.getbit(key, 1)).toEqual(1);
// When offset is beyond the string length, the string is assumed to be a contiguous space with 0 bits.
expect(await client.getbit(key, 1000)).toEqual(0);
expect(await client.getbit(Buffer.from(key), 1000)).toEqual(0);
// When key does not exist it is assumed to be an empty string, so offset is always out of range and the
// value is also assumed to be a contiguous space with 0 bits.
expect(await client.getbit(nonExistingKey, 1)).toEqual(0);
Expand Down Expand Up @@ -753,7 +758,7 @@ export function runBaseTests(config: {
const setKey = `{key}-${uuidv4()}`;

expect(await client.setbit(key, 1, 1)).toEqual(0);
expect(await client.setbit(key, 1, 0)).toEqual(1);
expect(await client.setbit(Buffer.from(key), 1, 0)).toEqual(1);

// invalid argument - offset can't be negative
await expect(client.setbit(key, -1, 1)).rejects.toThrow(
Expand Down Expand Up @@ -786,9 +791,12 @@ export function runBaseTests(config: {

expect(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(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.bitposInterval(Buffer.from(key), 0, 3, 5),
).toEqual(24);

// -1 is returned if start > end
expect(await client.bitposInterval(key, 0, 1, 0)).toEqual(-1);
Expand Down Expand Up @@ -947,7 +955,7 @@ export function runBaseTests(config: {

// INCRBY tests
expect(
await client.bitfield(key1, [
await client.bitfield(Buffer.from(key1), [
// binary value becomes:
// 0(11)00011 01101111 01101111 01100010 01000001 01110010 00000000 00000000 00010100
new BitFieldIncrBy(u2, offset1, 1),
Expand Down Expand Up @@ -1104,7 +1112,7 @@ export function runBaseTests(config: {
// offset is greater than current length of string: the operation is performed like the missing part all
// consists of bits set to 0.
expect(
await client.bitfieldReadOnly(key, [
await client.bitfieldReadOnly(Buffer.from(key), [
new BitFieldGet(
new UnsignedEncoding(3),
new BitOffset(100),
Expand Down Expand Up @@ -7884,7 +7892,10 @@ export function runBaseTests(config: {
expect(await client.set(key1, value)).toEqual("OK");
expect(await client.bitcount(key1)).toEqual(26);
expect(
await client.bitcount(key1, { start: 1, end: 1 }),
await client.bitcount(Buffer.from(key1), {
start: 1,
end: 1,
}),
).toEqual(6);
expect(
await client.bitcount(key1, { start: 0, end: -5 }),
Expand Down

0 comments on commit 3131719

Please sign in to comment.