Skip to content

Commit 8ec4736

Browse files
viktoriya-kutsarovaonobc
authored andcommitted
Add HGETDEL, HGETEX and HSETEX hash commands
Adds the following commands: * HGETDEL - get and delete the value of one or more fields of a given hash key. When the last field is deleted, the key will also be deleted * HGETEX - get the value of one or more fields of a given hash key and optionally set their expiration time or time-to-live (TTL) * HSETEX - set the value of one or more fields of a given hash key, and optionally set their expiration time or time-to-live (TTL) Original Pull Request: #3226 Resolves: #3211
1 parent b09f752 commit 8ec4736

26 files changed

+2704
-23
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
VERSION?=7.4.0
15+
VERSION?=8.0.0
1616
PROJECT?=redis
1717
GH_ORG?=redis
1818
SPRING_PROFILE?=ci

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

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
import org.apache.commons.logging.Log;
2525
import org.apache.commons.logging.LogFactory;
26+
import org.jetbrains.annotations.NotNull;
27+
import org.jspecify.annotations.NonNull;
2628
import org.jspecify.annotations.NullUnmarked;
2729
import org.jspecify.annotations.Nullable;
2830
import org.springframework.core.convert.converter.Converter;
@@ -1615,6 +1617,21 @@ public List<String> hVals(String key) {
16151617
return convertAndReturn(delegate.hVals(serialize(key)), byteListToStringList);
16161618
}
16171619

