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 #1701

Merged
merged 3 commits into from
Jun 28, 2024
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
* Python: Added XGROUP SETID command ([#1683](https://github.com/aws/glide-for-redis/pull/1683))
* Python: Added FUNCTION LOAD command ([#1699](https://github.com/aws/glide-for-redis/pull/1699))
* Python: Added XPENDING command ([#1704](https://github.com/aws/glide-for-redis/pull/1704))
* Python: Added RANDOMKEY command ([#1701](https://github.com/aws/glide-for-redis/pull/1701))

### Breaking Changes
* Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494))
Expand Down
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) => {
acarbonetto marked this conversation as resolved.
Show resolved Hide resolved
future::select_ok(requests.map(|request| {
Box::pin(async move {
let result = request.await?;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1742,9 +1742,8 @@ public void randomKey() {
// no keys in database
assertEquals(OK, clusterClient.flushall(SYNC).get());

// TODO: returns a ResponseError but expecting null
// uncomment when this is completed: https://github.com/amazon-contributing/redis-rs/pull/153
// assertNull(clusterClient.randomKey().get());
// no keys in database returns null
assertNull(clusterClient.randomKey().get());
}

@Test
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 @@ -658,3 +658,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 @@ -595,3 +595,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 @@ -3859,6 +3859,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
39 changes: 39 additions & 0 deletions python/python/tests/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7003,6 +7003,45 @@ 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: GlideClusterClient):
key = get_random_string(10)

# setup: delete all keys
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: GlideClient):
key = get_random_string(10)

# 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
4 changes: 4 additions & 0 deletions python/python/tests/test_transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,10 @@ async def transaction_test(
args.append(OK)
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):
Expand Down
Loading