Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hash Field Expiration (part II) (#3195) #3204

Merged
merged 9 commits into from
Mar 24, 2025
35 changes: 35 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java
Original file line number Diff line number Diff line change
@@ -1429,6 +1429,41 @@ public RedisFuture<Long> hset(K key, Map<K, V> map) {
return dispatch(commandBuilder.hset(key, map));
}

@Override
public RedisFuture<Long> hsetex(K key, Map<K, V> map) {
return dispatch(commandBuilder.hsetex(key, map));
}

@Override
public RedisFuture<Long> hsetex(K key, HSetExArgs hSetExArgs, Map<K, V> map) {
return dispatch(commandBuilder.hsetex(key, hSetExArgs, map));
}

@Override
public RedisFuture<List<KeyValue<K, V>>> hgetex(K key, K... fields) {
return dispatch(commandBuilder.hgetex(key, fields));
}

@Override
public RedisFuture<List<KeyValue<K, V>>> hgetex(K key, HGetExArgs hGetExArgs, K... fields) {
return dispatch(commandBuilder.hgetex(key, hGetExArgs, fields));
}

@Override
public RedisFuture<Long> hgetex(KeyValueStreamingChannel<K, V> channel, K key, HGetExArgs hGetExArgs, K... fields) {
return dispatch(commandBuilder.hgetex(channel, key, hGetExArgs, fields));
}

@Override
public RedisFuture<List<KeyValue<K, V>>> hgetdel(K key, K... fields) {
return dispatch(commandBuilder.hgetdel(key, fields));
}

@Override
public RedisFuture<Long> hgetdel(KeyValueStreamingChannel<K, V> channel, K key, K... fields) {
return dispatch(commandBuilder.hgetdel(channel, key, fields));
}

@Override
public RedisFuture<Boolean> hsetnx(K key, K field, V value) {
return dispatch(commandBuilder.hsetnx(key, field, value));
35 changes: 35 additions & 0 deletions src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java
Original file line number Diff line number Diff line change
@@ -1494,6 +1494,41 @@ public Mono<Long> hset(K key, Map<K, V> map) {
return createMono(() -> commandBuilder.hset(key, map));
}

@Override
public Mono<Long> hsetex(K key, Map<K, V> map) {
return createMono(() -> commandBuilder.hsetex(key, map));
}

@Override
public Mono<Long> hsetex(K key, HSetExArgs hSetExArgs, Map<K, V> map) {
return createMono(() -> commandBuilder.hsetex(key, hSetExArgs, map));
}

@Override
public Flux<KeyValue<K, V>> hgetex(K key, K... fields) {
return createDissolvingFlux(() -> commandBuilder.hgetex(key, fields));
}

@Override
public Flux<KeyValue<K, V>> hgetex(K key, HGetExArgs hGetExArgs, K... fields) {
return createDissolvingFlux(() -> commandBuilder.hgetex(key, hGetExArgs, fields));
}

@Override
public Mono<Long> hgetex(KeyValueStreamingChannel<K, V> channel, K key, HGetExArgs hGetExArgs, K... fields) {
return createMono(() -> commandBuilder.hgetex(channel, key, hGetExArgs, fields));
}

@Override
public Flux<KeyValue<K, V>> hgetdel(K key, K... fields) {
return createDissolvingFlux(() -> commandBuilder.hgetdel(key, fields));
}

@Override
public Mono<Long> hgetdel(KeyValueStreamingChannel<K, V> channel, K key, K... fields) {
return createMono(() -> commandBuilder.hgetdel(channel, key, fields));
}

@Override
public Mono<Boolean> hsetnx(K key, K field, V value) {
return createMono(() -> commandBuilder.hsetnx(key, field, value));
196 changes: 196 additions & 0 deletions src/main/java/io/lettuce/core/HGetExArgs.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package io.lettuce.core;

import io.lettuce.core.internal.LettuceAssert;
import io.lettuce.core.protocol.CommandArgs;
import io.lettuce.core.protocol.CommandType;

import java.time.Duration;
import java.time.Instant;
import java.util.Date;

/**
* Argument list builder for the Redis <a href="https://redis.io/commands/getex">HGETEX</a> command starting from Redis 8.0.
* Static import the methods from {@link Builder} and chain the method calls: {@code ex(10).nx()}.
* <p>
* {@link HGetExArgs} is a mutable object and instances should be used only once to avoid shared mutable state.
*
* @author Ivo Gaydajiev
* @since 6.6
*/
public class HGetExArgs implements CompositeArgument {

private Long ex;

private Long exAt;

private Long px;

private Long pxAt;

private boolean persist = false;

/**
* Builder entry points for {@link HGetExArgs}.
*/
public static class Builder {

/**
* Utility constructor.
*/
private Builder() {
}

/**
* Creates new {@link HGetExArgs} and enable {@literal EX}.
*
* @param timeout expire time in seconds.
* @return new {@link HGetExArgs} with {@literal EX} enabled.
* @see HGetExArgs#ex(long)
* @since 6.6
*/
public static HGetExArgs ex(Duration timeout) {
return new HGetExArgs().ex(timeout);
}

/**
* Creates new {@link HGetExArgs} and enable {@literal EXAT}.
*
* @param timestamp the timestamp type: posix time in seconds.
* @return new {@link HGetExArgs} with {@literal EXAT} enabled.
* @see HGetExArgs#exAt(Instant)
* @since 6.6
*/
public static HGetExArgs exAt(Instant timestamp) {
return new HGetExArgs().exAt(timestamp);
}

/**
* Creates new {@link HGetExArgs} and enable {@literal PX}.
*
* @param timeout expire time in milliseconds.
* @return new {@link HGetExArgs} with {@literal PX} enabled.
* @see HGetExArgs#px(long)
* @since 6.6
*/
public static HGetExArgs px(Duration timeout) {
return new HGetExArgs().px(timeout);
}

/**
* Creates new {@link HGetExArgs} and enable {@literal PXAT}.
*
* @param timestamp the timestamp type: posix time.
* @return new {@link HGetExArgs} with {@literal PXAT} enabled.
* @see HGetExArgs#pxAt(Instant)
* @since 6.6
*/
public static HGetExArgs pxAt(Instant timestamp) {
return new HGetExArgs().pxAt(timestamp);
}

/**
* Creates new {@link HGetExArgs} and enable {@literal PERSIST}.
*
* @return new {@link HGetExArgs} with {@literal PERSIST} enabled.
* @see HGetExArgs#persist()
*/
public static HGetExArgs persist() {
return new HGetExArgs().persist();
}

}

/**
* Set the specified expire time, in seconds.
*
* @param timeout expire time in seconds.
* @return {@code this} {@link HGetExArgs}.
* @since 6.6
*/
public HGetExArgs ex(Duration timeout) {

LettuceAssert.notNull(timeout, "Timeout must not be null");

this.ex = timeout.getSeconds();
return this;
}

/**
* Set the specified expire at time using a posix {@code timestamp}.
*
* @param timestamp the timestamp type: posix time in seconds.
* @return {@code this} {@link HGetExArgs}.
* @since 6.6
*/
public HGetExArgs exAt(Instant timestamp) {

LettuceAssert.notNull(timestamp, "Timestamp must not be null");
this.exAt = timestamp.getEpochSecond();
return this;
}

/**
* Set the specified expire time, in milliseconds.
*
* @param timeout expire time in milliseconds.
* @return {@code this} {@link HGetExArgs}.
*/
public HGetExArgs px(Duration timeout) {

LettuceAssert.notNull(timeout, "Timeout must not be null");

this.px = timeout.toMillis();
return this;
}

/**
* Set the specified expire at time using a posix {@code timestamp}.
*
* @param timestamp the timestamp type: posix time in milliseconds.
* @return {@code this} {@link HGetExArgs}.
* @since 6.6
*/
public HGetExArgs pxAt(Instant timestamp) {

LettuceAssert.notNull(timestamp, "Timestamp must not be null");

this.pxAt = timestamp.toEpochMilli();
return this;
}

/**
* Remove the time to live associated with the key.
*
* @return {@code this} {@link HGetExArgs}.
*/
public HGetExArgs persist() {

this.persist = true;
return this;
}

@Override
public <K, V> void build(CommandArgs<K, V> args) {

if (ex != null) {
args.add("EX").add(ex);
}

if (exAt != null) {
args.add("EXAT").add(exAt);
}

if (px != null) {
args.add("PX").add(px);
}

if (pxAt != null) {
args.add("PXAT").add(pxAt);
}

if (persist) {
args.add(CommandType.PERSIST);
}
}

}
Loading