From 0dde48b35b5de99598c0ae287758267c3bc6fa36 Mon Sep 17 00:00:00 2001 From: Shoham Elias <116083498+shohamazon@users.noreply.github.com> Date: Tue, 18 Jun 2024 10:44:45 +0300 Subject: [PATCH] Python: adds HSTRLEN command (#1564) --- CHANGELOG.md | 1 + python/python/glide/async_commands/core.py | 25 ++++++++++++++++++- .../glide/async_commands/transaction.py | 15 +++++++++++ python/python/tests/test_async_client.py | 15 +++++++++++ python/python/tests/test_transaction.py | 2 ++ 5 files changed, 57 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a6d92db95d..6d0bb11e3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ * Node: Added XLEN command ([#1555](https://github.com/aws/glide-for-redis/pull/1555)) * Node: Added ZINTERCARD command ([#1553](https://github.com/aws/glide-for-redis/pull/1553)) * Python: Added LMPOP and BLMPOP commands ([#1547](https://github.com/aws/glide-for-redis/pull/1547)) +* Python: Added HSTRLEN command ([#1564](https://github.com/aws/glide-for-redis/pull/1564)) * Python: Added MSETNX command ([#1565](https://github.com/aws/glide-for-redis/pull/1565)) * Python: Added MOVE command ([#1566](https://github.com/aws/glide-for-redis/pull/1566)) * Node: Added OBJECT IDLETIME command ([#1567](https://github.com/aws/glide-for-redis/pull/1567)) diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index 5625cbf3d4..5d2473f493 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -835,7 +835,7 @@ async def hget(self, key: str, field: str) -> Optional[str]: Returns None if `field` is not presented in the hash or `key` does not exist. Examples: - >>> await client.hset("my_hash", "field") + >>> await client.hset("my_hash", "field", "value") >>> await client.hget("my_hash", "field") "value" >>> await client.hget("my_hash", "nonexistent_field") @@ -1149,6 +1149,29 @@ async def hrandfield_withvalues(self, key: str, count: int) -> List[List[str]]: ), ) + async def hstrlen(self, key: str, field: str) -> int: + """ + Returns the string length of the value associated with `field` in the hash stored at `key`. + + See https://valkey.io/commands/hstrlen/ for more details. + + Args: + key (str): The key of the hash. + field (str): The field in the hash. + + Returns: + int: The string length or 0 if `field` or `key` does not exist. + + Examples: + >>> await client.hset("my_hash", "field", "value") + >>> await client.hstrlen("my_hash", "my_field") + 5 + """ + return cast( + int, + await self._execute_command(RequestType.HStrlen, [key, field]), + ) + async def lpush(self, key: str, elements: List[str]) -> int: """ Insert all the specified values at the head of the list stored at `key`. diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index d8e451f505..383c3487d3 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -741,6 +741,21 @@ def hrandfield_withvalues(self: TTransaction, key: str, count: int) -> TTransact RequestType.HRandField, [key, str(count), "WITHVALUES"] ) + def hstrlen(self: TTransaction, key: str, field: str) -> TTransaction: + """ + Returns the string length of the value associated with `field` in the hash stored at `key`. + + See https://valkey.io/commands/hstrlen/ for more details. + + Args: + key (str): The key of the hash. + field (str): The field in the hash. + + Commands response: + int: The string length or 0 if `field` or `key` does not exist. + """ + return self.append_command(RequestType.HStrlen, [key, field]) + def lpush(self: TTransaction, key: str, elements: List[str]) -> TTransaction: """ Insert all the specified values at the head of the list stored at `key`. diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 3c0be92527..eae0d7a325 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -909,6 +909,21 @@ async def test_hrandfield_withvalues(self, redis_client: TRedisClient): with pytest.raises(RequestError): await redis_client.hrandfield_withvalues(key2, 5) + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_hstrlen(self, redis_client: TRedisClient): + key = get_random_string(10) + + assert await redis_client.hstrlen(key, "field") == 0 + assert await redis_client.hset(key, {"field": "value"}) == 1 + assert await redis_client.hstrlen(key, "field") == 5 + + assert await redis_client.hstrlen(key, "field2") == 0 + + await redis_client.set(key, "value") + with pytest.raises(RequestError): + await redis_client.hstrlen(key, "field") + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_lpush_lpop_lrange(self, redis_client: TRedisClient): diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index 3b5e34023d..f576371906 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -168,6 +168,8 @@ async def transaction_test( args.append([key3]) transaction.hrandfield_withvalues(key4, 1) args.append([[key3, "10.5"]]) + transaction.hstrlen(key4, key3) + args.append(4) transaction.client_getname() args.append(None)