Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Python: added LMOVE and BLMOVE commands #1536

Merged
merged 5 commits into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
* Python: Added SINTERCARD command ([#1511](https://github.com/aws/glide-for-redis/pull/1511))
* Python: Added SORT command ([#1439](https://github.com/aws/glide-for-redis/pull/1439))
* Node: Added OBJECT ENCODING command ([#1518](https://github.com/aws/glide-for-redis/pull/1518))
* Python: Added LMOVE and BLMOVE commands ([#1535](https://github.com/aws/glide-for-redis/pull/1535))
GilboaAWS marked this conversation as resolved.
Show resolved Hide resolved

### Breaking Changes
* Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494))
Expand Down
3 changes: 2 additions & 1 deletion python/python/glide/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0

from glide.async_commands.command_args import Limit, OrderBy
from glide.async_commands.command_args import Limit, ListDirection, OrderBy
from glide.async_commands.core import (
ConditionalChange,
ExpireOptions,
Expand Down Expand Up @@ -98,6 +98,7 @@
"json",
"LexBoundary",
"Limit",
"ListDirection",
"RangeByIndex",
"RangeByLex",
"RangeByScore",
Expand Down
16 changes: 16 additions & 0 deletions python/python/glide/async_commands/command_args.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,19 @@ class OrderBy(Enum):
"""
DESC: Sort in descending order.
"""


class ListDirection(Enum):
"""
Enumeration representing element popping or adding direction for List commands.
"""

LEFT = "LEFT"
"""
LEFT: Represents the option that elements should be popped from or added to the left side of a list.
"""

RIGHT = "RIGHT"
"""
RIGHT: Represents the option that elements should be popped from or added to the right side of a list.
"""
97 changes: 96 additions & 1 deletion python/python/glide/async_commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
get_args,
)

from glide.async_commands.command_args import Limit, OrderBy
from glide.async_commands.command_args import Limit, ListDirection, OrderBy
from glide.async_commands.sorted_set import (
AggregationType,
InfBound,
Expand Down Expand Up @@ -1496,6 +1496,101 @@ async def linsert(
),
)

async def lmove(
self,
source: str,
destination: str,
where_from: ListDirection,
where_to: ListDirection,
) -> Optional[str]:
"""
Atomically pops and removes the left/right-most element to the list stored at `source`
depending on `where_from`, and pushes the element at the first/last element of the list
stored at `destination` depending on `where_to`.

GilboaAWS marked this conversation as resolved.
Show resolved Hide resolved
When in cluster mode, both `source` and `destination` must map to the same hash slot.

See https://valkey.io/commands/lmove/ for details.

Args:
source (str): The key to the source list.
destination (str): The key to the destination list.
where_from (ListDirection): The direction to remove the element from (`ListDirection.LEFT` or `ListDirection.RIGHT`).
where_to (ListDirection): The direction to add the element to (`ListDirection.LEFT` or `ListDirection.RIGHT`).

Returns:
Optional[str]: The popped element, or None if `source` does not exist.

Examples:
>>> client.lpush("testKey1", ["two", "one"])
>>> client.lpush("testKey2", ["four", "three"])
>>> await client.lmove("testKey1", "testKey2", ListDirection.LEFT, ListDirection.LEFT)
"one"
>>> updated_array1 = await client.lrange("testKey1", 0, -1)
["two"]
>>> await client.lrange("testKey2", 0, -1)
["one", "three", "four"]

Since: Redis version 6.2.0.
"""
return cast(
Optional[str],
await self._execute_command(
RequestType.LMove,
[source, destination, where_from.value, where_to.value],
),
)

async def blmove(
self,
source: str,
destination: str,
where_from: ListDirection,
where_to: ListDirection,
timeout: float,
) -> Optional[str]:
"""
Blocks the connection until it pops atomically and removes the left/right-most element to the
list stored at `source` depending on `where_from`, and pushes the element at the first/last element
of the list stored at `destination` depending on `where_to`.
`BLMOVE` is the blocking variant of `LMOVE`.

Notes:
GilboaAWS marked this conversation as resolved.
Show resolved Hide resolved
1. When in cluster mode, both `source` and `destination` must map to the same hash slot.
2. `BLMOVE` is a client blocking command, see https://github.com/aws/glide-for-redis/wiki/General-Concepts#blocking-commands for more details and best practices.

See https://valkey.io/commands/blmove/ for details.

Args:
source (str): The key to the source list.
destination (str): The key to the destination list.
where_from (ListDirection): The direction to remove the element from (`ListDirection.LEFT` or `ListDirection.RIGHT`).
where_to (ListDirection): The direction to add the element to (`ListDirection.LEFT` or `ListDirection.RIGHT`).
timeout (float): The number of seconds to wait for a blocking operation to complete. A value of `0` will block indefinitely.

Returns:
Optional[str]: The popped element, or None if `source` does not exist or if the operation timed-out.

Examples:
>>> await client.lpush("testKey1", ["two", "one"])
>>> await client.lpush("testKey2", ["four", "three"])
>>> await client.blmove("testKey1", "testKey2", ListDirection.LEFT, ListDirection.LEFT, 0.1)
"one"
>>> await client.lrange("testKey1", 0, -1)
["two"]
>>> updated_array2 = await client.lrange("testKey2", 0, -1)
["one", "three", "four"]

Since: Redis version 6.2.0.
"""
return cast(
Optional[str],
await self._execute_command(
RequestType.BLMove,
[source, destination, where_from.value, where_to.value, str(timeout)],
),
)

async def sadd(self, key: str, members: List[str]) -> int:
"""
Add specified members to the set stored at `key`.
Expand Down
66 changes: 64 additions & 2 deletions python/python/glide/async_commands/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import threading
from typing import List, Mapping, Optional, Tuple, TypeVar, Union

from glide.async_commands.command_args import Limit, OrderBy
from glide.async_commands.command_args import Limit, ListDirection, OrderBy
from glide.async_commands.core import (
ConditionalChange,
ExpireOptions,
Expand Down Expand Up @@ -931,7 +931,7 @@ def linsert(
"""
Inserts `element` in the list at `key` either before or after the `pivot`.

See https://redis.io/commands/linsert/ for details.
See https://valkey.io/commands/linsert/ for details.

Args:
key (str): The key of the list.
Expand All @@ -949,6 +949,68 @@ def linsert(
RequestType.LInsert, [key, position.value, pivot, element]
)

def lmove(
self: TTransaction,
source: str,
destination: str,
where_from: ListDirection,
where_to: ListDirection,
) -> TTransaction:
"""
Atomically pops and removes the left/right-most element to the list stored at `source`
depending on `where_from`, and pushes the element at the first/last element of the list
stored at `destination` depending on `where_to`.

See https://valkey.io/commands/lmove/ for details.

Args:
source (str): The key to the source list.
destination (str): The key to the destination list.
where_from (ListDirection): The direction to remove the element from (`ListDirection.LEFT` or `ListDirection.RIGHT`).
where_to (ListDirection): The direction to add the element to (`ListDirection.LEFT` or `ListDirection.RIGHT`).

Command response:
Optional[str]: The popped element, or `None` if `source` does not exist.

Since: Redis version 6.2.0.
"""
return self.append_command(
RequestType.LMove, [source, destination, where_from.value, where_to.value]
)

def blmove(
self: TTransaction,
source: str,
destination: str,
where_from: ListDirection,
where_to: ListDirection,
timeout: float,
) -> TTransaction:
"""
Blocks the connection until it pops atomically and removes the left/right-most element to the
list stored at `source` depending on `where_from`, and pushes the element at the first/last element
of the list stored at `destination` depending on `where_to`.
`blmove` is the blocking variant of `lmove`.

See https://valkey.io/commands/blmove/ for details.

GilboaAWS marked this conversation as resolved.
Show resolved Hide resolved
Args:
source (str): The key to the source list.
destination (str): The key to the destination list.
where_from (ListDirection): The direction to remove the element from (`ListDirection.LEFT` or `ListDirection.RIGHT`).
where_to (ListDirection): The direction to add the element to (`ListDirection.LEFT` or `ListDirection.RIGHT`).
timeout (float): The number of seconds to wait for a blocking operation to complete. A value of `0` will block indefinitely.

Command response:
Optional[str]: The popped element, or `None` if `source` does not exist or if the operation timed-out.

Since: Redis version 6.2.0.
"""
return self.append_command(
RequestType.BLMove,
[source, destination, where_from.value, where_to.value, str(timeout)],
)

def sadd(self: TTransaction, key: str, members: List[str]) -> TTransaction:
"""
Add specified members to the set stored at `key`.
Expand Down
Loading
Loading