From 5bef4dfe02fd26bbe5c58013d1f8442ef59177dd Mon Sep 17 00:00:00 2001 From: Aaron <69273634+aaron-congo@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:45:30 -0700 Subject: [PATCH] Node: add SETBIT command (#1978) * Node: add SETBIT command Signed-off-by: aaron-congo --- CHANGELOG.md | 1 + node/src/BaseClient.ts | 24 ++++++++++++++++++++++++ node/src/Commands.ts | 15 +++++++++++++++ node/src/Transaction.ts | 19 +++++++++++++++++++ node/tests/SharedTests.ts | 30 ++++++++++++++++++++++++++++++ node/tests/TestUtilities.ts | 5 +++++ 6 files changed, 94 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c4fb488db..5538bba0aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ #### Changes * Node: Added GETDEL command ([#1968](https://github.com/valkey-io/valkey-glide/pull/1968)) +* 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)) * Node: Added SDIFFSTORE command ([#1931](https://github.com/valkey-io/valkey-glide/pull/1931)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index fc6a5af580..83156ec2bd 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -81,6 +81,7 @@ import { createSCard, createSDiff, createSDiffStore, + createSetBit, createSInter, createSInterCard, createSInterStore, @@ -962,6 +963,29 @@ export class BaseClient { return this.createWritePromise(createDecrBy(key, amount)); } + /** + * 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 + * `2^32` and greater than or equal to `0`. If a key is non-existent then the bit at `offset` is set to `value` and + * the preceding bits are set to `0`. + * + * See https://valkey.io/commands/setbit/ for more details. + * + * @param key - The key of the string. + * @param offset - The index of the bit to be set. + * @param value - The bit value to set at `offset`. The value must be `0` or `1`. + * @returns The bit value that was previously stored at `offset`. + * + * @example + * ```typescript + * const result = await client.setbit("key", 1, 1); + * console.log(result); // Output: 0 - The second bit value was 0 before setting to 1. + * ``` + */ + public setbit(key: string, offset: number, value: number): Promise { + return this.createWritePromise(createSetBit(key, offset, value)); + } + /** Retrieve the value associated with `field` in the hash stored at `key`. * See https://valkey.io/commands/hget/ for details. * diff --git a/node/src/Commands.ts b/node/src/Commands.ts index f36e4949e6..a280beb159 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -442,6 +442,21 @@ export function createDecrBy( return createCommand(RequestType.DecrBy, [key, amount.toString()]); } +/** + * @internal + */ +export function createSetBit( + key: string, + offset: number, + value: number, +): command_request.Command { + return createCommand(RequestType.SetBit, [ + key, + offset.toString(), + value.toString(), + ]); +} + /** * @internal */ diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index faea761508..059c01988e 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -89,6 +89,7 @@ import { createSCard, createSDiff, createSDiffStore, + createSetBit, createSInter, createSInterCard, createSInterStore, @@ -375,6 +376,24 @@ export class BaseTransaction> { return this.addAndReturn(createDecrBy(key, amount)); } + /** + * 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 + * `2^32` and greater than or equal to `0`. If a key is non-existent then the bit at `offset` is set to `value` and + * the preceding bits are set to `0`. + * + * See https://valkey.io/commands/setbit/ for more details. + * + * @param key - The key of the string. + * @param offset - The index of the bit to be set. + * @param value - The bit value to set at `offset`. The value must be `0` or `1`. + * + * Command Response - The bit value that was previously stored at `offset`. + */ + public setbit(key: string, offset: number, value: number): T { + return this.addAndReturn(createSetBit(key, offset, value)); + } + /** Reads the configuration parameters of a running Redis server. * See https://valkey.io/commands/config-get/ for details. * diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 0ae1c7b4bd..16cd7b5246 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -488,6 +488,36 @@ export function runBaseTests(config: { 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()}`; + + expect(await client.setbit(key, 1, 1)).toEqual(0); + expect(await client.setbit(key, 1, 0)).toEqual(1); + + // invalid argument - offset can't be negative + await expect(client.setbit(key, -1, 1)).rejects.toThrow( + RequestError, + ); + + // invalid argument - "value" arg must be 0 or 1 + await expect(client.setbit(key, 0, 2)).rejects.toThrow( + RequestError, + ); + + // 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( + RequestError, + ); + }, protocol); + }, + config.timeout, + ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `config get and config set with timeout parameter_%p`, async (protocol) => { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 2724615b6d..78a84ad2ab 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -350,6 +350,7 @@ export async function transactionTest( const key14 = "{key}" + uuidv4(); // sorted set const key15 = "{key}" + uuidv4(); // list const key16 = "{key}" + uuidv4(); // list + const key17 = "{key}" + uuidv4(); // bitmap const field = uuidv4(); const value = uuidv4(); const args: ReturnType[] = []; @@ -604,6 +605,10 @@ export async function transactionTest( args.push([key6, field + "3"]); baseTransaction.blpop([key6], 0.1); args.push([key6, field + "1"]); + + baseTransaction.setbit(key17, 1, 1); + args.push(0); + baseTransaction.pfadd(key11, ["a", "b", "c"]); args.push(1); baseTransaction.pfcount([key11]);