diff --git a/glide-core/src/client/value_conversion.rs b/glide-core/src/client/value_conversion.rs index 13b881711a..43b1be0d53 100644 --- a/glide-core/src/client/value_conversion.rs +++ b/glide-core/src/client/value_conversion.rs @@ -86,6 +86,7 @@ pub(crate) fn expected_type_for_cmd(cmd: &Cmd) -> Option { Some(ExpectedReturnType::Boolean) } b"SMEMBERS" => Some(ExpectedReturnType::Set), + b"ZSCORE" => Some(ExpectedReturnType::DoubleOrNull), _ => None, } } diff --git a/glide-core/src/protobuf/redis_request.proto b/glide-core/src/protobuf/redis_request.proto index e36053aa7a..0f5d54eac6 100644 --- a/glide-core/src/protobuf/redis_request.proto +++ b/glide-core/src/protobuf/redis_request.proto @@ -102,6 +102,7 @@ enum RequestType { Zcard = 64; Zcount = 65; ZIncrBy = 66; + ZScore = 67; } message Command { diff --git a/glide-core/src/socket_listener.rs b/glide-core/src/socket_listener.rs index 21aef93a54..9921a08521 100644 --- a/glide-core/src/socket_listener.rs +++ b/glide-core/src/socket_listener.rs @@ -336,6 +336,7 @@ fn get_command(request: &Command) -> Option { RequestType::Zcard => Some(cmd("ZCARD")), RequestType::Zcount => Some(cmd("ZCOUNT")), RequestType::ZIncrBy => Some(cmd("ZINCRBY")), + RequestType::ZScore => Some(cmd("ZSCORE")), } } diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index a699fd475f..e5521d3423 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -1245,6 +1245,34 @@ async def zrem( await self._execute_command(RequestType.Zrem, [key] + members), ) + async def zscore(self, key: str, member: str) -> Optional[float]: + """ + Returns the score of `member` in the sorted set stored at `key`. + + See https://redis.io/commands/zscore/ for more details. + + Args: + key (str): The key of the sorted set. + member (str): The member whose score is to be retrieved. + + Returns: + Optional[float]: The score of the member. + If `member` does not exist in the sorted set, None is returned. + If `key` does not exist, None is returned. + If `key` holds a value that is not a sorted set, an error is returned. + + + Examples: + >>> await zscore("my_sorted_set", "member") + 10.5 # Indicates that the score of "member" in the sorted set "my_sorted_set" is 10.5. + >>> await zscore("my_sorted_set", "non_existing_member") + None + """ + return cast( + Optional[float], + await self._execute_command(RequestType.ZScore, [key, member]), + ) + async def invoke_script( self, script: Script, diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index d19e759b9c..ce0a8f4dde 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -915,6 +915,24 @@ def zrem( """ self.append_command(RequestType.Zrem, [key] + members) + def zscore(self, key: str, member: str): + """ + Returns the score of `member` in the sorted set stored at `key`. + + See https://redis.io/commands/zscore/ for more details. + + Args: + key (str): The key of the sorted set. + member (str): The member whose score is to be retrieved. + + Commands response: + Optional[float]: The score of the member. + If `member` does not exist in the sorted set, None is returned. + If `key` does not exist, None is returned. + If `key` holds a value that is not a sorted set, the transaction fails with an error + """ + self.append_command(RequestType.ZScore, [key, member]) + class Transaction(BaseTransaction): """ diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 173ce6dd9d..29565ed2ab 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -1069,6 +1069,18 @@ async def test_zcard(self, redis_client: TRedisClient): assert await redis_client.zrem(key, ["one"]) == 1 assert await redis_client.zcard(key) == 2 + @pytest.mark.parametrize("cluster_mode", [True, False]) + async def test_zscore(self, redis_client: TRedisClient): + key = get_random_string(10) + members_scores = {"one": 1, "two": 2, "three": 3} + assert await redis_client.zadd(key, members_scores=members_scores) == 3 + assert await redis_client.zscore(key, "one") == 1.0 + + assert await redis_client.zscore(key, "non_existing_member") == None + assert ( + await redis_client.zscore("non_existing_key", "non_existing_member") == None + ) + class TestCommandsUnitTests: def test_expiry_cmd_args(self): diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index bed3342f65..4746d561f2 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -90,6 +90,7 @@ def transaction_test( transaction.zadd_incr(key8, "one", 3) transaction.zrem(key8, ["one"]) transaction.zcard(key8) + transaction.zscore(key8, "two") return [ OK, value, @@ -132,6 +133,7 @@ def transaction_test( 4, 1, 2, + 2.0, ]