Skip to content

Commit

Permalink
Node: Add command SetRange
Browse files Browse the repository at this point in the history
Signed-off-by: TJ Zhang <[email protected]>
  • Loading branch information
TJ Zhang committed Aug 1, 2024
1 parent 54cfb74 commit 9832951
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
* Node: Added ZLEXCOUNT command ([#2022](https://github.com/valkey-io/valkey-glide/pull/2022))
* Node: Added ZREMRANGEBYLEX command ([#2025]((https://github.com/valkey-io/valkey-glide/pull/2025))
* Node: Added ZSCAN command ([#2061](https://github.com/valkey-io/valkey-glide/pull/2061))
* Node: Added SETRANGE command ([#2066](https://github.com/valkey-io/valkey-glide/pull/2066))

#### Breaking Changes
* Node: (Refactor) Convert classes to types ([#2005](https://github.com/valkey-io/valkey-glide/pull/2005))
Expand Down
29 changes: 29 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ import {
createSUnionStore,
createSet,
createSetBit,
createSetRange,
createStrlen,
createTTL,
createTouch,
Expand Down Expand Up @@ -4464,6 +4465,34 @@ export class BaseClient {
return this.createWritePromise(createTouch(keys));
}

/**
* Overwrites part of the string stored at `key`, starting at the specified `offset`,
* for the entire length of `value`. If the `offset` is larger than the current length of the string at `key`,
* the string is padded with zero bytes to make `offset` fit. Creates the `key` if it doesn't exist.
*
* See https://valkey.io/commands/setrange/ for more details.
*
* @param key - The key of the string to update.
* @param offset - The position in the string where `value` should be written.
* @param value - The string written with `offset`.
* @returns The length of the string stored at `key` after it was modified.
*
* @example
* ```typescript
* const len = await client.setrange("key", 6, "GLIDE");
* console.log(len); // Output: 11 - New key was created with length of 11 symbols
* const value = await client.get("key");
* console.log(result); // Output: "\0\0\0\0\0\0GLIDE" - The string was padded with zero bytes
* ```
*/
public async setrange(
key: string,
offset: number,
value: string,
): Promise<number> {
return this.createWritePromise(createSetRange(key, offset, value));
}

/**
* @internal
*/
Expand Down
9 changes: 9 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3044,3 +3044,12 @@ export function createZScan(

return createCommand(RequestType.ZScan, args);
}

/** @internal */
export function createSetRange(
key: string,
offset: number,
value: string,
): command_request.Command {
return createCommand(RequestType.SetRange, [key, offset.toString(), value]);
}
18 changes: 18 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ import {
createSelect,
createSet,
createSetBit,
createSetRange,
createSort,
createSortReadOnly,
createStrlen,
Expand Down Expand Up @@ -2694,6 +2695,23 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
public randomKey(): T {
return this.addAndReturn(createRandomKey());
}

/**
* Overwrites part of the string stored at `key`, starting at the specified `offset`,
* for the entire length of `value`. If the `offset` is larger than the current length of the string at `key`,
* the string is padded with zero bytes to make `offset` fit. Creates the `key` if it doesn't exist.
*
* See https://valkey.io/commands/setrange/ for more details.
*
* @param key - The key of the string to update.
* @param offset - The position in the string where `value` should be written.
* @param value - The string written with `offset`.
*
* Command Response - The length of the string stored at `key` after it was modified.
*/
public setrange(key: string, offset: number, value: string): T {
return this.addAndReturn(createSetRange(key, offset, value));
}
}

/**
Expand Down
30 changes: 30 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4659,6 +4659,36 @@ export function runBaseTests<Context>(config: {
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
"setrange test_%p",
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key = uuidv4();
const nonStringKey = uuidv4();

// new key
expect(await client.setrange(key, 0, "Hello World")).toBe(11);

// existing key
expect(await client.setrange(key, 6, "GLIDE")).toBe(11);
expect(await client.get(key)).toEqual("Hello GLIDE");

// offset > len
expect(await client.setrange(key, 15, "GLIDE")).toBe(20);
expect(await client.get(key)).toEqual(
"Hello GLIDE\0\0\0\0GLIDE",
);

// non-string key
expect(await client.lpush(nonStringKey, ["_"])).toBe(1);
await expect(
client.setrange(nonStringKey, 0, "_"),
).rejects.toThrow(RequestError);
}, protocol);
},
config.timeout,
);

// Set command tests

async function setWithExpiryOptions(client: BaseClient) {
Expand Down
2 changes: 2 additions & 0 deletions node/tests/TestUtilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,8 @@ export async function transactionTest(
responseData.push(["mget([key1, key2])", ["bar", "baz"]]);
baseTransaction.strlen(key1);
responseData.push(["strlen(key1)", 3]);
baseTransaction.setrange(key1, 0, "GLIDE");
responseData.push(["setrange(key1, 0, 'GLIDE'", 5]);
baseTransaction.del([key1]);
responseData.push(["del([key1])", 1]);
baseTransaction.hset(key4, { [field]: value });
Expand Down

0 comments on commit 9832951

Please sign in to comment.