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 OBJECT FREQ command #1472

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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#### Changes
* Python: Added OBJECT ENCODING command ([#1471](https://github.com/aws/glide-for-redis/pull/1471))
* Python: Added OBJECT FREQ command ([#1472](https://github.com/aws/glide-for-redis/pull/1472))

## 0.4.0 (2024-05-26)

Expand Down
22 changes: 22 additions & 0 deletions python/python/glide/async_commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3544,3 +3544,25 @@ async def object_encoding(self, key: str) -> Optional[str]:
Optional[str],
await self._execute_command(RequestType.ObjectEncoding, [key]),
)

async def object_freq(self, key: str) -> int:
"""
Returns the logarithmic access frequency counter of a Redis object stored at `key`.

See https://valkey.io/commands/object-freq for more details.

Args:
key (str): The key of the object to get the logarithmic access frequency counter of.

Returns:
int: If `key` exists, returns the logarithmic access frequency counter of the object stored at `key` as an
integer. Otherwise, returns None.

Examples:
>>> await client.object_freq("my_hash")
2 # The logarithmic access frequency counter of "my_hash" has a value of 2.
"""
return cast(
int,
await self._execute_command(RequestType.ObjectFreq, [key]),
)
15 changes: 15 additions & 0 deletions python/python/glide/async_commands/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -2475,6 +2475,21 @@ def object_encoding(self: TTransaction, key: str) -> TTransaction:
"""
return self.append_command(RequestType.ObjectEncoding, [key])

def object_freq(self: TTransaction, key: str) -> TTransaction:
"""
Returns the logarithmic access frequency counter of a Redis object stored at `key`.

See https://valkey.io/commands/object-freq for more details.

Args:
key (str): The key of the object to get the logarithmic access frequency counter of.

Command response:
int: If `key` exists, returns the logarithmic access frequency counter of the object stored at `key` as an
integer. Otherwise, returns None.
"""
return self.append_command(RequestType.ObjectFreq, [key])


class Transaction(BaseTransaction):
"""
Expand Down
20 changes: 20 additions & 0 deletions python/python/tests/test_async_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -3393,6 +3393,26 @@ async def test_object_encoding(self, redis_client: TRedisClient):
assert await redis_client.xadd(stream_key, [("field", "value")]) is not None
assert await redis_client.object_encoding(stream_key) == "stream"

@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_object_freq(self, redis_client: TRedisClient):
key = get_random_string(10)
non_existing_key = get_random_string(10)
maxmemory_policy_key = "maxmemory-policy"
config = await redis_client.config_get([maxmemory_policy_key])
maxmemory_policy = cast(str, config.get(maxmemory_policy_key))

try:
assert (
await redis_client.config_set({maxmemory_policy_key: "allkeys-lfu"})
== OK
)
assert await redis_client.object_freq(non_existing_key) is None
assert await redis_client.set(key, "") == OK
assert await redis_client.object_freq(key) >= 0
finally:
await redis_client.config_set({maxmemory_policy_key: maxmemory_policy})


class TestMultiKeyCommandCrossSlot:
@pytest.mark.parametrize("cluster_mode", [True])
Expand Down
29 changes: 28 additions & 1 deletion python/python/tests/test_transaction.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0

from datetime import datetime, timezone
from typing import List, Union
from typing import List, Union, cast

import pytest
from glide import RequestError
Expand Down Expand Up @@ -501,3 +501,30 @@ async def test_transaction_chaining_calls(self, redis_client: TRedisClient):
transaction.set(key, "value").get(key).delete([key])

assert await redis_client.exec(transaction) == [OK, "value", 1]

# object_freq is not tested in transaction_test as it requires that we set and later restore the max memory policy
@pytest.mark.parametrize("cluster_mode", [True, False])
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
async def test_transaction_object_freq(
self, redis_client: TRedisClient, cluster_mode: bool
):
string_key = get_random_string(10)
maxmemory_policy_key = "maxmemory-policy"
config = await redis_client.config_get([maxmemory_policy_key])
maxmemory_policy = cast(str, config.get(maxmemory_policy_key))

try:
transaction = ClusterTransaction() if cluster_mode else Transaction()
transaction.config_set({maxmemory_policy_key: "allkeys-lfu"})
transaction.set(string_key, "foo")
transaction.object_freq(string_key)

response = await redis_client.exec(transaction)
assert response is not None
assert len(response) == 3
assert response[0] == OK
assert response[1] == OK
frequency = cast(int, response[2])
assert frequency >= 0
finally:
await redis_client.config_set({maxmemory_policy_key: maxmemory_policy})
Loading