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: add RANDOMKEY command #396

Merged
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion glide-core/src/client/standalone_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ impl StandaloneClient {
Some(ResponsePolicy::OneSucceeded) => future::select_ok(requests.map(Box::pin))
.await
.map(|(result, _)| result),
Some(ResponsePolicy::OneSucceededNonEmpty) => {
Some(ResponsePolicy::FirstSucceededNonEmptyOrAllEmpty) => {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was renamed in redis-rs, so I had to rename here to get the Rust code to build successfully

future::select_ok(requests.map(|request| {
Box::pin(async move {
let result = request.await?;
Expand Down
22 changes: 22 additions & 0 deletions python/python/glide/async_commands/cluster_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -624,3 +624,25 @@ async def lolwut(
TClusterResponse[str],
await self._execute_command(RequestType.Lolwut, args, route),
)

async def random_key(self, route: Optional[Route] = None) -> Optional[str]:
"""
Returns a random existing key name.

See https://valkey.io/commands/randomkey for more details.

Args:
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:
Optional[str]: A random existing key name.

Examples:
>>> await client.random_key()
"random_key_name" # "random_key_name" is a random existing key name.
"""
return cast(
Optional[str],
await self._execute_command(RequestType.RandomKey, [], route),
)
18 changes: 18 additions & 0 deletions python/python/glide/async_commands/standalone_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,3 +566,21 @@ async def lolwut(
str,
await self._execute_command(RequestType.Lolwut, args),
)

async def random_key(self) -> Optional[str]:
"""
Returns a random existing key name from the currently selected database.

See https://valkey.io/commands/randomkey for more details.

Returns:
Optional[str]: A random existing key name from the currently selected database.

Examples:
>>> await client.random_key()
"random_key_name" # "random_key_name" is a random existing key name from the currently selected database.
"""
return cast(
Optional[str],
await self._execute_command(RequestType.RandomKey, []),
)
11 changes: 11 additions & 0 deletions python/python/glide/async_commands/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -3737,6 +3737,17 @@ def lolwut(
args.extend(str(var))
return self.append_command(RequestType.Lolwut, args)

def random_key(self: TTransaction) -> TTransaction:
"""
Returns a random existing key name.

See https://valkey.io/commands/randomkey for more details.

Command response:
Optional[str]: A random existing key name.
"""
return self.append_command(RequestType.RandomKey, [])


class Transaction(BaseTransaction):
"""
Expand Down
41 changes: 41 additions & 0 deletions python/python/tests/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6487,6 +6487,47 @@ async def test_lolwut(self, redis_client: TGlideClient):
result = await redis_client.lolwut(2, [10, 20], RandomNode())
assert "Redis ver. " in node_result

@pytest.mark.parametrize("cluster_mode", [True])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_cluster_client_random_key(self, redis_client: TGlideClient):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
async def test_cluster_client_random_key(self, redis_client: TGlideClient):
async def test_cluster_client_random_key(self, redis_client: GlideClusterClient):

And you can remove assert for client type then

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, will address all of these when I push to upstream

key = get_random_string(10)

# setup: delete all keys
assert isinstance(redis_client, GlideClusterClient)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert isinstance(redis_client, GlideClusterClient)

assert await redis_client.flushall(FlushMode.SYNC)

# no keys exists, so random_key returns None
assert await redis_client.random_key() is None

assert await redis_client.set(key, "foo") == OK
# `key` should be the only existing key, so random_key should return `key`
assert await redis_client.random_key() == key
assert await redis_client.random_key(AllPrimaries()) == key

@pytest.mark.parametrize("cluster_mode", [False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_standalone_client_random_key(self, redis_client: TGlideClient):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same in this test

key = get_random_string(10)

assert isinstance(redis_client, GlideClient)
# setup: delete all keys in DB 0 and DB 1
assert await redis_client.select(0) == OK
assert await redis_client.flushdb(FlushMode.SYNC) == OK
assert await redis_client.select(1) == OK
assert await redis_client.flushdb(FlushMode.SYNC) == OK

# no keys exist so random_key returns None
assert await redis_client.random_key() is None
# set `key` in DB 1
assert await redis_client.set(key, "foo") == OK
# `key` should be the only key in the database
assert await redis_client.random_key() == key

# switch back to DB 0
assert await redis_client.select(0) == OK
# DB 0 should still have no keys, so random_key should still return None
assert await redis_client.random_key() is None


class TestMultiKeyCommandCrossSlot:
@pytest.mark.parametrize("cluster_mode", [True])
Expand Down
5 changes: 5 additions & 0 deletions python/python/tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,11 @@ async def transaction_test(
transaction.flushdb()
args.append(OK)

transaction.set(key, "foo")
args.append(OK)
transaction.random_key()
args.append(key)

min_version = "6.2.0"
if not await check_if_server_version_lt(redis_client, min_version):
transaction.flushall(FlushMode.SYNC)
Expand Down
Loading