From 2f97fa9fcb073c72aec728162f59cab4a205c700 Mon Sep 17 00:00:00 2001 From: TJ Zhang Date: Thu, 25 Jul 2024 14:19:20 -0700 Subject: [PATCH 1/4] Add command HStrlen Signed-off-by: TJ Zhang --- CHANGELOG.md | 1 + node/src/BaseClient.ts | 22 ++++++++++++++++++++++ node/src/Commands.ts | 10 ++++++++++ node/src/Transaction.ts | 15 +++++++++++++++ node/tests/SharedTests.ts | 25 +++++++++++++++++++++++++ node/tests/TestUtilities.ts | 2 ++ 6 files changed, 75 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 10e2e3cf99..9c129c304c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -131,6 +131,7 @@ * Node: Added ZRevRank command ([#1977](https://github.com/valkey-io/valkey-glide/pull/1977)) * Node: Added GeoDist command ([#1988](https://github.com/valkey-io/valkey-glide/pull/1988)) * Node: Added GeoHash command ([#1997](https://github.com/valkey-io/valkey-glide/pull/1997)) +* Node: Added HStrlen command ([#2020](https://github.com/valkey-io/valkey-glide/pull/2020)) #### Breaking Changes * Node: Update XREAD to return a Map of Map ([#1494](https://github.com/valkey-io/valkey-glide/pull/1494)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index ef25d8be0e..6a833c6654 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -64,6 +64,7 @@ import { createHMGet, createHSet, createHSetNX, + createHStrlen, createHVals, createIncr, createIncrBy, @@ -1393,6 +1394,27 @@ export class BaseClient { return this.createWritePromise(createHVals(key)); } + /** + * Returns the string length of the value associated with `field` in the hash stored at `key`. + * + * See https://valkey.io/commands/hget/ for details. + * + * @param key - The key of the hash. + * @param field - The field in the hash. + * @returns The string length or `0` if `field` or `key` does not exist. + * + * @example + * ```typescript + * // Example usage of the hget method on an-existing field + * await client.hset("my_hash", "field", "value"); + * const result = await client.hstrlen("my_hash", "field"); + * console.log(result); // Output: 5 + * ``` + */ + public hstrlen(key: string, field: string): Promise { + return this.createWritePromise(createHStrlen(key, field)); + } + /** Inserts all the specified values at the head of the list stored at `key`. * `elements` are inserted one after the other to the head of the list, from the leftmost element to the rightmost element. * If `key` does not exist, it is created as empty list before performing the push operations. diff --git a/node/src/Commands.ts b/node/src/Commands.ts index 4c1c6254c3..d67e6031f9 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -2249,3 +2249,13 @@ export function createZIncrBy( member, ]); } + +/** + * @internal + */ +export function createHStrlen( + key: string, + field: string, +): command_request.Command { + return createCommand(RequestType.HStrlen, [key, field]); +} diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index b945655cbb..6e787bfa47 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -73,6 +73,7 @@ import { createHMGet, createHSet, createHSetNX, + createHStrlen, createHVals, createIncr, createIncrBy, @@ -680,6 +681,20 @@ export class BaseTransaction> { return this.addAndReturn(createHVals(key)); } + /** + * Returns the string length of the value associated with `field` in the hash stored at `key`. + * + * See https://valkey.io/commands/hget/ for details. + * + * @param key - The key of the hash. + * @param field - The field in the hash. + * + * Command Response - The string length or `0` if `field` or `key` does not exist. + */ + public hstrlen(key: string, field: string): T { + return this.addAndReturn(createHStrlen(key, field)); + } + /** Inserts all the specified values at the head of the list stored at `key`. * `elements` are inserted one after the other to the head of the list, from the leftmost element to the rightmost element. * If `key` does not exist, it is created as empty list before performing the push operations. diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 81fb10e214..2f8998bcec 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -1102,6 +1102,31 @@ export function runBaseTests(config: { config.timeout, ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `hstrlen test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + const key1 = uuidv4(); + const key2 = uuidv4(); + const field = uuidv4(); + + expect(await client.hset(key1, { field: "value" })).toBe(1); + expect(await client.hstrlen(key1, "field")).toBe(5); + + // missing value + expect(await client.hstrlen(key1, "nonExistingField")).toBe(0); + + // missing key + expect(await client.hstrlen(key2, "field")).toBe(0); + + // key exists but holds non hash type value + checkSimple(await client.set(key2, "value")).toEqual("OK"); + await expect(client.hstrlen(key2, field)).rejects.toThrow(); + }, protocol); + }, + config.timeout, + ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( `lpush, lpop and lrange with existing and non existing key_%p`, async (protocol) => { diff --git a/node/tests/TestUtilities.ts b/node/tests/TestUtilities.ts index 17ce37c6f6..e589213359 100644 --- a/node/tests/TestUtilities.ts +++ b/node/tests/TestUtilities.ts @@ -439,6 +439,8 @@ export async function transactionTest( responseData.push(["del([key1])", 1]); baseTransaction.hset(key4, { [field]: value }); responseData.push(["hset(key4, { [field]: value })", 1]); + baseTransaction.hstrlen(key4, field); + responseData.push(["hstrlen(key4, field)", value.length]); baseTransaction.hlen(key4); responseData.push(["hlen(key4)", 1]); baseTransaction.hsetnx(key4, field, value); From 3b42098aec717f96a44c87f3fd14f7247fbff5f7 Mon Sep 17 00:00:00 2001 From: TJ Zhang Date: Fri, 26 Jul 2024 12:25:02 -0700 Subject: [PATCH 2/4] addressing comments Signed-off-by: TJ Zhang --- node/src/BaseClient.ts | 5 ++--- node/src/Transaction.ts | 2 +- node/tests/SharedTests.ts | 5 ++++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index 6a833c6654..636b352825 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -1397,7 +1397,7 @@ export class BaseClient { /** * Returns the string length of the value associated with `field` in the hash stored at `key`. * - * See https://valkey.io/commands/hget/ for details. + * See https://valkey.io/commands/hstrlen/ for details. * * @param key - The key of the hash. * @param field - The field in the hash. @@ -1405,8 +1405,7 @@ export class BaseClient { * * @example * ```typescript - * // Example usage of the hget method on an-existing field - * await client.hset("my_hash", "field", "value"); + * await client.hset("my_hash", {"field": "value"}); * const result = await client.hstrlen("my_hash", "field"); * console.log(result); // Output: 5 * ``` diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index 6e787bfa47..8c8f391b24 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -684,7 +684,7 @@ export class BaseTransaction> { /** * Returns the string length of the value associated with `field` in the hash stored at `key`. * - * See https://valkey.io/commands/hget/ for details. + * See https://valkey.io/commands/hstrlen/ for details. * * @param key - The key of the hash. * @param field - The field in the hash. diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 2f8998bcec..95c140e913 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -8,6 +8,7 @@ // represents a running server instance. See first 2 test cases as examples. import { expect, it } from "@jest/globals"; +import { RedisError } from "build-ts"; import { v4 as uuidv4 } from "uuid"; import { BitmapIndexType, @@ -1121,7 +1122,9 @@ export function runBaseTests(config: { // key exists but holds non hash type value checkSimple(await client.set(key2, "value")).toEqual("OK"); - await expect(client.hstrlen(key2, field)).rejects.toThrow(); + await expect(client.hstrlen(key2, field)).rejects.toThrow( + RedisError, + ); }, protocol); }, config.timeout, From a54e52d43abc566975adbdfd02cc492889bded60 Mon Sep 17 00:00:00 2001 From: TJ Zhang Date: Fri, 26 Jul 2024 12:33:46 -0700 Subject: [PATCH 3/4] fixing throw type Signed-off-by: TJ Zhang --- node/tests/SharedTests.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 95c140e913..1107a32ac2 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -1123,7 +1123,7 @@ export function runBaseTests(config: { // key exists but holds non hash type value checkSimple(await client.set(key2, "value")).toEqual("OK"); await expect(client.hstrlen(key2, field)).rejects.toThrow( - RedisError, + RequestError, ); }, protocol); }, From 368c385fca8f6e7353f037045808283474a9cd93 Mon Sep 17 00:00:00 2001 From: TJ Zhang Date: Fri, 26 Jul 2024 12:36:49 -0700 Subject: [PATCH 4/4] remove import Signed-off-by: TJ Zhang --- node/tests/SharedTests.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 1107a32ac2..3e1fba7147 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -8,7 +8,6 @@ // represents a running server instance. See first 2 test cases as examples. import { expect, it } from "@jest/globals"; -import { RedisError } from "build-ts"; import { v4 as uuidv4 } from "uuid"; import { BitmapIndexType,