From f27fae5ae6efb0c52a34aa984880b432d3f4eea0 Mon Sep 17 00:00:00 2001 From: aaron-congo Date: Fri, 14 Jun 2024 16:57:28 -0700 Subject: [PATCH] Python: add GETBIT command --- CHANGELOG.md | 1 + python/python/glide/async_commands/core.py | 24 ++++++++++++++++++ .../glide/async_commands/transaction.py | 17 +++++++++++++ python/python/tests/test_async_client.py | 25 +++++++++++++++++++ python/python/tests/test_transaction.py | 2 ++ 5 files changed, 69 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35eed0db5d..3f83a4e1d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ * Node: Added OBJECT IDLETIME command ([#1567](https://github.com/aws/glide-for-redis/pull/1567)) * Node: Added OBJECT REFCOUNT command ([#1568](https://github.com/aws/glide-for-redis/pull/1568)) * Python: Added SETBIT command ([#1571](https://github.com/aws/glide-for-redis/pull/1571)) +* Python: Added GETBIT command ([#1575](https://github.com/aws/glide-for-redis/pull/1575)) ### Breaking Changes * Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494)) diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index e8da7c28b5..2840ead49f 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -4061,6 +4061,30 @@ async def setbit(self, key: str, offset: int, value: int) -> int: ), ) + async def getbit(self, key: str, offset: int) -> int: + """ + Returns the bit value at `offset` in the string value stored at `key`. + `offset` should be greater than or equal to zero. + + See https://valkey.io/commands/getbit for more details. + + Args: + key (str): The key of the string. + offset (int): The index of the bit to return. + + Returns: + int: The bit at the given `offset` of the string. Returns `0` if the key is empty or if the positive + `offset` exceeds the length of the string. + + Examples: + >>> await client.getbit("my_key", 1) + 1 # Indicates that the second bit of the string stored at "my_key" is set to 1. + """ + return cast( + int, + await self._execute_command(RequestType.GetBit, [key, str(offset)]), + ) + async def object_encoding(self, key: str) -> Optional[str]: """ Returns the internal encoding for the Redis object stored at `key`. diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index 778801327b..788419c8ce 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -2794,6 +2794,23 @@ def setbit(self: TTransaction, key: str, offset: int, value: int) -> TTransactio """ return self.append_command(RequestType.SetBit, [key, str(offset), str(value)]) + def getbit(self: TTransaction, key: str, offset: int) -> TTransaction: + """ + Returns the bit value at `offset` in the string value stored at `key`. + `offset` should be greater than or equal to zero. + + See https://valkey.io/commands/getbit for more details. + + Args: + key (str): The key of the string. + offset (int): The index of the bit to return. + + Command response: + int: The bit at the given `offset` of the string. Returns `0` if the key is empty or if the positive + `offset` exceeds the length of the string. + """ + return self.append_command(RequestType.GetBit, [key, str(offset)]) + def object_encoding(self: TTransaction, key: str) -> TTransaction: """ Returns the internal encoding for the Redis object stored at `key`. diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 2af10c4532..7d2ee0f704 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -4047,6 +4047,31 @@ async def test_setbit(self, redis_client: TRedisClient): with pytest.raises(RequestError): await redis_client.setbit(set_key, 0, 0) + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_getbit(self, redis_client: TRedisClient): + key = get_random_string(10) + non_existing_key = get_random_string(10) + set_key = get_random_string(10) + value = "foobar" + + assert await redis_client.set(key, value) == OK + assert await redis_client.getbit(key, 1) == 1 + assert await redis_client.getbit(key, 1000) == 0 + assert await redis_client.getbit(non_existing_key, 1) == 0 + + assert await redis_client.setbit(key, 5, 0) == 1 + assert await redis_client.getbit(key, 5) == 0 + + # invalid argument - offset can't be negative + with pytest.raises(RequestError): + assert await redis_client.getbit(key, -1) == 1 + + # key exists, but it is not a string + assert await redis_client.sadd(set_key, ["foo"]) == 1 + with pytest.raises(RequestError): + await redis_client.getbit(set_key, 0) + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_object_encoding(self, redis_client: TRedisClient): diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index a0c8e40e4a..de073fcfce 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -349,6 +349,8 @@ async def transaction_test( args.append(0) transaction.setbit(key19, 1, 0) args.append(1) + transaction.getbit(key19, 1) + args.append(0) transaction.geoadd( key12,