From 2c4eaac1c1ef07a6b33bfe2ac4d1945912b09c8c Mon Sep 17 00:00:00 2001 From: Viet Hoang <1300077+vietqhoang@users.noreply.github.com> Date: Wed, 29 Oct 2025 21:31:20 -0700 Subject: [PATCH] Add `hexpire` and `httl` Introduced in 7.4.0, https://redis.io/docs/latest/commands/hexpire/ --- lib/redis/commands/hashes.rb | 32 ++++++++++++++++++++++++++++++++ lib/redis/distributed.rb | 8 ++++++++ test/lint/hashes.rb | 23 +++++++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/lib/redis/commands/hashes.rb b/lib/redis/commands/hashes.rb index a6e9c10c4..dfefc92aa 100644 --- a/lib/redis/commands/hashes.rb +++ b/lib/redis/commands/hashes.rb @@ -253,6 +253,38 @@ def hscan_each(key, **options, &block) break if cursor == "0" end end + + # Sets the time to live in seconds for one or more fields. + # + # @example + # redis.hset("hash", "f1", "v1") + # redis.hexpire("hash", 10, "f1", "f2") # => [1, -2] + # + # @param [String] key + # @param [Integer] ttl + # @param [Array] fields + # @return [Array] Feedback on if the fields have been updated. + # + # See https://redis.io/docs/latest/commands/hexpire/#return-information for array reply. + def hexpire(key, ttl, *fields) + send_command([:hexpire, key, ttl, 'FIELDS', fields.length, *fields]) + end + + # Returns the time to live in seconds for one or more fields. + # + # @example + # redis.hset("hash", "f1", "v1", "f2", "v2") + # redis.hexpire("hash", 10, "f1") # => [1] + # redis.httl("hash", "f1", "f2", "f3") # => [10, -1, -2] + # + # @param [String] key + # @param [Array] fields + # @return [Array] Feedback on the TTL of the fields. + # + # See https://redis.io/docs/latest/commands/httl/#return-information for array reply. + def httl(key, *fields) + send_command([:httl, key, 'FIELDS', fields.length, *fields]) + end end end end diff --git a/lib/redis/distributed.rb b/lib/redis/distributed.rb index 91bfd47ad..3bbe7b63a 100644 --- a/lib/redis/distributed.rb +++ b/lib/redis/distributed.rb @@ -918,6 +918,14 @@ def hgetall(key) node_for(key).hgetall(key) end + def hexpire(key, ttl, *fields) + node_for(key).hexpire(key, ttl, *fields) + end + + def httl(key, ttl, *fields) + node_for(key).httl(key, ttl, *fields) + end + # Scan a hash def hscan(key, cursor, **options) node_for(key).hscan(key, cursor, **options) diff --git a/test/lint/hashes.rb b/test/lint/hashes.rb index 698c3be22..3b1479c8d 100644 --- a/test/lint/hashes.rb +++ b/test/lint/hashes.rb @@ -227,5 +227,28 @@ def test_hscan expected = ['0', [%w[f1 Jack], %w[f2 33]]] assert_equal expected, redis.hscan('foo', 0) end + + def test_hexpire + target_version "7.4.0" do + r.hset("foo", "f1", "v2") + + assert_equal [1], r.hexpire("foo", 4, "f1") + assert_in_range(1..4, r.httl("foo", "f1")[0]) + end + end + + def test_httl + target_version "7.4.0" do + assert [-2], r.httl("foo", "f1") + + r.hset("foo", "f1", "v2") + + assert [-1], r.httl("foo", "f1") + + r.hexpire("foo", 4, "f1") + + assert_in_range(1..4, r.httl("foo", "f1")[0]) + end + end end end