diff --git a/CHANGELOG.md b/CHANGELOG.md index c77ccb0666..a110784353 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ * Node: Added ZINTERCARD command ([#1553](https://github.com/aws/glide-for-redis/pull/1553)) * Python: Added LMPOP and BLMPOP commands ([#1547](https://github.com/aws/glide-for-redis/pull/1547)) * Node: Added OBJECT IDLETIME command ([#1567](https://github.com/aws/glide-for-redis/pull/1567)) +* Node: Added OBJECT REFCOUNT command ([#1568](https://github.com/aws/glide-for-redis/pull/1568)) ### Breaking Changes * Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494)) diff --git a/node/src/BaseClient.ts b/node/src/BaseClient.ts index cf4b0919e2..519abc4de1 100644 --- a/node/src/BaseClient.ts +++ b/node/src/BaseClient.ts @@ -102,6 +102,7 @@ import { createXLen, createZInterCard, createObjectIdletime, + createObjectRefcount, } from "./Commands"; import { ClosingError, @@ -2593,6 +2594,25 @@ export class BaseClient { return this.createWritePromise(createObjectIdletime(key)); } + /** + * Returns the reference count of the object stored at `key`. + * + * See https://valkey.io/commands/object-refcount/ for more details. + * + * @param key - The `key` of the object to get the reference count of. + * @returns If `key` exists, returns the reference count of the object stored at `key` as a `number`. + * Otherwise, returns `null`. + * + * @example + * ```typescript + * const result = await client.objectRefcount("my_hash"); + * console.log(result); // Output: 2 - "my_hash" has a reference count of 2. + * ``` + */ + public objectRefcount(key: string): Promise { + return this.createWritePromise(createObjectRefcount(key)); + } + /** * @internal */ diff --git a/node/src/Commands.ts b/node/src/Commands.ts index f507555dae..60053d9e4b 100644 --- a/node/src/Commands.ts +++ b/node/src/Commands.ts @@ -1500,3 +1500,10 @@ export function createObjectFreq(key: string): redis_request.Command { export function createObjectIdletime(key: string): redis_request.Command { return createCommand(RequestType.ObjectIdleTime, [key]); } + +/** + * @internal + */ +export function createObjectRefcount(key: string): redis_request.Command { + return createCommand(RequestType.ObjectRefCount, [key]); +} diff --git a/node/src/Transaction.ts b/node/src/Transaction.ts index fbb1889d22..61f7da97c3 100644 --- a/node/src/Transaction.ts +++ b/node/src/Transaction.ts @@ -107,6 +107,7 @@ import { createXLen, createZInterCard, createObjectIdletime, + createObjectRefcount, } from "./Commands"; import { redis_request } from "./ProtobufMessage"; @@ -1507,6 +1508,20 @@ export class BaseTransaction> { public objectIdletime(key: string): T { return this.addAndReturn(createObjectIdletime(key)); } + + /** + * Returns the reference count of the object stored at `key`. + * + * See https://valkey.io/commands/object-refcount/ for more details. + * + * @param key - The `key` of the object to get the reference count of. + * + * Command Response - If `key` exists, returns the reference count of the object stored at `key` as a `number`. + * Otherwise, returns `null`. + */ + public objectRefcount(key: string): T { + return this.addAndReturn(createObjectRefcount(key)); + } } /** diff --git a/node/tests/RedisClient.test.ts b/node/tests/RedisClient.test.ts index 97a1f6e0d7..3c238cf0c8 100644 --- a/node/tests/RedisClient.test.ts +++ b/node/tests/RedisClient.test.ts @@ -266,6 +266,31 @@ describe("RedisClient", () => { }, ); + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + "object refcount transaction test_%p", + async (protocol) => { + const client = await RedisClient.createClient( + getClientConfigurationOption(cluster.getAddresses(), protocol), + ); + + const key = uuidv4(); + const transaction = new Transaction(); + transaction.set(key, "foo"); + transaction.objectRefcount(key); + + const response = await client.exec(transaction); + expect(response).not.toBeNull(); + + if (response != null) { + expect(response.length).toEqual(2); + expect(response[0]).toEqual("OK"); // transaction.set(key, "foo"); + expect(response[1]).toBeGreaterThanOrEqual(1); // transaction.objectRefcount(key); + } + + client.close(); + }, + ); + runBaseTests({ init: async (protocol, clientName?) => { const options = getClientConfigurationOption( diff --git a/node/tests/RedisClusterClient.test.ts b/node/tests/RedisClusterClient.test.ts index 967069597e..6a189b4210 100644 --- a/node/tests/RedisClusterClient.test.ts +++ b/node/tests/RedisClusterClient.test.ts @@ -417,4 +417,29 @@ describe("RedisClusterClient", () => { client.close(); }, ); + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + "object refcount transaction test_%p", + async (protocol) => { + const client = await RedisClusterClient.createClient( + getClientConfigurationOption(cluster.getAddresses(), protocol), + ); + + const key = uuidv4(); + const transaction = new ClusterTransaction(); + transaction.set(key, "foo"); + transaction.objectRefcount(key); + + const response = await client.exec(transaction); + expect(response).not.toBeNull(); + + if (response != null) { + expect(response.length).toEqual(2); + expect(response[0]).toEqual("OK"); // transaction.set(key, "foo"); + expect(response[1]).toBeGreaterThanOrEqual(1); // transaction.objectRefcount(key); + } + + client.close(); + }, + ); }); diff --git a/node/tests/SharedTests.ts b/node/tests/SharedTests.ts index 6e544e4602..7cca08f7f9 100644 --- a/node/tests/SharedTests.ts +++ b/node/tests/SharedTests.ts @@ -3297,6 +3297,23 @@ export function runBaseTests(config: { setTimeout(resolve, numMilliseconds); }); } + + it.each([ProtocolVersion.RESP2, ProtocolVersion.RESP3])( + `object refcount test_%p`, + async (protocol) => { + await runTest(async (client: BaseClient) => { + const key = `{key}:${uuidv4()}`; + const nonExistingKey = `{key}:${uuidv4()}`; + + expect(await client.objectRefcount(nonExistingKey)).toBeNull(); + expect(await client.set(key, "foo")).toEqual("OK"); + expect(await client.objectRefcount(key)).toBeGreaterThanOrEqual( + 1, + ); + }, protocol); + }, + config.timeout, + ); } export function runCommonTests(config: {