From 813f0fd8f030b63751ef647c871ff89522975057 Mon Sep 17 00:00:00 2001 From: Shoham Elias Date: Thu, 15 Feb 2024 15:32:06 +0000 Subject: [PATCH 1/2] Python: adds SISMEMBER command --- CHANGELOG.md | 3 +- glide-core/src/client/value_conversion.rs | 5 ++-- glide-core/src/protobuf/redis_request.proto | 1 + glide-core/src/socket_listener.rs | 1 + python/python/glide/async_commands/core.py | 29 +++++++++++++++++++ .../glide/async_commands/transaction.py | 20 +++++++++++++ python/python/tests/test_async_client.py | 11 +++++++ python/python/tests/test_transaction.py | 2 ++ 8 files changed, 68 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cc795c97f..9bf984c3b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Node: Allow routing Cluster requests by address. ([#1021](https://github.com/aws/glide-for-redis/pull/1021)) * Python: Added HSETNX command. ([#954](https://github.com/aws/glide-for-redis/pull/954)) +* Python: Added SISMEMBER command ([#971](https://github.com/aws/glide-for-redis/pull/971)) ## 0.2.0 (2024-02-11) @@ -16,7 +17,7 @@ * Python, Node: When recieving LPOP/RPOP with count, convert result to Array. ([#811](https://github.com/aws/glide-for-redis/pull/811)) * Python, Node: Added TYPE command ([#945](https://github.com/aws/glide-for-redis/pull/945), [#980](https://github.com/aws/glide-for-redis/pull/980)) * Python, Node: Added HLEN command ([#944](https://github.com/aws/glide-for-redis/pull/944), [#981](https://github.com/aws/glide-for-redis/pull/981)) -* Node: Added ZCOUNT command ([#909](https://github.com/aws/glide-for-redis/pull/909)) +* Python, Node: Added ZCOUNT command ([#878](https://github.com/aws/glide-for-redis/pull/878)) ([#909](https://github.com/aws/glide-for-redis/pull/909)) * Python: Added ECHO command ([#953](https://github.com/aws/glide-for-redis/pull/953)) * Python, Node: Added ZPOPMIN command ([#975](https://github.com/aws/glide-for-redis/pull/975), [#1008](https://github.com/aws/glide-for-redis/pull/1008)) * Node: Added STRLEN command ([#993](https://github.com/aws/glide-for-redis/pull/993)) diff --git a/glide-core/src/client/value_conversion.rs b/glide-core/src/client/value_conversion.rs index 2aca949d34..73a886e994 100644 --- a/glide-core/src/client/value_conversion.rs +++ b/glide-core/src/client/value_conversion.rs @@ -201,9 +201,8 @@ pub(crate) fn expected_type_for_cmd(cmd: &Cmd) -> Option { Some(ExpectedReturnType::Map) } b"INCRBYFLOAT" | b"HINCRBYFLOAT" => Some(ExpectedReturnType::Double), - b"HEXISTS" | b"HSETNX" | b"EXPIRE" | b"EXPIREAT" | b"PEXPIRE" | b"PEXPIREAT" => { - Some(ExpectedReturnType::Boolean) - } + b"HEXISTS" | b"HSETNX" | b"EXPIRE" | b"EXPIREAT" | b"PEXPIRE" | b"PEXPIREAT" + | b"SISMEMBER" => Some(ExpectedReturnType::Boolean), b"SMEMBERS" => Some(ExpectedReturnType::Set), b"ZSCORE" => Some(ExpectedReturnType::DoubleOrNull), b"ZPOPMIN" | b"ZPOPMAX" => Some(ExpectedReturnType::MapOfStringToDouble), diff --git a/glide-core/src/protobuf/redis_request.proto b/glide-core/src/protobuf/redis_request.proto index 7b413654d4..bfaf1bbe36 100644 --- a/glide-core/src/protobuf/redis_request.proto +++ b/glide-core/src/protobuf/redis_request.proto @@ -124,6 +124,7 @@ enum RequestType { XGroupCreate = 80; XGroupDestroy = 81; HSetNX = 82; + SIsMember = 83; } message Command { diff --git a/glide-core/src/socket_listener.rs b/glide-core/src/socket_listener.rs index de9ce806dc..ba24a93a44 100644 --- a/glide-core/src/socket_listener.rs +++ b/glide-core/src/socket_listener.rs @@ -361,6 +361,7 @@ fn get_command(request: &Command) -> Option { RequestType::XGroupDestroy => Some(get_two_word_command("XGROUP", "DESTROY")), RequestType::XTrim => Some(cmd("XTRIM")), RequestType::HSetNX => Some(cmd("HSETNX")), + RequestType::SIsMember => Some(cmd("SISMEMBER")), } } diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index 7ddfededa3..fa51137e66 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -902,6 +902,35 @@ async def scard(self, key: str) -> int: """ return cast(int, await self._execute_command(RequestType.SCard, [key])) + async def sismember( + self, + key: str, + member: str, + ) -> bool: + """ + Returns if `member` is a member of the set stored at `key`. + + See https://redis.io/commands/sismember/ for more details. + + Args: + key (str): The key of the set. + member (str): The member to check for existence in the set. + + Returns: + bool: True if the member exists in the set, False otherwise. + If `key` doesn't exist, it is treated as an empty set and the command returns False. + + Examples: + >>> await client.sismember("my_set", "member1") + True # Indicates that "member1" exists in the set "my_set". + >>> await client.sismember("my_set", "non_existing_member") + False # Indicates that "non_existing_member" does not exist in the set "my_set". + """ + return cast( + bool, + await self._execute_command(RequestType.SIsMember, [key, member]), + ) + async def ltrim(self, key: str, start: int, end: int) -> TOK: """ Trim an existing list so that it will contain only the specified range of elements specified. diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index ee52e5cb94..ed3ba10172 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -695,6 +695,26 @@ def scard(self: TTransaction, key: str) -> TTransaction: """ return self.append_command(RequestType.SCard, [key]) + def sismember( + self: TTransaction, + key: str, + member: str, + ) -> TTransaction: + """ + Returns if `member` is a member of the set stored at `key`. + + See https://redis.io/commands/sismember/ for more details. + + Args: + key (str): The key of the set. + member (str): The member to check for existence in the set. + + Commands response: + bool: True if the member exists in the set, False otherwise. + If `key` doesn't exist, it is treated as an empty set and the command returns False. + """ + return self.append_command(RequestType.SIsMember, [key, member]) + def ltrim(self: TTransaction, key: str, start: int, end: int) -> TTransaction: """ Trim an existing list so that it will contain only the specified range of elements specified. diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index c17f1fde94..6d35103a7f 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -857,6 +857,17 @@ async def test_sadd_srem_smembers_scard_wrong_type_raise_error( await redis_client.smembers(key) assert "Operation against a key holding the wrong kind of value" in str(e) + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_sismember(self, redis_client: TRedisClient): + key = get_random_string(10) + member = get_random_string(5) + assert await redis_client.sadd(key, [member]) == 1 + assert await redis_client.sismember(key, member) == True + + assert await redis_client.sismember(key, get_random_string(5)) == False + assert await redis_client.sismember("non_existing_key", member) == False + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_ltrim(self, redis_client: TRedisClient): diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index ee242962dc..621e2b1751 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -135,6 +135,8 @@ def transaction_test( args.append({"bar"}) transaction.scard(key7) args.append(1) + transaction.sismember(key7, "bar") + args.append(True) transaction.zadd(key8, {"one": 1, "two": 2, "three": 3}) args.append(3) From b0fd36055ce4509b8e88f8e96ad1bde167789567 Mon Sep 17 00:00:00 2001 From: Shoham Elias Date: Thu, 29 Feb 2024 13:00:56 +0000 Subject: [PATCH 2/2] pr comments change --- python/python/tests/test_async_client.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 6d35103a7f..5fff8c965e 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -863,10 +863,9 @@ async def test_sismember(self, redis_client: TRedisClient): key = get_random_string(10) member = get_random_string(5) assert await redis_client.sadd(key, [member]) == 1 - assert await redis_client.sismember(key, member) == True - - assert await redis_client.sismember(key, get_random_string(5)) == False - assert await redis_client.sismember("non_existing_key", member) == False + assert await redis_client.sismember(key, member) + assert not await redis_client.sismember(key, get_random_string(5)) + assert not await redis_client.sismember("non_existing_key", member) @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])