From 9a6eb0e3a0d590f42e7abb209b07ef87d84838c5 Mon Sep 17 00:00:00 2001 From: Shoham Elias <116083498+shohamazon@users.noreply.github.com> Date: Tue, 18 Jun 2024 11:47:59 +0300 Subject: [PATCH] Python: adds TOUCH command (#1582) --- CHANGELOG.md | 1 + python/python/glide/async_commands/core.py | 23 +++++++++++++++++++ .../glide/async_commands/transaction.py | 14 +++++++++++ python/python/tests/test_async_client.py | 14 ++++++++++- python/python/tests/test_transaction.py | 2 ++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d62796a2bf..ab4b77f2af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ * 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)) * Python: Added BITCOUNT command ([#1592](https://github.com/aws/glide-for-redis/pull/1592)) +* Python: Added TOUCH command ([#1582](https://github.com/aws/glide-for-redis/pull/1582)) ### 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 0ebc864673..39e06735dd 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -796,6 +796,29 @@ async def decrby(self, key: str, amount: int) -> int: int, await self._execute_command(RequestType.DecrBy, [key, str(amount)]) ) + async def touch(self, keys: List[str]) -> int: + """ + Updates the last access time of specified keys. + + See https://valkey.io/commands/touch/ for details. + + Note: + When in cluster mode, the command may route to multiple nodes when `keys` map to different hash slots. + + Args: + keys (List[str]): The keys to update last access time. + + Returns: + int: The number of keys that were updated, a key is ignored if it doesn't exist. + + Examples: + >>> await client.set("myKey1", "value1") + >>> await client.set("myKey2", "value2") + >>> await client.touch(["myKey1", "myKey2", "nonExistentKey"]) + 2 # Last access time of 2 keys has been updated. + """ + return cast(int, await self._execute_command(RequestType.Touch, keys)) + async def hset(self, key: str, field_value_map: Mapping[str, str]) -> int: """ Sets the specified fields to their respective values in the hash stored at `key`. diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index cabd250157..fd9462bf70 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -346,6 +346,20 @@ def mget(self: TTransaction, keys: List[str]) -> TTransaction: """ return self.append_command(RequestType.MGet, keys) + def touch(self: TTransaction, keys: List[str]) -> TTransaction: + """ + Updates the last access time of specified keys. + + See https://valkey.io/commands/touch/ for details. + + Args: + keys (List[str]): The keys to update last access time. + + Commands response: + int: The number of keys that were updated, a key is ignored if it doesn't exist. + """ + return self.append_command(RequestType.Touch, keys) + def config_rewrite(self: TTransaction) -> TTransaction: """ Rewrite the configuration file with the current configuration. diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 7c55bfe43e..8b25b4573c 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -549,6 +549,18 @@ async def test_mset_mget(self, redis_client: TRedisClient): keys[-1] = None assert mget_res == keys + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_touch(self, redis_client: TRedisClient): + keys = [get_random_string(10), get_random_string(10)] + key_value_pairs = {key: value for key, value in zip(keys, keys)} + + assert await redis_client.mset(key_value_pairs) == OK + assert await redis_client.touch(keys) == 2 + + # 2 existing keys, one non-existing + assert await redis_client.touch([*keys, get_random_string(3)]) == 2 + @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) async def test_msetnx(self, redis_client: TRedisClient): @@ -4942,7 +4954,7 @@ async def test_multi_key_command_routed_to_multiple_nodes( await redis_client.delete(["abc", "zxy", "lkn"]) await redis_client.mget(["abc", "zxy", "lkn"]) await redis_client.mset({"abc": "1", "zxy": "2", "lkn": "3"}) - # TODO touch + await redis_client.touch(["abc", "zxy", "lkn"]) class TestCommandsUnitTests: diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index f933ad8d87..bdd30ac449 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -91,6 +91,8 @@ async def transaction_test( transaction.exists([key2]) args.append(1) + transaction.touch([key2]) + args.append(1) transaction.delete([key2]) args.append(1)