Skip to content

Commit

Permalink
Python: adds HLEN command (#944)
Browse files Browse the repository at this point in the history
  • Loading branch information
shohamazon committed Feb 13, 2024
1 parent 0a233c1 commit 396bb6d
Show file tree
Hide file tree
Showing 7 changed files with 60 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Standalone client: Improve connection errors. ([#854](https://github.com/aws/glide-for-redis/pull/854))
* Python, Node: When recieving LPOP/RPOP with count, convert result to Array. ([#811](https://github.com/aws/glide-for-redis/pull/811))
* Python: Added TYPE command ([#945](https://github.com/aws/glide-for-redis/pull/945))
* Python: Added HLEN command ([#944](https://github.com/aws/glide-for-redis/pull/944))

#### Features
* Python, Node: Added support in Lua Scripts ([#775](https://github.com/aws/glide-for-redis/pull/775), [#860](https://github.com/aws/glide-for-redis/pull/860))
Expand Down
1 change: 1 addition & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ enum RequestType {
ZIncrBy = 66;
ZScore = 67;
Type = 68;
HLen = 69;
}

message Command {
Expand Down
1 change: 1 addition & 0 deletions glide-core/src/socket_listener.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,7 @@ fn get_command(request: &Command) -> Option<Cmd> {
RequestType::ZIncrBy => Some(cmd("ZINCRBY")),
RequestType::ZScore => Some(cmd("ZSCORE")),
RequestType::Type => Some(cmd("TYPE")),
RequestType::HLen => Some(cmd("HLEN")),
}
}

Expand Down
21 changes: 21 additions & 0 deletions python/python/glide/async_commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,27 @@ async def hdel(self, key: str, fields: List[str]) -> int:
int, await self._execute_command(RequestType.HashDel, [key] + fields)
)

async def hlen(self, key: str) -> int:
"""
Returns the number of fields contained in the hash stored at `key`.
See https://redis.io/commands/hlen/ for more details.
Args:
key (str): The key of the hash.
Returns:
int: The number of fields in the hash, or 0 when the key does not exist.
If `key` holds a value that is not a hash, an error is returned.
Examples:
>>> await client.hlen("my_hash")
3
>>> await client.hlen("non_existing_key")
0
"""
return cast(int, await self._execute_command(RequestType.HLen, [key]))

async def lpush(self, key: str, elements: List[str]) -> int:
"""Insert 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
Expand Down
15 changes: 15 additions & 0 deletions python/python/glide/async_commands/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,21 @@ def hexists(self, key: str, field: str):
"""
self.append_command(RequestType.HashExists, [key, field])

def hlen(self, key: str):
"""
Returns the number of fields contained in the hash stored at `key`.
See https://redis.io/commands/hlen/ for more details.
Args:
key (str): The key of the hash.
Command response:
int: The number of fields in the hash, or 0 when the key does not exist.
If `key` holds a value that is not a hash, the transaction fails with an error.
"""
self.append_command(RequestType.HLen, [key])

def client_getname(self):
"""
Get the name of the connection on which the transaction is being executed.
Expand Down
19 changes: 19 additions & 0 deletions python/python/tests/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,25 @@ async def test_hexist(self, redis_client: TRedisClient):
assert await redis_client.hexists(key, "nonExistingField") == False
assert await redis_client.hexists("nonExistingKey", field2) == False

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_hlen(self, redis_client: TRedisClient):
key = get_random_string(10)
key2 = get_random_string(5)
field = get_random_string(5)
field2 = get_random_string(5)
field_value_map = {field: "value", field2: "value2"}

assert await redis_client.hset(key, field_value_map) == 2
assert await redis_client.hlen(key) == 2
assert await redis_client.hdel(key, [field]) == 1
assert await redis_client.hlen(key) == 1
assert await redis_client.hlen("non_existing_hash") == 0

assert await redis_client.set(key2, "value") == OK
with pytest.raises(RequestError):
await redis_client.hlen(key2)

@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):
Expand Down
2 changes: 2 additions & 0 deletions python/python/tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def transaction_test(

transaction.hset(key4, {key: value, key2: value2})
transaction.hget(key4, key2)
transaction.hlen(key4)

transaction.hincrby(key4, key3, 5)
transaction.hincrbyfloat(key4, key3, 5.5)
Expand Down Expand Up @@ -116,6 +117,7 @@ def transaction_test(
{"timeout": "1000"},
2,
value2,
2,
5,
10.5,
True,
Expand Down

0 comments on commit 396bb6d

Please sign in to comment.