diff --git a/CHANGELOG.md b/CHANGELOG.md index c2a2abb9a8..1291dd1069 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ * Python: Added SRandMember command ([#1578](https://github.com/aws/glide-for-redis/pull/1578)) * 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 FLUSHALL command ([#1579](https://github.com/aws/glide-for-redis/pull/1579)) * Python: Added TOUCH command ([#1582](https://github.com/aws/glide-for-redis/pull/1582)) * Python: Added BITOP command ([#1596](https://github.com/aws/glide-for-redis/pull/1596)) * Python: Added BITPOS command ([#1604](https://github.com/aws/glide-for-redis/pull/1604)) diff --git a/python/python/glide/__init__.py b/python/python/glide/__init__.py index 18d52b8d27..f8f25171ce 100644 --- a/python/python/glide/__init__.py +++ b/python/python/glide/__init__.py @@ -7,6 +7,7 @@ ExpireOptions, ExpirySet, ExpiryType, + FlushMode, InfoSection, InsertPosition, StreamAddOptions, @@ -93,6 +94,7 @@ "ExpireOptions", "ExpirySet", "ExpiryType", + "FlushMode", "GeoSearchByBox", "GeoSearchByRadius", "GeoSearchCount", diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index 6796c9608f..34eb743885 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -5,7 +5,12 @@ from typing import Dict, List, Mapping, Optional, cast from glide.async_commands.command_args import Limit, OrderBy -from glide.async_commands.core import CoreCommands, InfoSection, _build_sort_args +from glide.async_commands.core import ( + CoreCommands, + FlushMode, + InfoSection, + _build_sort_args, +) from glide.async_commands.transaction import BaseTransaction, ClusterTransaction from glide.constants import TOK, TClusterResponse, TResult, TSingleNodeRoute from glide.protobuf.redis_request_pb2 import RequestType @@ -478,3 +483,34 @@ async def publish(self, message: str, channel: str, sharded: bool = False) -> in RequestType.SPublish if sharded else RequestType.Publish, [channel, message] ) return cast(int, result) + + async def flushall( + self, flush_mode: Optional[FlushMode] = None, route: Optional[Route] = None + ) -> TClusterResponse[TOK]: + """ + Deletes all the keys of all the existing databases. This command never fails. + + See https://valkey.io/commands/flushall for more details. + + Args: + flush_mode (Optional[FlushMode]): The flushing mode, could be either `SYNC` or `ASYNC`. + route (Optional[Route]): The command will be routed to all primary nodes, unless `route` is provided, + in which case the client will route the command to the nodes defined by `route`. + + Returns: + TClusterResponse[TOK]: OK. + + Examples: + >>> await client.flushall(FlushMode.ASYNC) + OK # This command never fails. + >>> await client.flushall(FlushMode.ASYNC, AllNodes()) + OK # This command never fails. + """ + args = [] + if flush_mode is not None: + args.append(flush_mode.value) + + return cast( + TClusterResponse[TOK], + await self._execute_command(RequestType.FlushAll, args, route), + ) diff --git a/python/python/glide/async_commands/core.py b/python/python/glide/async_commands/core.py index 674239f4f1..2a2b242972 100644 --- a/python/python/glide/async_commands/core.py +++ b/python/python/glide/async_commands/core.py @@ -329,6 +329,21 @@ class InsertPosition(Enum): AFTER = "AFTER" +class FlushMode(Enum): + """ + Defines flushing mode for: + + `FLUSHALL` command and `FUNCTION FLUSH` command. + + See https://valkey.io/commands/flushall/ and https://valkey.io/commands/function-flush/ for details + + SYNC was introduced in version 6.2.0. + """ + + ASYNC = "ASYNC" + SYNC = "SYNC" + + def _build_sort_args( key: str, by_pattern: Optional[str] = None, diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index 74fff200a1..bf92c74b32 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -5,7 +5,12 @@ from typing import Dict, List, Mapping, Optional, cast from glide.async_commands.command_args import Limit, OrderBy -from glide.async_commands.core import CoreCommands, InfoSection, _build_sort_args +from glide.async_commands.core import ( + CoreCommands, + FlushMode, + InfoSection, + _build_sort_args, +) from glide.async_commands.transaction import BaseTransaction, Transaction from glide.constants import TOK, TResult from glide.protobuf.redis_request_pb2 import RequestType @@ -429,3 +434,28 @@ async def publish(self, message: str, channel: str) -> int: """ result = await self._execute_command(RequestType.Publish, [channel, message]) return cast(int, result) + + async def flushall(self, flush_mode: Optional[FlushMode] = None) -> TOK: + """ + Deletes all the keys of all the existing databases. This command never fails. + + See https://valkey.io/commands/flushall for more details. + + Args: + flush_mode (Optional[FlushMode]): The flushing mode, could be either `SYNC` or `ASYNC`. + + Returns: + TOK: OK. + + Examples: + >>> await client.flushall(FlushMode.ASYNC) + OK # This command never fails. + """ + args = [] + if flush_mode is not None: + args.append(flush_mode.value) + + return cast( + TOK, + await self._execute_command(RequestType.FlushAll, args), + ) diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index b69268c020..5c77b3f352 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -9,6 +9,7 @@ ConditionalChange, ExpireOptions, ExpirySet, + FlushMode, GeospatialData, GeoUnit, InfoSection, @@ -3285,6 +3286,24 @@ def srandmember_count(self: TTransaction, key: str, count: int) -> TTransaction: """ return self.append_command(RequestType.SRandMember, [key, str(count)]) + def flushall( + self: TTransaction, flush_mode: Optional[FlushMode] = None + ) -> TTransaction: + """ + Deletes all the keys of all the existing databases. This command never fails. + See https://valkey.io/commands/flushall for more details. + + Args: + flush_mode (Optional[FlushMode]): The flushing mode, could be either `SYNC` or `ASYNC`. + + Command Response: + TOK: OK. + """ + args = [] + if flush_mode is not None: + args.append(flush_mode.value) + return self.append_command(RequestType.FlushAll, args) + class Transaction(BaseTransaction): """ diff --git a/python/python/glide/routes.py b/python/python/glide/routes.py index 29cf8b364c..cf4c4a1bd3 100644 --- a/python/python/glide/routes.py +++ b/python/python/glide/routes.py @@ -24,6 +24,12 @@ def __init__(self) -> None: class AllNodes(Route): + """ + Route request to all nodes. + Warning: + Don't use it with write commands, they could be routed to a replica (RO) node and fail. + """ + pass @@ -32,6 +38,12 @@ class AllPrimaries(Route): class RandomNode(Route): + """ + Route request to a random node. + Warning: + Don't use it with write commands, because they could be randomly routed to a replica (RO) node and fail. + """ + pass diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index b588b266ed..13ec84a126 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -18,6 +18,8 @@ ExpireOptions, ExpirySet, ExpiryType, + FlushMode, + InfBound, InfoSection, InsertPosition, StreamAddOptions, @@ -5209,6 +5211,29 @@ async def test_srandmember_count(self, redis_client: TRedisClient): with pytest.raises(RequestError): await redis_client.srandmember_count(string_key, 8) + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_flushall(self, redis_client: TRedisClient): + min_version = "6.2.0" + key = f"{{key}}-1{get_random_string(5)}" + value = get_random_string(5) + + await redis_client.set(key, value) + assert await redis_client.dbsize() > 0 + assert await redis_client.flushall() is OK + assert await redis_client.flushall(FlushMode.ASYNC) is OK + if not await check_if_server_version_lt(redis_client, min_version): + assert await redis_client.flushall(FlushMode.SYNC) is OK + assert await redis_client.dbsize() == 0 + + if isinstance(redis_client, RedisClusterClient): + await redis_client.set(key, value) + assert await redis_client.flushall(route=AllPrimaries()) is OK + assert await redis_client.flushall(FlushMode.ASYNC, AllPrimaries()) is OK + if not await check_if_server_version_lt(redis_client, min_version): + assert await redis_client.flushall(FlushMode.SYNC, AllPrimaries()) is OK + assert await redis_client.dbsize() == 0 + class TestMultiKeyCommandCrossSlot: @pytest.mark.parametrize("cluster_mode", [True]) diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index b5c079991c..9f0a0f7291 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -8,7 +8,12 @@ from glide import RequestError from glide.async_commands.bitmap import BitmapIndexType, BitwiseOperation, OffsetOptions from glide.async_commands.command_args import Limit, ListDirection, OrderBy -from glide.async_commands.core import InsertPosition, StreamAddOptions, TrimByMinId +from glide.async_commands.core import ( + FlushMode, + InsertPosition, + StreamAddOptions, + TrimByMinId, +) from glide.async_commands.sorted_set import ( AggregationType, GeoSearchByBox, @@ -465,6 +470,15 @@ async def transaction_test( args.append("one") transaction.srandmember_count(key7, 1) args.append(["one"]) + transaction.flushall(FlushMode.ASYNC) + args.append(OK) + transaction.flushall() + args.append(OK) + + min_version = "6.2.0" + if not await check_if_server_version_lt(redis_client, min_version): + transaction.flushall(FlushMode.SYNC) + args.append(OK) min_version = "7.0.0" if not await check_if_server_version_lt(redis_client, min_version):