Skip to content

Commit

Permalink
Node: added OBJECT FREQ command (valkey-io#1542)
Browse files Browse the repository at this point in the history
* Node: added OBJECT FREQ command (#345)

* Node: added OBJECT FREQ command

* Addressed review comments

* Updated CHANGELOG.md

* Addressed review comments

* Addressed review comment

* Addressed review comment - added OBJECT FREQ standalone test

---------

Co-authored-by: Andrew Carbonetto <andrew.carbonetto@improving.com>
  • Loading branch information
2 people authored and cyip10 committed Jun 24, 2024
1 parent 9f266a1 commit 9e1826a
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Python: Added LMOVE and BLMOVE commands ([#1536](https://github.com/aws/glide-for-redis/pull/1536))
* Node: Added SUNIONSTORE command ([#1549](https://github.com/aws/glide-for-redis/pull/1549))
* Node: Added PFCOUNT command ([#1545](https://github.com/aws/glide-for-redis/pull/1545))
* Node: Added OBJECT FREQ command ([#1542](https://github.com/aws/glide-for-redis/pull/1542))

### Breaking Changes
* Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494))
Expand Down
18 changes: 18 additions & 0 deletions node/src/BaseClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import {
createMGet,
createMSet,
createObjectEncoding,
createObjectFreq,
createPExpire,
createPExpireAt,
createPTTL,
Expand Down Expand Up @@ -2480,6 +2481,23 @@ export class BaseClient {
return this.createWritePromise(createObjectEncoding(key));
}

/** Returns the logarithmic access frequency counter of a Redis object stored at `key`.
*
* See https://valkey.io/commands/object-freq for more details.
*
* @param key - The `key` of the object to get the logarithmic access frequency counter of.
* @returns - If `key` exists, returns the logarithmic access frequency counter of the object
* stored at `key` as a `number`. Otherwise, returns `null`.
* @example
* ```typescript
* const result = await client.object_freq("my_hash");
* console.log(result); // Output: 2 - The logarithmic access frequency counter of "my_hash".
* ```
*/
public object_freq(key: string): Promise<number | null> {
return this.createWritePromise(createObjectFreq(key));
}

/**
* @internal
*/
Expand Down
7 changes: 7 additions & 0 deletions node/src/Commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1436,3 +1436,10 @@ export function createPfCount(keys: string[]): redis_request.Command {
export function createObjectEncoding(key: string): redis_request.Command {
return createCommand(RequestType.ObjectEncoding, [key]);
}

/**
* @internal
*/
export function createObjectFreq(key: string): redis_request.Command {
return createCommand(RequestType.ObjectFreq, [key]);
}
13 changes: 13 additions & 0 deletions node/src/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
createMGet,
createMSet,
createObjectEncoding,
createObjectFreq,
createPExpire,
createPExpireAt,
createPTTL,
Expand Down Expand Up @@ -1422,6 +1423,18 @@ export class BaseTransaction<T extends BaseTransaction<T>> {
public object_encoding(key: string): T {
return this.addAndReturn(createObjectEncoding(key));
}

/** Returns the logarithmic access frequency counter of a Redis object stored at `key`.
*
* See https://valkey.io/commands/object-freq for more details.
*
* @param key - The `key` of the object to get the logarithmic access frequency counter of.
* Command Response - If `key` exists, returns the logarithmic access frequency counter of
* the object stored at `key` as a `number`. Otherwise, returns `null`.
*/
public object_freq(key: string): T {
return this.addAndReturn(createObjectFreq(key));
}
}

/**
Expand Down
43 changes: 42 additions & 1 deletion node/tests/RedisClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ import { RedisCluster } from "../../utils/TestUtils.js";
import { redis_request } from "../src/ProtobufMessage";
import { runBaseTests } from "./SharedTests";
import {
convertStringArrayToBuffer,
flushAndCloseClient,
getClientConfigurationOption,
parseCommandLineArgs,
parseEndpoints,
transactionTest,
convertStringArrayToBuffer,
} from "./TestUtilities";

/* eslint-disable @typescript-eslint/no-var-requires */
Expand Down Expand Up @@ -180,6 +180,47 @@ describe("RedisClient", () => {
},
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
"object freq transaction test_%p",
async (protocol) => {
const client = await RedisClient.createClient(
getClientConfigurationOption(cluster.getAddresses(), protocol),
);

const key = uuidv4();
const maxmemoryPolicyKey = "maxmemory-policy";
const config = await client.configGet([maxmemoryPolicyKey]);
const maxmemoryPolicy = String(config[maxmemoryPolicyKey]);

try {
const transaction = new Transaction();
transaction.configSet({
[maxmemoryPolicyKey]: "allkeys-lfu",
});
transaction.set(key, "foo");
transaction.object_freq(key);

const response = await client.exec(transaction);
expect(response).not.toBeNull();

if (response != null) {
expect(response.length).toEqual(3);
expect(response[0]).toEqual("OK");
expect(response[1]).toEqual("OK");
expect(response[2]).toBeGreaterThanOrEqual(0);
}
} finally {
expect(
await client.configSet({
[maxmemoryPolicyKey]: maxmemoryPolicy,
}),
).toEqual("OK");
}

client.close();
},
);

runBaseTests<Context>({
init: async (protocol, clientName?) => {
const options = getClientConfigurationOption(
Expand Down
41 changes: 41 additions & 0 deletions node/tests/RedisClusterClient.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,4 +324,45 @@ describe("RedisClusterClient", () => {
client.close();
},
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
"object freq transaction test_%p",
async (protocol) => {
const client = await RedisClusterClient.createClient(
getClientConfigurationOption(cluster.getAddresses(), protocol),
);

const key = uuidv4();
const maxmemoryPolicyKey = "maxmemory-policy";
const config = await client.configGet([maxmemoryPolicyKey]);
const maxmemoryPolicy = String(config[maxmemoryPolicyKey]);

try {
const transaction = new ClusterTransaction();
transaction.configSet({
[maxmemoryPolicyKey]: "allkeys-lfu",
});
transaction.set(key, "foo");
transaction.object_freq(key);

const response = await client.exec(transaction);
expect(response).not.toBeNull();

if (response != null) {
expect(response.length).toEqual(3);
expect(response[0]).toEqual("OK");
expect(response[1]).toEqual("OK");
expect(response[2]).toBeGreaterThanOrEqual(0);
}
} finally {
expect(
await client.configSet({
[maxmemoryPolicyKey]: maxmemoryPolicy,
}),
).toEqual("OK");
}

client.close();
},
);
});
35 changes: 35 additions & 0 deletions node/tests/SharedTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3079,6 +3079,41 @@ export function runBaseTests<Context>(config: {
},
config.timeout,
);

it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])(
"object freq test_%p",
async (protocol) => {
await runTest(async (client: BaseClient) => {
const key = uuidv4();
const nonExistingKey = uuidv4();
const maxmemoryPolicyKey = "maxmemory-policy";
const config = await client.configGet([maxmemoryPolicyKey]);
const maxmemoryPolicy = String(config[maxmemoryPolicyKey]);

try {
expect(
await client.configSet({
[maxmemoryPolicyKey]: "allkeys-lfu",
}),
).toEqual("OK");
expect(await client.object_freq(nonExistingKey)).toEqual(
null,
);
expect(await client.set(key, "foobar")).toEqual("OK");
expect(
await client.object_freq(key),
).toBeGreaterThanOrEqual(0);
} finally {
expect(
await client.configSet({
[maxmemoryPolicyKey]: maxmemoryPolicy,
}),
).toEqual("OK");
}
}, protocol);
},
config.timeout,
);
}

export function runCommonTests<Context>(config: {
Expand Down

0 comments on commit 9e1826a

Please sign in to comment.