Skip to content

Commit d750240

Browse files
committed
Polishing.
Extract BoundHashFieldExpirationOperations to provide a fluent way of interacting with expirations on BoundHashOps and RedisMap.
1 parent c3c1e46 commit d750240

File tree

13 files changed

+415
-242
lines changed

13 files changed

+415
-242
lines changed

src/main/java/org/springframework/data/redis/connection/Hash.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,16 @@
2121
import org.springframework.util.ObjectUtils;
2222

2323
/**
24+
* Types for interacting with Hash data structures.
25+
*
2426
* @author Christoph Strobl
2527
* @since 3.5
2628
*/
2729
public interface Hash {
2830

31+
/**
32+
* Expiration options for Hash Expiation updates.
33+
*/
2934
class FieldExpirationOptions {
3035

3136
private static final FieldExpirationOptions NONE = new FieldExpirationOptions(Condition.ALWAYS);
@@ -124,6 +129,9 @@ public enum Condition {
124129
* Set expiration only when the new expiration is greater than current one.
125130
*/
126131
LT
132+
127133
}
134+
128135
}
136+
129137
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.redis.core;
17+
18+
import java.time.Duration;
19+
import java.time.Instant;
20+
import java.util.concurrent.TimeUnit;
21+
22+
import org.springframework.data.redis.connection.Hash;
23+
import org.springframework.data.redis.core.types.Expiration;
24+
import org.springframework.data.redis.core.types.Expirations;
25+
import org.springframework.lang.Nullable;
26+
27+
/**
28+
* Hash Field Expiration operations bound to a certain hash key and set of hash fields.
29+
*
30+
* @param <HK> type of the hash field names.
31+
* @author Mark Paluch
32+
* @since 3.5
33+
*/
34+
public interface BoundHashFieldExpirationOperations<HK> {
35+
36+
/**
37+
* Apply {@link Expiration} to the hash without any additional constraints.
38+
*
39+
* @param expiration the expiration definition.
40+
* @return changes to the hash fields.
41+
*/
42+
default ExpireChanges<HK> expire(Expiration expiration) {
43+
return expire(expiration, Hash.FieldExpirationOptions.none());
44+
}
45+
46+
/**
47+
* Apply {@link Expiration} to the hash fields given {@link Hash.FieldExpirationOptions expiration options}.
48+
*
49+
* @param expiration the expiration definition.
50+
* @param options expiration options.
51+
* @return changes to the hash fields.
52+
*/
53+
ExpireChanges<HK> expire(Expiration expiration, Hash.FieldExpirationOptions options);
54+
55+
/**
56+
* Set time to live for given {@code hashKey}.
57+
*
58+
* @param timeout the amount of time after which the key will be expired, must not be {@literal null}.
59+
* @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is
60+
* deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time
61+
* is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition
62+
* is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline /
63+
* transaction.
64+
* @throws IllegalArgumentException if the timeout is {@literal null}.
65+
* @see <a href="https://redis.io/docs/latest/commands/hexpire/">Redis Documentation: HEXPIRE</a>
66+
* @since 3.5
67+
*/
68+
@Nullable
69+
ExpireChanges<HK> expire(Duration timeout);
70+
71+
/**
72+
* Set the expiration for given {@code hashKey} as a {@literal date} timestamp.
73+
*
74+
* @param expireAt must not be {@literal null}.
75+
* @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is
76+
* deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating
77+
* expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX |
78+
* GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in
79+
* pipeline / transaction.
80+
* @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}.
81+
* @see <a href="https://redis.io/docs/latest/commands/hexpireat/">Redis Documentation: HEXPIRE</a>
82+
* @since 3.5
83+
*/
84+
@Nullable
85+
ExpireChanges<HK> expireAt(Instant expireAt);
86+
87+
/**
88+
* Remove the expiration from given {@code hashKey} .
89+
*
90+
* @return a list of {@link Long} values for each of the fields provided: {@code 1} indicating expiration time is
91+
* removed; {@code -1} field has no expiration time to be removed; {@code -2} indicating there is no such
92+
* field; {@literal null} when used in pipeline / transaction.
93+
* @see <a href="https://redis.io/docs/latest/commands/hpersist/">Redis Documentation: HPERSIST</a>
94+
* @since 3.5
95+
*/
96+
@Nullable
97+
ExpireChanges<HK> persist();
98+
99+
/**
100+
* Get the time to live for {@code hashKey} in seconds.
101+
*
102+
* @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative
103+
* value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration
104+
* time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline /
105+
* transaction.
106+
* @see <a href="https://redis.io/docs/latest/commands/httl/">Redis Documentation: HTTL</a>
107+
* @since 3.5
108+
*/
109+
@Nullable
110+
Expirations<HK> getTimeToLive();
111+
112+
/**
113+
* Get the time to live for {@code hashKey} and convert it to the given {@link TimeUnit}.
114+
*
115+
* @param timeUnit must not be {@literal null}.
116+
* @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative
117+
* value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration
118+
* time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline /
119+
* transaction.
120+
* @see <a href="https://redis.io/docs/latest/commands/httl/">Redis Documentation: HTTL</a>
121+
* @since 3.5
122+
*/
123+
@Nullable
124+
Expirations<HK> getTimeToLive(TimeUnit timeUnit);
125+
126+
}

src/main/java/org/springframework/data/redis/core/BoundHashOperations.java

Lines changed: 38 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,12 @@
1515
*/
1616
package org.springframework.data.redis.core;
1717

18-
import java.time.Duration;
19-
import java.time.Instant;
18+
import java.util.Arrays;
2019
import java.util.Collection;
2120
import java.util.List;
2221
import java.util.Map;
2322
import java.util.Set;
24-
import java.util.concurrent.TimeUnit;
2523

26-
import org.springframework.data.redis.connection.Hash.FieldExpirationOptions;
27-
import org.springframework.data.redis.core.types.Expiration;
28-
import org.springframework.data.redis.core.types.Expirations;
2924
import org.springframework.lang.Nullable;
3025

3126
/**
@@ -160,88 +155,6 @@ public interface BoundHashOperations<H, HK, HV> extends BoundKeyOperations<H> {
160155
@Nullable
161156
Long lengthOfValue(HK hashKey);
162157

163-
default ExpireChanges<HK> expire(Expiration expiration, Collection<HK> hashKeys) {
164-
return expire(expiration, FieldExpirationOptions.none(), hashKeys);
165-
}
166-
167-
ExpireChanges<HK> expire(Expiration expiration, FieldExpirationOptions options, Collection<HK> hashKeys);
168-
169-
/**
170-
* Set time to live for given {@code hashKey} .
171-
*
172-
* @param timeout the amount of time after which the key will be expired, must not be {@literal null}.
173-
* @param hashKeys must not be {@literal null}.
174-
* @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is
175-
* deleted already due to expiration, or provided expiry interval is 0; {@code 1} indicating expiration time
176-
* is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX | GT | LT condition
177-
* is not met); {@code -2} indicating there is no such field; {@literal null} when used in pipeline /
178-
* transaction.
179-
* @throws IllegalArgumentException if the timeout is {@literal null}.
180-
* @see <a href="https://redis.io/docs/latest/commands/hexpire/">Redis Documentation: HEXPIRE</a>
181-
* @since 3.5
182-
*/
183-
@Nullable
184-
ExpireChanges<HK> expire(Duration timeout, Collection<HK> hashKeys);
185-
186-
/**
187-
* Set the expiration for given {@code hashKey} as a {@literal date} timestamp.
188-
*
189-
* @param expireAt must not be {@literal null}.
190-
* @param hashKeys must not be {@literal null}.
191-
* @return a list of {@link Long} values for each of the fields provided: {@code 2} indicating the specific field is
192-
* deleted already due to expiration, or provided expiry interval is in the past; {@code 1} indicating
193-
* expiration time is set/updated; {@code 0} indicating the expiration time is not set (a provided NX | XX |
194-
* GT | LT condition is not met); {@code -2} indicating there is no such field; {@literal null} when used in
195-
* pipeline / transaction.
196-
* @throws IllegalArgumentException if the instant is {@literal null} or too large to represent as a {@code Date}.
197-
* @see <a href="https://redis.io/docs/latest/commands/hexpireat/">Redis Documentation: HEXPIRE</a>
198-
* @since 3.5
199-
*/
200-
@Nullable
201-
ExpireChanges<HK> expireAt(Instant expireAt, Collection<HK> hashKeys);
202-
203-
/**
204-
* Remove the expiration from given {@code hashKey} .
205-
*
206-
* @param hashKeys must not be {@literal null}.
207-
* @return a list of {@link Long} values for each of the fields provided: {@code 1} indicating expiration time is
208-
* removed; {@code -1} field has no expiration time to be removed; {@code -2} indicating there is no such
209-
* field; {@literal null} when used in pipeline / transaction.
210-
* @see <a href="https://redis.io/docs/latest/commands/hpersist/">Redis Documentation: HPERSIST</a>
211-
* @since 3.5
212-
*/
213-
@Nullable
214-
ExpireChanges<HK> persist(Collection<HK> hashKeys);
215-
216-
/**
217-
* Get the time to live for {@code hashKey} in seconds.
218-
*
219-
* @param hashKeys must not be {@literal null}.
220-
* @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative
221-
* value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration
222-
* time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline /
223-
* transaction.
224-
* @see <a href="https://redis.io/docs/latest/commands/httl/">Redis Documentation: HTTL</a>
225-
* @since 3.5
226-
*/
227-
@Nullable
228-
Expirations<HK> getTimeToLive(Collection<HK> hashKeys);
229-
230-
/**
231-
* Get the time to live for {@code hashKey} and convert it to the given {@link TimeUnit}.
232-
*
233-
* @param timeUnit must not be {@literal null}.
234-
* @param hashKeys must not be {@literal null}.
235-
* @return a list of {@link Long} values for each of the fields provided: the time to live in seconds; or a negative
236-
* value to signal an error. The command returns {@code -1} if the key exists but has no associated expiration
237-
* time. The command returns {@code -2} if the key does not exist; {@literal null} when used in pipeline /
238-
* transaction.
239-
* @see <a href="https://redis.io/docs/latest/commands/httl/">Redis Documentation: HTTL</a>
240-
* @since 3.5
241-
*/
242-
@Nullable
243-
Expirations<HK> getTimeToLive(TimeUnit timeUnit, Collection<HK> hashKeys);
244-
245158
/**
246159
* Get size of hash at the bound key.
247160
*
@@ -302,8 +215,45 @@ default ExpireChanges<HK> expire(Expiration expiration, Collection<HK> hashKeys)
302215
*/
303216
Cursor<Map.Entry<HK, HV>> scan(ScanOptions options);
304217

218+
/**
219+
* Returns a bound operations object to perform operations on the hash field expiration for all hash fields at the
220+
* bound {@code key}. Operations on the expiration object obtain keys at the time of invoking any expiration
221+
* operation.
222+
*
223+
* @return the bound operations object to perform operations on the hash field expiration.
224+
* @since 3.5
225+
*/
226+
default BoundHashFieldExpirationOperations<HK> expiration() {
227+
return new DefaultBoundHashFieldExpirationOperations<>(getOperations().opsForHash(), getKey(), this::keys);
228+
}
229+
230+
/**
231+
* Returns a bound operations object to perform operations on the hash field expiration for all hash fields at the
232+
* bound {@code key} for the given hash fields.
233+
*
234+
* @param hashFields collection of hash fields to operate on.
235+
* @return the bound operations object to perform operations on the hash field expiration.
236+
* @since 3.5
237+
*/
238+
default BoundHashFieldExpirationOperations<HK> expiration(HK... hashFields) {
239+
return expiration(Arrays.asList(hashFields));
240+
}
241+
242+
/**
243+
* Returns a bound operations object to perform operations on the hash field expiration for all hash fields at the
244+
* bound {@code key} for the given hash fields.
245+
*
246+
* @param hashFields collection of hash fields to operate on.
247+
* @return the bound operations object to perform operations on the hash field expiration.
248+
* @since 3.5
249+
*/
250+
default BoundHashFieldExpirationOperations<HK> expiration(Collection<HK> hashFields) {
251+
return new DefaultBoundHashFieldExpirationOperations<>(getOperations().opsForHash(), getKey(), () -> hashFields);
252+
}
253+
305254
/**
306255
* @return never {@literal null}.
307256
*/
308257
RedisOperations<H, ?> getOperations();
258+
309259
}

0 commit comments

Comments
 (0)