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 GETBIT command #1989

Merged
merged 1 commit into from
Jul 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 BITCOUNT command ([#1982](https://github.com/valkey-io/valkey-glide/pull/1982))
* 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))
* Node: Added SETBIT command ([#1978](https://github.com/valkey-io/valkey-glide/pull/1978))
* Node: Added LPUSHX and RPUSHX command([#1959](https://github.com/valkey-io/valkey-glide/pull/1959))
* Node: Added LSET command ([#1952](https://github.com/valkey-io/valkey-glide/pull/1952))
Expand Down
22 changes: 22 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import {
createExpireAt,
createGeoAdd,
createGet,
createGetBit,
createGetDel,
createHDel,
createHExists,
Expand Down Expand Up @@ -972,6 +973,27 @@ export class BaseClient {
return this.createWritePromise(createDecrBy(key, amount));
}

/**
* Returns the bit value at `offset` in the string value stored at `key`. `offset` must be greater than or equal
* to zero.
*
* See https://valkey.io/commands/getbit/ for more details.
*
* @param key - The key of the string.
* @param offset - The index of the bit to return.
* @returns 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.
*
* @example
* ```typescript
* const result = await client.getbit("key", 1);
* console.log(result); // Output: 1 - The second bit of the string stored at "key" is set to 1.
* ```
*/
public getbit(key: string, offset: number): Promise<number> {
return this.createWritePromise(createGetBit(key, offset));
}

/**
* Sets or clears the bit at `offset` in the string value stored at `key`. The `offset` is a zero-based index, with
* `0` being the first element of the list, `1` being the next element, and so on. The `offset` must be less than
Expand Down
10 changes: 10 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,16 @@ export function createDecrBy(
return createCommand(RequestType.DecrBy, [key, amount.toString()]);
}

/**
* @internal
*/
export function createGetBit(
key: string,
offset: number,
): command_request.Command {
return createCommand(RequestType.GetBit, [key, offset.toString()]);
}

/**
* @internal
*/
Expand Down
17 changes: 17 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import {
createFunctionLoad,
createGeoAdd,
createGet,
createGetBit,
createGetDel,
createHDel,
createHExists,
Expand Down Expand Up @@ -387,6 +388,22 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
return this.addAndReturn(createDecrBy(key, amount));
}

/**
* Returns the bit value at `offset` in the string value stored at `key`. `offset` must be greater than or equal
* to zero.
*
* See https://valkey.io/commands/getbit/ for more details.
*
* @param key - The key of the string.
* @param offset - The index of the bit to return.
*
* 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 {
return this.addAndReturn(createGetBit(key, offset));
}

/**
* Sets or clears the bit at `offset` in the string value stored at `key`. The `offset` is a zero-based index, with
* `0` being the first element of the list, `1` being the next element, and so on. The `offset` must be less than
Expand Down
37 changes: 34 additions & 3 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,12 +495,43 @@ export function runBaseTests<Context>(config: {
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`getbit test_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key = `{key}-${uuidv4()}`;
const nonExistingKey = `{key}-${uuidv4()}`;
const setKey = `{key}-${uuidv4()}`;

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);
// 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);

// invalid argument - offset can't be negative
await expect(client.getbit(key, -1)).rejects.toThrow(
RequestError,
);

// key exists, but it is not a string
expect(await client.sadd(setKey, ["foo"])).toEqual(1);
await expect(client.getbit(setKey, 0)).rejects.toThrow(
RequestError,
);
}, protocol);
},
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
`setbit test_%p`,
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key = `{key}-${uuidv4()}`;
const stringKey = `{key}-${uuidv4()}`;
const setKey = `{key}-${uuidv4()}`;

expect(await client.setbit(key, 1, 1)).toEqual(0);
expect(await client.setbit(key, 1, 0)).toEqual(1);
Expand All @@ -516,8 +547,8 @@ export function runBaseTests<Context>(config: {
);

// key exists, but it is not a string
expect(await client.sadd(stringKey, ["foo"])).toEqual(1);
await expect(client.setbit(stringKey, 0, 0)).rejects.toThrow(
expect(await client.sadd(setKey, ["foo"])).toEqual(1);
await expect(client.setbit(setKey, 0, 0)).rejects.toThrow(
RequestError,
);
}, protocol);
Expand Down
2 changes: 2 additions & 0 deletions node/tests/TestUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,8 @@ export async function transactionTest(

baseTransaction.setbit(key17, 1, 1);
args.push(0);
baseTransaction.getbit(key17, 1);
args.push(1);
baseTransaction.set(key17, "foobar");
args.push("OK");
baseTransaction.bitcount(key17);
Expand Down
Loading