diff --git a/CHANGELOG.md b/CHANGELOG.md index 326166b939..30f4004e08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ * Python: Added ZREMRANGEBYLEX command ([#1306](https://github.com/aws/glide-for-redis/pull/1306)) * Python: Added LINSERT command ([#1304](https://github.com/aws/glide-for-redis/pull/1304)) * Python: Added GEOPOS command ([#1301](https://github.com/aws/glide-for-redis/pull/1301)) +* Python: Added PFADD command ([#1315](https://github.com/aws/glide-for-redis/pull/1315)) #### Fixes * Python: Fix typing error "‘type’ object is not subscriptable" ([#1203](https://github.com/aws/glide-for-redis/pull/1203)) diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index 9780eb3cbf..a2818b7174 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -2355,3 +2355,30 @@ async def invoke_script( ["foo", "bar"] """ return await self._execute_script(script.get_hash(), keys, args) + + async def pfadd(self, key: str, elements: List[str]) -> int: + """ + Adds all elements to the HyperLogLog data structure stored at the specified `key`. + Creates a new structure if the `key` does not exist. + When no elements are provided, and `key` exists and is a HyperLogLog, then no operation is performed. + + See https://redis.io/commands/pfadd/ for more details. + + Args: + key (str): The key of the HyperLogLog data structure to add elements into. + elements (List[str]): A list of members to add to the HyperLogLog stored at `key`. + + Returns: + int: If the HyperLogLog is newly created, or if the HyperLogLog approximated cardinality is + altered, then returns 1. Otherwise, returns 0. + + Examples: + >>> await client.pfadd("hll_1", ["a", "b", "c" ]) + 1 # A data structure was created or modified + >>> await client.pfadd("hll_2", []) + 1 # A new empty data structure was created + """ + return cast( + int, + await self._execute_command(RequestType.PfAdd, [key] + elements), + ) diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index 94840f8094..e90b339086 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -1761,6 +1761,24 @@ def dbsize(self: TTransaction) -> TTransaction: """ return self.append_command(RequestType.DBSize, []) + def pfadd(self: TTransaction, key: str, elements: List[str]) -> TTransaction: + """ + Adds all elements to the HyperLogLog data structure stored at the specified `key`. + Creates a new structure if the `key` does not exist. + When no elements are provided, and `key` exists and is a HyperLogLog, then no operation is performed. + + See https://redis.io/commands/pfadd/ for more details. + + Args: + key (str): The key of the HyperLogLog data structure to add elements into. + elements (List[str]): A list of members to add to the HyperLogLog stored at `key`. + + Commands response: + int: If the HyperLogLog is newly created, or if the HyperLogLog approximated cardinality is + altered, then returns 1. Otherwise, returns 0. + """ + return self.append_command(RequestType.PfAdd, [key] + elements) + class Transaction(BaseTransaction): """ diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index ea5f3cb077..849425ab8a 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -2027,6 +2027,19 @@ async def test_append(self, redis_client: TRedisClient): assert await redis_client.append(key, value) == 10 assert await redis_client.get(key) == value * 2 + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_pfadd(self, redis_client: TRedisClient): + key = get_random_string(10) + assert await redis_client.pfadd(key, []) == 1 + assert await redis_client.pfadd(key, ["one", "two"]) == 1 + assert await redis_client.pfadd(key, ["two"]) == 0 + assert await redis_client.pfadd(key, []) == 0 + + assert await redis_client.set("foo", "value") == OK + with pytest.raises(RequestError): + await redis_client.pfadd("foo", []) + 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 dd0460c1bf..983d10bb12 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -38,7 +38,7 @@ async def transaction_test( key7 = "{{{}}}:{}".format(keyslot, get_random_string(3)) key8 = "{{{}}}:{}".format(keyslot, get_random_string(3)) key9 = "{{{}}}:{}".format(keyslot, get_random_string(3)) - key10 = "{{{}}}:{}".format(keyslot, get_random_string(3)) # list + key10 = "{{{}}}:{}".format(keyslot, get_random_string(3)) # hyper log log value = datetime.now(timezone.utc).strftime("%m/%d/%Y, %H:%M:%S") value2 = get_random_string(5) @@ -212,6 +212,9 @@ async def transaction_test( transaction.zremrangebylex(key8, InfBound.NEG_INF, InfBound.POS_INF) args.append(0) + transaction.pfadd(key10, ["a", "b", "c"]) + args.append(1) + transaction.geoadd( key9, {