Skip to content

Commit 121202c

Browse files
mlb5000PavelPashov
andauthored
feat: Implement hexpire for #1898 (#1918)
* Implement hexpire * feat: implement proper hexpire command signatures and tests Original implementation by @mlb5000 * chore: update ioredis/comands version --------- Co-authored-by: Pavel Pashov <[email protected]>
1 parent 541b15d commit 121202c

File tree

5 files changed

+99
-8
lines changed

5 files changed

+99
-8
lines changed

bin/returnTypes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ module.exports = {
142142
hdel: "number",
143143
hello: "unknown[]",
144144
hexists: "number",
145+
hexpire: "number[]",
145146
hget: "string | null",
146147
hgetall: "[field: string, value: string][]",
147148
hincrby: "number",

lib/utils/RedisCommander.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3870,6 +3870,23 @@ interface RedisCommander<Context extends ClientContext = { type: "default" }> {
38703870
callback?: Callback<number>
38713871
): Result<number, Context>;
38723872

3873+
/**
3874+
* Set expiry for hash field using relative time to expire (seconds)
3875+
* - _group_: hash
3876+
* - _complexity_: O(N) where N is the number of specified fields
3877+
* - _since_: 7.4.0
3878+
*/
3879+
hexpire(...args: [key: RedisKey, seconds: number | string, fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[], callback: Callback<number[]>]): Result<number[], Context>;
3880+
hexpire(...args: [key: RedisKey, seconds: number | string, fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[]]): Result<number[], Context>;
3881+
hexpire(...args: [key: RedisKey, seconds: number | string, nx: 'NX', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[], callback: Callback<number[]>]): Result<number[], Context>;
3882+
hexpire(...args: [key: RedisKey, seconds: number | string, nx: 'NX', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[]]): Result<number[], Context>;
3883+
hexpire(...args: [key: RedisKey, seconds: number | string, xx: 'XX', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[], callback: Callback<number[]>]): Result<number[], Context>;
3884+
hexpire(...args: [key: RedisKey, seconds: number | string, xx: 'XX', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[]]): Result<number[], Context>;
3885+
hexpire(...args: [key: RedisKey, seconds: number | string, gt: 'GT', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[], callback: Callback<number[]>]): Result<number[], Context>;
3886+
hexpire(...args: [key: RedisKey, seconds: number | string, gt: 'GT', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[]]): Result<number[], Context>;
3887+
hexpire(...args: [key: RedisKey, seconds: number | string, lt: 'LT', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[], callback: Callback<number[]>]): Result<number[], Context>;
3888+
hexpire(...args: [key: RedisKey, seconds: number | string, lt: 'LT', fieldsToken: 'FIELDS', numfields: number | string, ...fields: (string | Buffer)[]]): Result<number[], Context>;
3889+
38733890
/**
38743891
* Get the value of a hash field
38753892
* - _group_: hash

package-lock.json

Lines changed: 8 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"url": "https://opencollective.com/ioredis"
4242
},
4343
"dependencies": {
44-
"@ioredis/commands": "^1.1.1",
44+
"@ioredis/commands": "^1.3.0",
4545
"cluster-key-slot": "^1.1.0",
4646
"debug": "^4.3.4",
4747
"denque": "^2.1.0",

test/functional/hexpire.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import Redis from "../../lib/Redis";
2+
import { expect } from "chai";
3+
4+
describe("hexpire", () => {
5+
const hashKey = "test_hash_key";
6+
const field = "test_field";
7+
8+
it("should handle non-existing field", async () => {
9+
const redis = new Redis();
10+
11+
const result = await redis.hexpire(
12+
"non_existing_hash_key",
13+
60,
14+
"NX",
15+
"FIELDS",
16+
1,
17+
"non_existing_field"
18+
);
19+
20+
expect(result).to.deep.equal([-2]);
21+
});
22+
23+
it("should handle existing field", async () => {
24+
const redis = new Redis();
25+
26+
await redis.hset(hashKey, field, "value");
27+
28+
const result = await redis.hexpire(hashKey, 60, "FIELDS", 1, field);
29+
30+
expect(result).to.deep.equal([1]);
31+
});
32+
33+
it("should return 0 when condition is not met", async () => {
34+
const redis = new Redis();
35+
36+
await redis.hset(hashKey, field, "value");
37+
await redis.hexpire(hashKey, 60, "FIELDS", 1, field); // Set initial expiry
38+
39+
// Try to set expiry with NX when field already has expiry
40+
const result = await redis.hexpire(hashKey, 120, "NX", "FIELDS", 1, field);
41+
42+
expect(result).to.deep.equal([0]);
43+
});
44+
45+
it("should return 2 when expiring field with 0 seconds", async () => {
46+
const redis = new Redis();
47+
48+
await redis.hset(hashKey, field, "value");
49+
50+
const result = await redis.hexpire(hashKey, 0, "FIELDS", 1, field);
51+
52+
expect(result).to.deep.equal([2]);
53+
});
54+
55+
it("should expire multiple fields", async () => {
56+
const redis = new Redis();
57+
58+
await redis.hset(hashKey, field, "value", "field2", "value2");
59+
60+
const result = await redis.hexpire(
61+
hashKey,
62+
60,
63+
"FIELDS",
64+
3,
65+
field,
66+
"field2",
67+
"non_existing_field"
68+
);
69+
70+
expect(result).to.deep.equal([1, 1, -2]);
71+
});
72+
});

0 commit comments

Comments
 (0)