Skip to content

Commit

Permalink
Node: Add binary api for bitmap commands
Browse files Browse the repository at this point in the history
Signed-off-by: Andrew Carbonetto <[email protected]>
  • Loading branch information
acarbonetto committed Aug 21, 2024
1 parent 56dead0 commit 3924035
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 34 deletions.
18 changes: 9 additions & 9 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1377,8 +1377,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 @@ -1402,7 +1402,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 @@ -1426,7 +1426,7 @@ export class BaseClient {
* ```
*/
public async setbit(
key: string,
key: GlideString,
offset: number,
value: number,
): Promise<number> {
Expand Down Expand Up @@ -1458,7 +1458,7 @@ export class BaseClient {
* ```
*/
public async bitpos(
key: string,
key: GlideString,
bit: number,
start?: number,
): Promise<number> {
Expand Down Expand Up @@ -1499,7 +1499,7 @@ export class BaseClient {
* ```
*/
public async bitposInterval(
key: string,
key: GlideString,
bit: number,
start: number,
end: number,
Expand Down Expand Up @@ -1542,7 +1542,7 @@ export class BaseClient {
* ```
*/
public async bitfield(
key: string,
key: GlideString,
subcommands: BitFieldSubCommands[],
): Promise<(number | null)[]> {
return this.createWritePromise(createBitField(key, subcommands));
Expand All @@ -1566,7 +1566,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 @@ -5675,7 +5675,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 @@ -472,8 +472,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 @@ -482,7 +482,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 @@ -492,7 +492,7 @@ export function createGetBit(
* @internal
*/
export function createSetBit(
key: string,
key: GlideString,
offset: number,
value: number,
): command_request.Command {
Expand Down Expand Up @@ -781,14 +781,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 @@ -2418,7 +2418,7 @@ export type BitOffsetOptions = {
* @internal
*/
export function createBitCount(
key: string,
key: GlideString,
options?: BitOffsetOptions,
): command_request.Command {
const args = [key];
Expand Down Expand Up @@ -2450,13 +2450,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 @@ -610,8 +610,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 @@ -628,7 +628,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 @@ -646,7 +646,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 @@ -665,7 +665,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 @@ -694,7 +694,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 @@ -727,7 +727,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 @@ -743,7 +743,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 @@ -3333,7 +3333,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 @@ -586,6 +586,7 @@ export function runBaseTests(config: {
const key2 = `{key}-${uuidv4()}`;
const key3 = `{key}-${uuidv4()}`;
const keys = [key1, key2];
const binaryEncoded = [Buffer.from(key1), Buffer.from(key2)];
const destination = `{key}-${uuidv4()}`;
const nonExistingKey1 = `{key}-${uuidv4()}`;
const nonExistingKey2 = `{key}-${uuidv4()}`;
Expand All @@ -606,7 +607,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,
binaryEncoded,
),
).toEqual(6);
expect(await client.get(destination)).toEqual("goofev");

Expand Down Expand Up @@ -720,7 +725,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 @@ -748,7 +753,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 @@ -781,9 +786,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 @@ -942,7 +950,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 @@ -1099,7 +1107,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 @@ -7697,7 +7705,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 3924035

Please sign in to comment.