Skip to content

Commit ce3f301

Browse files
authored
Merge pull request #1090 from araishikeiwai/expire-options
Add support for EXPIRE command group options (NX/XX/GT/LT)
2 parents ad7a0f9 + 6fa362c commit ce3f301

File tree

2 files changed

+108
-8
lines changed

2 files changed

+108
-8
lines changed

lib/redis/commands/keys.rb

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,40 @@ def persist(key)
6969
#
7070
# @param [String] key
7171
# @param [Integer] seconds time to live
72+
# @param [Hash] options
73+
# - `:nx => true`: Set expiry only when the key has no expiry.
74+
# - `:xx => true`: Set expiry only when the key has an existing expiry.
75+
# - `:gt => true`: Set expiry only when the new expiry is greater than current one.
76+
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
7277
# @return [Boolean] whether the timeout was set or not
73-
def expire(key, seconds)
74-
send_command([:expire, key, seconds], &Boolify)
78+
def expire(key, seconds, nx: nil, xx: nil, gt: nil, lt: nil)
79+
args = [:expire, key, seconds]
80+
args << "NX" if nx
81+
args << "XX" if xx
82+
args << "GT" if gt
83+
args << "LT" if lt
84+
85+
send_command(args, &Boolify)
7586
end
7687

7788
# Set the expiration for a key as a UNIX timestamp.
7889
#
7990
# @param [String] key
8091
# @param [Integer] unix_time expiry time specified as a UNIX timestamp
92+
# @param [Hash] options
93+
# - `:nx => true`: Set expiry only when the key has no expiry.
94+
# - `:xx => true`: Set expiry only when the key has an existing expiry.
95+
# - `:gt => true`: Set expiry only when the new expiry is greater than current one.
96+
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
8197
# @return [Boolean] whether the timeout was set or not
82-
def expireat(key, unix_time)
83-
send_command([:expireat, key, unix_time], &Boolify)
98+
def expireat(key, unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
99+
args = [:expireat, key, unix_time]
100+
args << "NX" if nx
101+
args << "XX" if xx
102+
args << "GT" if gt
103+
args << "LT" if lt
104+
105+
send_command(args, &Boolify)
84106
end
85107

86108
# Get the time to live (in seconds) for a key.
@@ -103,18 +125,40 @@ def ttl(key)
103125
#
104126
# @param [String] key
105127
# @param [Integer] milliseconds time to live
128+
# @param [Hash] options
129+
# - `:nx => true`: Set expiry only when the key has no expiry.
130+
# - `:xx => true`: Set expiry only when the key has an existing expiry.
131+
# - `:gt => true`: Set expiry only when the new expiry is greater than current one.
132+
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
106133
# @return [Boolean] whether the timeout was set or not
107-
def pexpire(key, milliseconds)
108-
send_command([:pexpire, key, milliseconds], &Boolify)
134+
def pexpire(key, milliseconds, nx: nil, xx: nil, gt: nil, lt: nil)
135+
args = [:pexpire, key, milliseconds]
136+
args << "NX" if nx
137+
args << "XX" if xx
138+
args << "GT" if gt
139+
args << "LT" if lt
140+
141+
send_command(args, &Boolify)
109142
end
110143

111144
# Set the expiration for a key as number of milliseconds from UNIX Epoch.
112145
#
113146
# @param [String] key
114147
# @param [Integer] ms_unix_time expiry time specified as number of milliseconds from UNIX Epoch.
148+
# @param [Hash] options
149+
# - `:nx => true`: Set expiry only when the key has no expiry.
150+
# - `:xx => true`: Set expiry only when the key has an existing expiry.
151+
# - `:gt => true`: Set expiry only when the new expiry is greater than current one.
152+
# - `:lt => true`: Set expiry only when the new expiry is less than current one.
115153
# @return [Boolean] whether the timeout was set or not
116-
def pexpireat(key, ms_unix_time)
117-
send_command([:pexpireat, key, ms_unix_time], &Boolify)
154+
def pexpireat(key, ms_unix_time, nx: nil, xx: nil, gt: nil, lt: nil)
155+
args = [:pexpireat, key, ms_unix_time]
156+
args << "NX" if nx
157+
args << "XX" if xx
158+
args << "GT" if gt
159+
args << "LT" if lt
160+
161+
send_command(args, &Boolify)
118162
end
119163

120164
# Get the time to live (in milliseconds) for a key.

test/lint/value_types.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,20 @@ def test_expire
6666
r.set("foo", "s1")
6767
assert r.expire("foo", 2)
6868
assert_in_range 0..2, r.ttl("foo")
69+
70+
target_version "7.0.0" do
71+
r.set("bar", "s2")
72+
refute r.expire("bar", 5, xx: true)
73+
assert r.expire("bar", 5, nx: true)
74+
refute r.expire("bar", 5, nx: true)
75+
assert r.expire("bar", 5, xx: true)
76+
77+
r.expire("bar", 10)
78+
refute r.expire("bar", 15, lt: true)
79+
refute r.expire("bar", 5, gt: true)
80+
assert r.expire("bar", 15, gt: true)
81+
assert r.expire("bar", 5, lt: true)
82+
end
6983
end
7084

7185
def test_pexpire
@@ -74,12 +88,40 @@ def test_pexpire
7488
assert r.pexpire("foo", 2000)
7589
assert_in_range 0..2, r.ttl("foo")
7690
end
91+
92+
target_version "7.0.0" do
93+
r.set("bar", "s2")
94+
refute r.pexpire("bar", 5_000, xx: true)
95+
assert r.pexpire("bar", 5_000, nx: true)
96+
refute r.pexpire("bar", 5_000, nx: true)
97+
assert r.pexpire("bar", 5_000, xx: true)
98+
99+
r.pexpire("bar", 10_000)
100+
refute r.pexpire("bar", 15_000, lt: true)
101+
refute r.pexpire("bar", 5_000, gt: true)
102+
assert r.pexpire("bar", 15_000, gt: true)
103+
assert r.pexpire("bar", 5_000, lt: true)
104+
end
77105
end
78106

79107
def test_expireat
80108
r.set("foo", "s1")
81109
assert r.expireat("foo", (Time.now + 2).to_i)
82110
assert_in_range 0..2, r.ttl("foo")
111+
112+
target_version "7.0.0" do
113+
r.set("bar", "s2")
114+
refute r.expire_at("bar", (Time.now + 5).to_i, xx: true)
115+
assert r.expire_at("bar", (Time.now + 5).to_i, nx: true)
116+
refute r.expire_at("bar", (Time.now + 5).to_i, nx: true)
117+
assert r.expire_at("bar", (Time.now + 5).to_i, xx: true)
118+
119+
r.expire_at("bar", 10)
120+
refute r.expire_at("bar", (Time.now + 15).to_i, lt: true)
121+
refute r.expire_at("bar", (Time.now + 5).to_i, gt: true)
122+
assert r.expire_at("bar", (Time.now + 15).to_i, gt: true)
123+
assert r.expire_at("bar", (Time.now + 5).to_i, lt: true)
124+
end
83125
end
84126

85127
def test_pexpireat
@@ -88,6 +130,20 @@ def test_pexpireat
88130
assert r.pexpireat("foo", (Time.now + 2).to_i * 1_000)
89131
assert_in_range 0..2, r.ttl("foo")
90132
end
133+
134+
target_version "7.0.0" do
135+
r.set("bar", "s2")
136+
refute r.expire_at("bar", (Time.now + 5).to_i * 1_000, xx: true)
137+
assert r.expire_at("bar", (Time.now + 5).to_i * 1_000, nx: true)
138+
refute r.expire_at("bar", (Time.now + 5).to_i * 1_000, nx: true)
139+
assert r.expire_at("bar", (Time.now + 5).to_i * 1_000, xx: true)
140+
141+
r.expire_at("bar", 10)
142+
refute r.expire_at("bar", (Time.now + 15).to_i * 1_000, lt: true)
143+
refute r.expire_at("bar", (Time.now + 5).to_i * 1_000, gt: true)
144+
assert r.expire_at("bar", (Time.now + 15).to_i * 1_000, gt: true)
145+
assert r.expire_at("bar", (Time.now + 5).to_i * 1_000, lt: true)
146+
end
91147
end
92148

93149
def test_persist

0 commit comments

Comments
 (0)