1620+
@Override
1621+
public List<String> hGetDel(String key, String... fields) {
1622+
return convertAndReturn(delegate.hGetDel(serialize(key), serializeMulti(fields)), byteListToStringList);
1623+
}
1624+
1625+
@Override
1626+
public List<String> hGetEx(String key, Expiration expiration, String... fields) {
1627+
return convertAndReturn(delegate.hGetEx(serialize(key), expiration, serializeMulti(fields)), byteListToStringList);
1628+
}
1629+
1630+
@Override
1631+
public Boolean hSetEx(@NonNull String key, @NonNull Map<@NonNull String, String> hashes, HashFieldSetOption condition, Expiration expiration) {
1632+
return convertAndReturn(delegate.hSetEx(serialize(key), serialize(hashes), condition, expiration), Converters.identityConverter());
1633+
}
1634+
16181635
@Override
16191636
public Long incr(String key) {
16201637
return incr(serialize(key));
@@ -2593,6 +2610,21 @@ public List<Long> hTtl(byte[] key, TimeUnit timeUnit, byte[]... fields) {
25932610
return this.delegate.hTtl(key, timeUnit, fields);
25942611
}
25952612

2613+
@Override
2614+
public List<byte[]> hGetDel(@NotNull byte[] key, @NotNull byte[]... fields) {
2615+
return convertAndReturn(delegate.hGetDel(key, fields), Converters.identityConverter());
2616+
}
2617+
2618+
@Override
2619+
public List<byte[]> hGetEx(@NotNull byte[] key, Expiration expiration, @NotNull byte[]... fields) {
2620+
return convertAndReturn(delegate.hGetEx(key, expiration, fields), Converters.identityConverter());
2621+
}
2622+
2623+
@Override
2624+
public Boolean hSetEx(@NotNull byte[] key, @NonNull Map<byte[], byte[]> hashes, HashFieldSetOption condition, Expiration expiration) {
2625+
return convertAndReturn(delegate.hSetEx(key, hashes, condition, expiration), Converters.identityConverter());
2626+
}
2627+
25962628
public @Nullable List<Long> applyExpiration(String key,
25972629
org.springframework.data.redis.core.types.Expiration expiration,
25982630
ExpirationOptions options, String... fields) {

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,27 @@ default List<Long> hpTtl(byte[] key, byte[]... fields) {
16021602
return hashCommands().hpTtl(key, fields);
16031603
}
16041604

1605+
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
1606+
@Override
1607+
@Deprecated
1608+
default List<byte[]> hGetDel(byte[] key, byte[]... fields) {
1609+
return hashCommands().hGetDel(key, fields);
1610+
}
1611+
1612+
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
1613+
@Override
1614+
@Deprecated
1615+
default List<byte[]> hGetEx(byte[] key, Expiration expiration, byte[]... fields) {
1616+
return hashCommands().hGetEx(key, expiration, fields);
1617+
}
1618+
1619+
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
1620+
@Override
1621+
@Deprecated
1622+
default Boolean hSetEx(byte[] key, Map<byte[], byte[]> hashes, HashFieldSetOption condition, Expiration expiration) {
1623+
return hashCommands().hSetEx(key, hashes, condition, expiration);
1624+
}
1625+
16051626
/** @deprecated in favor of {@link RedisConnection#hashCommands()}}. */
16061627
@Override
16071628
@Deprecated

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

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ public interface ReactiveHashCommands {
5858
*
5959
* @author Christoph Strobl
6060
* @author Tihomir Mateev
61+
* @author Viktoriya Kutsarova
6162
*/
6263
class HashFieldsCommand extends KeyCommand {
6364

@@ -1255,4 +1256,255 @@ default Flux<Long> hpTtl(ByteBuffer key, List<ByteBuffer> fields) {
12551256
*/
12561257
Flux<NumericResponse<HashFieldsCommand, Long>> hpTtl(Publisher<HashFieldsCommand> commands);
12571258

1259+
1260+
/**
1261+
* {@literal HGETDEL} {@link Command}.
1262+
*
1263+
* @author Viktoriya Kutsarova
1264+
* @see <a href="https://redis.io/commands/hgetdel">Redis Documentation: HGETDEL</a>
1265+
*/
1266+
class HGetDelCommand extends HashFieldsCommand {
1267+
1268+
private HGetDelCommand(@Nullable ByteBuffer key, List<ByteBuffer> fields) {
1269+
super(key, fields);
1270+
}
1271+
1272+
/**
1273+
* Creates a new {@link HGetDelCommand} given a {@link ByteBuffer field name}.
1274+
*
1275+
* @param field must not be {@literal null}.
1276+
* @return a new {@link HGetDelCommand} for a {@link ByteBuffer field name}.
1277+
*/
1278+
public static HGetDelCommand field(ByteBuffer field) {
1279+
1280+
Assert.notNull(field, "Field must not be null");
1281+
1282+
return new HGetDelCommand(null, Collections.singletonList(field));
1283+
}
1284+
1285+
/**
1286+
* Creates a new {@link HGetDelCommand} given a {@link Collection} of field names.
1287+
*
1288+
* @param fields must not be {@literal null}.
1289+
* @return a new {@link HGetDelCommand} for a {@link Collection} of field names.
1290+
*/
1291+
public static HGetDelCommand fields(Collection<ByteBuffer> fields) {
1292+
1293+
Assert.notNull(fields, "Fields must not be null");
1294+
1295+
return new HGetDelCommand(null, new ArrayList<>(fields));
1296+
}
1297+
1298+
/**
1299+
* Applies the hash {@literal key}. Constructs a new command instance with all previously configured properties.
1300+
*
1301+
* @param key must not be {@literal null}.
1302+
* @return a new {@link HGetDelCommand} with {@literal key} applied.
1303+
*/
1304+
public HGetDelCommand from(ByteBuffer key) {
1305+
1306+
Assert.notNull(key, "Key must not be null");
1307+
1308+
return new HGetDelCommand(key, getFields());
1309+
}
1310+
}
1311+
1312+
1313+
/**
1314+
* Get and delete the value of one or more {@literal fields} from hash at {@literal key}. Values are returned in the
1315+
* order of the requested keys. Absent field values are represented using {@literal null} in the resulting {@link List}.
1316+
* When the last field is deleted, the key will also be deleted.
1317+
*
1318+
* @param key must not be {@literal null}.
1319+
* @param fields must not be {@literal null}.
1320+
* @return never {@literal null}.
1321+
* @see <a href="https://redis.io/commands/hgetdel">Redis Documentation: HGETDEL</a>
1322+
*/
1323+
default Mono<List<ByteBuffer>> hGetDel(ByteBuffer key, Collection<ByteBuffer> fields) {
1324+
1325+
Assert.notNull(key, "Key must not be null");
1326+
Assert.notNull(fields, "Fields must not be null");
1327+
1328+
return hGetDel(Mono.just(HGetDelCommand.fields(fields).from(key))).next().map(MultiValueResponse::getOutput);
1329+
}
1330+
1331+
/**
1332+
* Get and delete the value of one or more {@literal fields} from hash at {@literal key}. Values are returned in the
1333+
* order of the requested keys. Absent field values are represented using {@literal null} in the resulting {@link List}.
1334+
* When the last field is deleted, the key will also be deleted.
1335+
*
1336+
* @param commands must not be {@literal null}.
1337+
* @return never {@literal null}.
1338+
* @see <a href="https://redis.io/commands/hgetdel">Redis Documentation: HGETDEL</a>
1339+
*/
1340+
Flux<MultiValueResponse<HGetDelCommand, ByteBuffer>> hGetDel(Publisher<HGetDelCommand> commands);
1341+
1342+
class HGetExCommand extends HashFieldsCommand {
1343+
1344+
private final Expiration expiration;
1345+
1346+
private HGetExCommand(@Nullable ByteBuffer key, List<ByteBuffer> fields, Expiration expiration) {
1347+
1348+
super(key, fields);
1349+
1350+
this.expiration = expiration;
1351+
}
1352+
1353+
/**
1354+
* Creates a new {@link HGetExCommand}.
1355+
*
1356+
* @param fields the {@code fields} names to apply expiration to
1357+
* @param expiration the {@link Expiration} to apply to the given {@literal fields}.
1358+
* @return new instance of {@link HGetExCommand}.
1359+
*/
1360+
public static HGetExCommand expire(List<ByteBuffer> fields, Expiration expiration) {
1361+
return new HGetExCommand(null, fields, expiration);
1362+
}
1363+
1364+
/**
1365+
* @param key the {@literal key} from which to expire the {@literal fields} from.
1366+
* @return new instance of {@link HashExpireCommand}.
1367+
*/
1368+
public HGetExCommand from(ByteBuffer key) {
1369+
return new HGetExCommand(key, getFields(), expiration);
1370+
}
1371+
1372+
/**
1373+
* Creates a new {@link HGetExCommand}.
1374+
*
1375+
* @param fields the {@code fields} names to apply expiration to
1376+
* @return new instance of {@link HGetExCommand}.
1377+
*/
1378+
public HGetExCommand fields(Collection<ByteBuffer> fields) {
1379+
return new HGetExCommand(getKey(), new ArrayList<>(fields), expiration);
1380+
}
1381+
1382+
public Expiration getExpiration() {
1383+
return expiration;
1384+
}
1385+
}
1386+
1387+
/**
1388+
* Get the value of one or more {@literal fields} from hash at {@literal key} and optionally set expiration time or
1389+
* time-to-live (TTL) for given {@literal fields}.
1390+
*
1391+
* @param key must not be {@literal null}.
1392+
* @param fields must not be {@literal null}.
1393+
* @return never {@literal null}.
1394+
* @see <a href="https://redis.io/commands/hgetex">Redis Documentation: HGETEX</a>
1395+
*/
1396+
default Mono<List<ByteBuffer>> hGetEx(ByteBuffer key, Expiration expiration, List<ByteBuffer> fields) {
1397+
1398+
Assert.notNull(key, "Key must not be null");
1399+
Assert.notNull(fields, "Fields must not be null");
1400+
1401+
return hGetEx(Mono.just(HGetExCommand.expire(fields, expiration).from(key))).next().map(MultiValueResponse::getOutput);
1402+
}
1403+
1404+
/**
1405+
* Get the value of one or more {@literal fields} from hash at {@literal key} and optionally set expiration time or
1406+
* time-to-live (TTL) for given {@literal fields}.
1407+
*
1408+
* @param commands must not be {@literal null}.
1409+
* @return never {@literal null}.
1410+
* @see <a href="https://redis.io/commands/hgetex">Redis Documentation: HGETEX</a>
1411+
*/
1412+
Flux<MultiValueResponse<HGetExCommand, ByteBuffer>> hGetEx(Publisher<HGetExCommand> commands);
1413+
1414+
/**
1415+
* {@literal HSETEX} {@link Command}.
1416+
*
1417+
* @author Viktoriya Kutsarova
1418+
* @see <a href="https://redis.io/commands/hsetex">Redis Documentation: HSETEX</a>
1419+
*/
1420+
class HSetExCommand extends KeyCommand {
1421+
1422+
private final Map<ByteBuffer, ByteBuffer> fieldValueMap;
1423+
private final RedisHashCommands.HashFieldSetOption condition;
1424+
private final Expiration expiration;
1425+
1426+
private HSetExCommand(@Nullable ByteBuffer key, Map<ByteBuffer, ByteBuffer> fieldValueMap,
1427+
RedisHashCommands.HashFieldSetOption condition, Expiration expiration) {
1428+
super(key);
1429+
this.fieldValueMap = fieldValueMap;
1430+
this.condition = condition;
1431+
this.expiration = expiration;
1432+
}
1433+
1434+
/**
1435+
* Creates a new {@link HSetExCommand} for setting field-value pairs with condition and expiration.
1436+
*
1437+
* @param fieldValueMap the field-value pairs to set; must not be {@literal null}.
1438+
* @param condition the condition for setting fields; must not be {@literal null}.
1439+
* @param expiration the expiration to apply; must not be {@literal null}.
1440+
* @return new instance of {@link HSetExCommand}.
1441+
*/
1442+
public static HSetExCommand setWithConditionAndExpiration(Map<ByteBuffer, ByteBuffer> fieldValueMap,
1443+
RedisHashCommands.HashFieldSetOption condition, Expiration expiration) {
1444+
return new HSetExCommand(null, fieldValueMap, condition, expiration);
1445+
}
1446+
1447+
/**
1448+
* Applies the hash {@literal key}. Constructs a new command instance with all previously configured properties.
1449+
*
1450+
* @param key must not be {@literal null}.
1451+
* @return a new {@link HSetExCommand} with {@literal key} applied.
1452+
*/
1453+
public HSetExCommand from(ByteBuffer key) {
1454+
Assert.notNull(key, "Key must not be null");
1455+
return new HSetExCommand(key, fieldValueMap, condition, expiration);
1456+
}
1457+
1458+
/**
1459+
* @return the field-value map.
1460+
*/
1461+
public Map<ByteBuffer, ByteBuffer> getFieldValueMap() {
1462+
return fieldValueMap;
1463+
}
1464+
1465+
/**
1466+
* @return the condition for setting fields.
1467+
*/
1468+
public RedisHashCommands.HashFieldSetOption getCondition() {
1469+
return condition;
1470+
}
1471+
1472+
/**
1473+
* @return the expiration to apply.
1474+
*/
1475+
public Expiration getExpiration() {
1476+
return expiration;
1477+
}
1478+
}
1479+
1480+
/**
1481+
* Set field-value pairs in hash at {@literal key} with condition and expiration.
1482+
*
1483+
* @param key must not be {@literal null}.
1484+
* @param fieldValueMap the field-value pairs to set; must not be {@literal null}.
1485+
* @param condition the condition for setting fields; must not be {@literal null}.
1486+
* @param expiration the expiration to apply; must not be {@literal null}.
1487+
* @return never {@literal null}.
1488+
* @see <a href="https://redis.io/commands/hsetex">Redis Documentation: HSETEX</a>
1489+
*/
1490+
default Mono<Boolean> hSetEx(ByteBuffer key, Map<ByteBuffer, ByteBuffer> fieldValueMap,
1491+
RedisHashCommands.HashFieldSetOption condition, Expiration expiration) {
1492+
1493+
Assert.notNull(key, "Key must not be null");
1494+
Assert.notNull(fieldValueMap, "Field-value map must not be null");
1495+
Assert.notNull(condition, "Condition must not be null");
1496+
Assert.notNull(expiration, "Expiration must not be null");
1497+
1498+
return hSetEx(Mono.just(HSetExCommand.setWithConditionAndExpiration(fieldValueMap, condition, expiration).from(key)))
1499+
.next().map(CommandResponse::getOutput);
1500+
}
1501+
1502+
/**
1503+
* Set field-value pairs in hash at {@literal key} with condition and expiration.
1504+
*
1505+
* @param commands must not be {@literal null}.
1506+
* @return never {@literal null}.
1507+
* @see <a href="https://redis.io/commands/hsetex">Redis Documentation: HSETEX</a>
1508+
*/
1509+
Flux<BooleanResponse<HSetExCommand>> hSetEx(Publisher<HSetExCommand> commands);
12581510
}

0 commit comments

Comments
 (0)