From 073a7992af85738ec11b4f2075daeb783847203a Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Wed, 3 Feb 2021 11:58:40 +0100 Subject: [PATCH] Introduce overloads for expire[at] and pexpire[at] accepting Instant and Duration #1607 We now ship an improved integration with JSR-310 types. --- .../core/AbstractRedisAsyncCommands.java | 31 ++++++++- .../core/AbstractRedisReactiveCommands.java | 29 +++++++- src/main/java/io/lettuce/core/SetArgs.java | 54 +++++++++++++++ .../core/api/async/RedisKeyAsyncCommands.java | 66 ++++++++++++++----- .../reactive/RedisKeyReactiveCommands.java | 66 ++++++++++++++----- .../core/api/sync/RedisKeyCommands.java | 66 ++++++++++++++----- .../async/NodeSelectionKeyAsyncCommands.java | 66 ++++++++++++++----- .../api/sync/NodeSelectionKeyCommands.java | 66 ++++++++++++++----- .../coroutines/RedisKeyCoroutinesCommands.kt | 53 +++++++++++++-- .../RedisKeyCoroutinesCommandsImpl.kt | 14 +++- .../io/lettuce/core/api/RedisKeyCommands.java | 62 +++++++++++++---- .../commands/KeyCommandIntegrationTests.java | 15 ++++- .../StringCommandIntegrationTests.java | 7 ++ 13 files changed, 497 insertions(+), 98 deletions(-) diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index adffbc4b2a..809056d4e8 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -18,6 +18,7 @@ import static io.lettuce.core.protocol.CommandType.*; import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -592,8 +593,9 @@ public RedisFuture expire(K key, long seconds) { } @Override - public RedisFuture expireat(K key, Date timestamp) { - return expireat(key, timestamp.getTime() / 1000); + public RedisFuture expire(K key, Duration seconds) { + LettuceAssert.notNull(seconds, "Timeout must not be null"); + return expire(key, seconds.toMillis() / 1000); } @Override @@ -601,6 +603,18 @@ public RedisFuture expireat(K key, long timestamp) { return dispatch(commandBuilder.expireat(key, timestamp)); } + @Override + public RedisFuture expireat(K key, Date timestamp) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return expireat(key, timestamp.getTime() / 1000); + } + + @Override + public RedisFuture expireat(K key, Instant timestamp) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return expireat(key, timestamp.toEpochMilli() / 1000); + } + @Override public void flushCommands() { connection.flushCommands(); @@ -1088,11 +1102,24 @@ public RedisFuture pexpire(K key, long milliseconds) { return dispatch(commandBuilder.pexpire(key, milliseconds)); } + @Override + public RedisFuture pexpire(K key, Duration milliseconds) { + LettuceAssert.notNull(milliseconds, "Timeout must not be null"); + return pexpire(key, milliseconds.toMillis()); + } + @Override public RedisFuture pexpireat(K key, Date timestamp) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); return pexpireat(key, timestamp.getTime()); } + @Override + public RedisFuture pexpireat(K key, Instant timestamp) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return pexpireat(key, timestamp.toEpochMilli()); + } + @Override public RedisFuture pexpireat(K key, long timestamp) { return dispatch(commandBuilder.pexpireat(key, timestamp)); diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java index 66c2bacaf3..4242d843fb 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java @@ -18,6 +18,7 @@ import static io.lettuce.core.protocol.CommandType.*; import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -649,6 +650,12 @@ public Mono expire(K key, long seconds) { return createMono(() -> commandBuilder.expire(key, seconds)); } + @Override + public Mono expire(K key, Duration seconds) { + LettuceAssert.notNull(seconds, "Timeout must not be null"); + return expire(key, seconds.toMillis() / 1000); + } + @Override public Mono expireat(K key, long timestamp) { return createMono(() -> commandBuilder.expireat(key, timestamp)); @@ -656,9 +663,16 @@ public Mono expireat(K key, long timestamp) { @Override public Mono expireat(K key, Date timestamp) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); return expireat(key, timestamp.getTime() / 1000); } + @Override + public Mono expireat(K key, Instant timestamp) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return expireat(key, timestamp.toEpochMilli() / 1000); + } + @Override public void flushCommands() { connection.flushCommands(); @@ -1154,8 +1168,9 @@ public Mono pexpire(K key, long milliseconds) { } @Override - public Mono pexpireat(K key, Date timestamp) { - return pexpireat(key, timestamp.getTime()); + public Mono pexpire(K key, Duration milliseconds) { + LettuceAssert.notNull(milliseconds, "Timeout must not be null"); + return pexpire(key, milliseconds.toMillis()); } @Override @@ -1163,6 +1178,16 @@ public Mono pexpireat(K key, long timestamp) { return createMono(() -> commandBuilder.pexpireat(key, timestamp)); } + @Override + public Mono pexpireat(K key, Date timestamp) { + return pexpireat(key, timestamp.getTime()); + } + + @Override + public Mono pexpireat(K key, Instant timestamp) { + return pexpireat(key, timestamp.toEpochMilli()); + } + @Override public Mono pfadd(K key, V... values) { return createMono(() -> commandBuilder.pfadd(key, values)); diff --git a/src/main/java/io/lettuce/core/SetArgs.java b/src/main/java/io/lettuce/core/SetArgs.java index 472929736f..c0eaf136b3 100644 --- a/src/main/java/io/lettuce/core/SetArgs.java +++ b/src/main/java/io/lettuce/core/SetArgs.java @@ -15,6 +15,7 @@ */ package io.lettuce.core; +import java.time.Duration; import java.time.Instant; import java.util.Date; @@ -69,6 +70,18 @@ public static SetArgs ex(long timeout) { return new SetArgs().ex(timeout); } + /** + * Creates new {@link SetArgs} and enable {@literal EX}. + * + * @param timeout expire time in seconds. + * @return new {@link SetArgs} with {@literal EX} enabled. + * @see SetArgs#ex(long) + * @since 6.1 + */ + public static SetArgs ex(Duration timeout) { + return new SetArgs().ex(timeout); + } + /** * Creates new {@link SetArgs} and enable {@literal EXAT}. * @@ -115,6 +128,18 @@ public static SetArgs px(long timeout) { return new SetArgs().px(timeout); } + /** + * Creates new {@link SetArgs} and enable {@literal PX}. + * + * @param timeout expire time in milliseconds. + * @return new {@link SetArgs} with {@literal PX} enabled. + * @see SetArgs#px(long) + * @since 6.1 + */ + public static SetArgs px(Duration timeout) { + return new SetArgs().px(timeout); + } + /** * Creates new {@link SetArgs} and enable {@literal PXAT}. * @@ -195,6 +220,21 @@ public SetArgs ex(long timeout) { return this; } + /** + * Set the specified expire time, in seconds. + * + * @param timeout expire time in seconds. + * @return {@code this} {@link SetArgs}. + * @since 6.1 + */ + public SetArgs ex(Duration timeout) { + + LettuceAssert.notNull(timeout, "Timeout must not be null"); + + this.ex = timeout.toMillis() / 1000; + return this; + } + /** * Set the specified expire at time using a posix {@code timestamp}. * @@ -248,6 +288,20 @@ public SetArgs px(long timeout) { return this; } + /** + * Set the specified expire time, in milliseconds. + * + * @param timeout expire time in milliseconds. + * @return {@code this} {@link SetArgs}. + */ + public SetArgs 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}. * diff --git a/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java b/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java index aa8e610fb0..f929d761c4 100644 --- a/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java +++ b/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java @@ -15,6 +15,8 @@ */ package io.lettuce.core.api.async; +import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.List; @@ -101,20 +103,38 @@ public interface RedisKeyAsyncCommands { * @param key the key. * @param seconds the seconds type: long. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ RedisFuture expire(K key, long seconds); + /** + * Set a key's time to live in seconds. + * + * @param key the key. + * @param seconds the seconds. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set. + * @since 6.1 + */ + RedisFuture expire(K key, Duration seconds); + /** * Set the expiration for a key as a UNIX timestamp. * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + RedisFuture expireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ RedisFuture expireat(K key, Date timestamp); @@ -123,12 +143,11 @@ public interface RedisKeyAsyncCommands { * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: - * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + * @since 6.1 */ - RedisFuture expireat(K key, long timestamp); + RedisFuture expireat(K key, Instant timestamp); /** * Find all keys matching the given pattern. @@ -222,20 +241,38 @@ public interface RedisKeyAsyncCommands { * @param key the key. * @param milliseconds the milliseconds type: long. * @return integer-reply, specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ RedisFuture pexpire(K key, long milliseconds); + /** + * Set a key's time to live in milliseconds. + * + * @param key the key. + * @param milliseconds the milliseconds. + * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or + * the timeout could not be set. + * @since 6.1 + */ + RedisFuture pexpire(K key, Duration milliseconds); + /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + RedisFuture pexpireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the milliseconds-timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ RedisFuture pexpireat(K key, Date timestamp); @@ -245,11 +282,10 @@ public interface RedisKeyAsyncCommands { * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - RedisFuture pexpireat(K key, long timestamp); + RedisFuture pexpireat(K key, Instant timestamp); /** * Get the time to live for a key in milliseconds. diff --git a/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java b/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java index 5f71af5a5e..2a17c163ac 100644 --- a/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java +++ b/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java @@ -15,6 +15,8 @@ */ package io.lettuce.core.api.reactive; +import java.time.Duration; +import java.time.Instant; import java.util.Date; import reactor.core.publisher.Flux; @@ -101,20 +103,38 @@ public interface RedisKeyReactiveCommands { * @param key the key. * @param seconds the seconds type: long. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Mono expire(K key, long seconds); + /** + * Set a key's time to live in seconds. + * + * @param key the key. + * @param seconds the seconds. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set. + * @since 6.1 + */ + Mono expire(K key, Duration seconds); + /** * Set the expiration for a key as a UNIX timestamp. * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + Mono expireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ Mono expireat(K key, Date timestamp); @@ -123,12 +143,11 @@ public interface RedisKeyReactiveCommands { * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: - * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + * @since 6.1 */ - Mono expireat(K key, long timestamp); + Mono expireat(K key, Instant timestamp); /** * Find all keys matching the given pattern. @@ -224,20 +243,38 @@ public interface RedisKeyReactiveCommands { * @param key the key. * @param milliseconds the milliseconds type: long. * @return integer-reply, specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Mono pexpire(K key, long milliseconds); + /** + * Set a key's time to live in milliseconds. + * + * @param key the key. + * @param milliseconds the milliseconds. + * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or + * the timeout could not be set. + * @since 6.1 + */ + Mono pexpire(K key, Duration milliseconds); + /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + Mono pexpireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the milliseconds-timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ Mono pexpireat(K key, Date timestamp); @@ -247,11 +284,10 @@ public interface RedisKeyReactiveCommands { * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - Mono pexpireat(K key, long timestamp); + Mono pexpireat(K key, Instant timestamp); /** * Get the time to live for a key in milliseconds. diff --git a/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java b/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java index d7d7dffbfd..9b034da9b7 100644 --- a/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java +++ b/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java @@ -15,6 +15,8 @@ */ package io.lettuce.core.api.sync; +import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.List; @@ -100,20 +102,38 @@ public interface RedisKeyCommands { * @param key the key. * @param seconds the seconds type: long. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Boolean expire(K key, long seconds); + /** + * Set a key's time to live in seconds. + * + * @param key the key. + * @param seconds the seconds. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set. + * @since 6.1 + */ + Boolean expire(K key, Duration seconds); + /** * Set the expiration for a key as a UNIX timestamp. * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + Boolean expireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ Boolean expireat(K key, Date timestamp); @@ -122,12 +142,11 @@ public interface RedisKeyCommands { * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: - * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + * @since 6.1 */ - Boolean expireat(K key, long timestamp); + Boolean expireat(K key, Instant timestamp); /** * Find all keys matching the given pattern. @@ -221,20 +240,38 @@ public interface RedisKeyCommands { * @param key the key. * @param milliseconds the milliseconds type: long. * @return integer-reply, specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Boolean pexpire(K key, long milliseconds); + /** + * Set a key's time to live in milliseconds. + * + * @param key the key. + * @param milliseconds the milliseconds. + * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or + * the timeout could not be set. + * @since 6.1 + */ + Boolean pexpire(K key, Duration milliseconds); + /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + Boolean pexpireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the milliseconds-timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ Boolean pexpireat(K key, Date timestamp); @@ -244,11 +281,10 @@ public interface RedisKeyCommands { * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - Boolean pexpireat(K key, long timestamp); + Boolean pexpireat(K key, Instant timestamp); /** * Get the time to live for a key in milliseconds. diff --git a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionKeyAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionKeyAsyncCommands.java index b856fbef58..3ebcf29389 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionKeyAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionKeyAsyncCommands.java @@ -15,6 +15,8 @@ */ package io.lettuce.core.cluster.api.async; +import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.List; @@ -100,20 +102,38 @@ public interface NodeSelectionKeyAsyncCommands { * @param key the key. * @param seconds the seconds type: long. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ AsyncExecutions expire(K key, long seconds); + /** + * Set a key's time to live in seconds. + * + * @param key the key. + * @param seconds the seconds. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set. + * @since 6.1 + */ + AsyncExecutions expire(K key, Duration seconds); + /** * Set the expiration for a key as a UNIX timestamp. * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + AsyncExecutions expireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ AsyncExecutions expireat(K key, Date timestamp); @@ -122,12 +142,11 @@ public interface NodeSelectionKeyAsyncCommands { * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: - * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + * @since 6.1 */ - AsyncExecutions expireat(K key, long timestamp); + AsyncExecutions expireat(K key, Instant timestamp); /** * Find all keys matching the given pattern. @@ -221,20 +240,38 @@ public interface NodeSelectionKeyAsyncCommands { * @param key the key. * @param milliseconds the milliseconds type: long. * @return integer-reply, specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ AsyncExecutions pexpire(K key, long milliseconds); + /** + * Set a key's time to live in milliseconds. + * + * @param key the key. + * @param milliseconds the milliseconds. + * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or + * the timeout could not be set. + * @since 6.1 + */ + AsyncExecutions pexpire(K key, Duration milliseconds); + /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + AsyncExecutions pexpireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the milliseconds-timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ AsyncExecutions pexpireat(K key, Date timestamp); @@ -244,11 +281,10 @@ public interface NodeSelectionKeyAsyncCommands { * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - AsyncExecutions pexpireat(K key, long timestamp); + AsyncExecutions pexpireat(K key, Instant timestamp); /** * Get the time to live for a key in milliseconds. diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionKeyCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionKeyCommands.java index 3769502de7..fc9d8c1261 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionKeyCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionKeyCommands.java @@ -15,6 +15,8 @@ */ package io.lettuce.core.cluster.api.sync; +import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.List; @@ -100,20 +102,38 @@ public interface NodeSelectionKeyCommands { * @param key the key. * @param seconds the seconds type: long. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Executions expire(K key, long seconds); + /** + * Set a key's time to live in seconds. + * + * @param key the key. + * @param seconds the seconds. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set. + * @since 6.1 + */ + Executions expire(K key, Duration seconds); + /** * Set the expiration for a key as a UNIX timestamp. * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + Executions expireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ Executions expireat(K key, Date timestamp); @@ -122,12 +142,11 @@ public interface NodeSelectionKeyCommands { * * @param key the key. * @param timestamp the timestamp type: posix time. - * @return Boolean integer-reply specifically: - * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + * @since 6.1 */ - Executions expireat(K key, long timestamp); + Executions expireat(K key, Instant timestamp); /** * Find all keys matching the given pattern. @@ -221,20 +240,38 @@ public interface NodeSelectionKeyCommands { * @param key the key. * @param milliseconds the milliseconds type: long. * @return integer-reply, specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Executions pexpire(K key, long milliseconds); + /** + * Set a key's time to live in milliseconds. + * + * @param key the key. + * @param milliseconds the milliseconds. + * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or + * the timeout could not be set. + * @since 6.1 + */ + Executions pexpire(K key, Duration milliseconds); + /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. - * @return Boolean integer-reply specifically: + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + Executions pexpireat(K key, long timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * - * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set - * (see: {@code EXPIRE}). + * @param key the key. + * @param timestamp the milliseconds-timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). */ Executions pexpireat(K key, Date timestamp); @@ -244,11 +281,10 @@ public interface NodeSelectionKeyCommands { * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - Executions pexpireat(K key, long timestamp); + Executions pexpireat(K key, Instant timestamp); /** * Get the time to live for a key in milliseconds. diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt index e0f88bd019..7d83c8177b 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt @@ -18,6 +18,8 @@ package io.lettuce.core.api.coroutines import io.lettuce.core.* import kotlinx.coroutines.flow.Flow +import java.time.Duration +import java.time.Instant import java.util.* /** @@ -91,18 +93,38 @@ interface RedisKeyCoroutinesCommands { * @param key the key. * @param seconds the seconds type: long. * @return Boolean integer-reply specifically: - * * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set. */ suspend fun expire(key: K, seconds: Long): Boolean? + /** + * Set a key's time to live in seconds. + * + * @param key the key. + * @param seconds the seconds. + * @return Boolean integer-reply specifically: + * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set. + * @since 6.1 + */ + suspend fun expire(key: K, seconds: Duration): Boolean? + /** * Set the expiration for a key as a UNIX timestamp. * * @param key the key. * @param timestamp the timestamp type: posix time. * @return Boolean integer-reply specifically: + * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set + * (see: `EXPIRE`). + */ + suspend fun expireat(key: K, timestamp: Long): Boolean? + + /** + * Set the expiration for a key as a UNIX timestamp. * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @return Boolean integer-reply specifically: * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set * (see: `EXPIRE`). */ @@ -114,11 +136,11 @@ interface RedisKeyCoroutinesCommands { * @param key the key. * @param timestamp the timestamp type: posix time. * @return Boolean integer-reply specifically: - * * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set * (see: `EXPIRE`). + * @since 6.1 */ - suspend fun expireat(key: K, timestamp: Long): Boolean? + suspend fun expireat(key: K, timestamp: Instant): Boolean? /** * Find all keys matching the given pattern. @@ -203,18 +225,38 @@ interface RedisKeyCoroutinesCommands { * @param key the key. * @param milliseconds the milliseconds type: long. * @return integer-reply, specifically: - * * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set. */ suspend fun pexpire(key: K, milliseconds: Long): Boolean? + /** + * Set a key's time to live in milliseconds. + * + * @param key the key. + * @param milliseconds the milliseconds. + * @return integer-reply, specifically: + * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set. + * @since 6.1 + */ + suspend fun pexpire(key: K, milliseconds: Duration): Boolean? + /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: + * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set + * (see: `EXPIRE`). + */ + suspend fun pexpireat(key: K, timestamp: Long): Boolean? + + /** + * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * + * @param key the key. + * @param timestamp the milliseconds-timestamp type: posix time. + * @return Boolean integer-reply specifically: * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set * (see: `EXPIRE`). */ @@ -226,11 +268,10 @@ interface RedisKeyCoroutinesCommands { * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * `true` if the timeout was set. `false` if `key` does not exist or the timeout could not be set * (see: `EXPIRE`). */ - suspend fun pexpireat(key: K, timestamp: Long): Boolean? + suspend fun pexpireat(key: K, timestamp: Instant): Boolean? /** * Get the time to live for a key in milliseconds. diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt index 41ea2a4780..aa40aa547b 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt @@ -21,6 +21,8 @@ import io.lettuce.core.api.reactive.RedisKeyReactiveCommands import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.reactive.awaitFirstOrNull +import java.time.Duration +import java.time.Instant import java.util.* /** @@ -53,9 +55,15 @@ internal class RedisKeyCoroutinesCommandsImpl(internal val ops override suspend fun expire(key: K, seconds: Long): Boolean? = ops.expire(key, seconds).awaitFirstOrNull() + override suspend fun expire(key: K, seconds: Duration): Boolean? = + ops.expire(key, seconds).awaitFirstOrNull() + override suspend fun expireat(key: K, timestamp: Date): Boolean? = ops.expireat(key, timestamp).awaitFirstOrNull() + override suspend fun expireat(key: K, timestamp: Instant): Boolean? = + ops.expireat(key, timestamp).awaitFirstOrNull() + override suspend fun expireat(key: K, timestamp: Long): Boolean? = ops.expireat(key, timestamp).awaitFirstOrNull() @@ -89,10 +97,14 @@ internal class RedisKeyCoroutinesCommandsImpl(internal val ops override suspend fun pexpire(key: K, milliseconds: Long): Boolean? = ops.pexpire(key, milliseconds).awaitFirstOrNull() - override suspend fun pexpireat(key: K, timestamp: Date): Boolean? = ops.pexpireat(key, timestamp).awaitFirstOrNull() + override suspend fun pexpire(key: K, milliseconds: Duration): Boolean? = ops.pexpire(key, milliseconds).awaitFirstOrNull() override suspend fun pexpireat(key: K, timestamp: Long): Boolean? = ops.pexpireat(key, timestamp).awaitFirstOrNull() + override suspend fun pexpireat(key: K, timestamp: Date): Boolean? = ops.pexpireat(key, timestamp).awaitFirstOrNull() + + override suspend fun pexpireat(key: K, timestamp: Instant): Boolean? = ops.pexpireat(key, timestamp).awaitFirstOrNull() + override suspend fun pttl(key: K): Long? = ops.pttl(key).awaitFirstOrNull() override suspend fun randomkey(): K? = ops.randomkey().awaitFirstOrNull() diff --git a/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java b/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java index a904b93aa0..9f738fa24c 100644 --- a/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java +++ b/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java @@ -15,10 +15,13 @@ */ package io.lettuce.core.api; +import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.List; -import io.lettuce.core.*; +import io.lettuce.core.KeyScanArgs; +import io.lettuce.core.RestoreArgs; import io.lettuce.core.output.KeyStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; @@ -91,22 +94,31 @@ public interface RedisKeyCommands { * @param key the key. * @param seconds the seconds type: long. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Boolean expire(K key, long seconds); + /** + * Set a key's time to live in seconds. + * + * @param key the key. + * @param seconds the seconds. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set. + * @since 6.1 + */ + Boolean expire(K key, Duration seconds); + /** * Set the expiration for a key as a UNIX timestamp. * * @param key the key. * @param timestamp the timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - Boolean expireat(K key, Date timestamp); + Boolean expireat(K key, long timestamp); /** * Set the expiration for a key as a UNIX timestamp. @@ -114,11 +126,21 @@ public interface RedisKeyCommands { * @param key the key. * @param timestamp the timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - Boolean expireat(K key, long timestamp); + Boolean expireat(K key, Date timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + * @since 6.1 + */ + Boolean expireat(K key, Instant timestamp); /** * Find all keys matching the given pattern. @@ -212,22 +234,31 @@ public interface RedisKeyCommands { * @param key the key. * @param milliseconds the milliseconds type: long. * @return integer-reply, specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set. */ Boolean pexpire(K key, long milliseconds); + /** + * Set a key's time to live in milliseconds. + * + * @param key the key. + * @param milliseconds the milliseconds. + * @return integer-reply, specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not exist or + * the timeout could not be set. + * @since 6.1 + */ + Boolean pexpire(K key, Duration milliseconds); + /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. * * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - Boolean pexpireat(K key, Date timestamp); + Boolean pexpireat(K key, long timestamp); /** * Set the expiration for a key as a UNIX timestamp specified in milliseconds. @@ -235,11 +266,20 @@ public interface RedisKeyCommands { * @param key the key. * @param timestamp the milliseconds-timestamp type: posix time. * @return Boolean integer-reply specifically: - * * {@code true} if the timeout was set. {@code false} if {@code key} does not exist or the timeout could not be set * (see: {@code EXPIRE}). */ - Boolean pexpireat(K key, long timestamp); + Boolean pexpireat(K key, Date timestamp); + + /** + * Set the expiration for a key as a UNIX timestamp specified in milliseconds. + * + * @param key the key. + * @param timestamp the milliseconds-timestamp type: posix time. + * @return Boolean integer-reply specifically: {@code true} if the timeout was set. {@code false} if {@code key} does not + * exist or the timeout could not be set (see: {@code EXPIRE}). + */ + Boolean pexpireat(K key, Instant timestamp); /** * Get the time to live for a key in milliseconds. diff --git a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java index 5e795cc563..dd694184be 100644 --- a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java @@ -18,6 +18,7 @@ import static org.assertj.core.api.Assertions.*; import java.time.Duration; +import java.time.Instant; import java.util.Date; import java.util.HashSet; import java.util.LinkedHashMap; @@ -139,7 +140,10 @@ void expire() { assertThat(redis.expire(key, 10)).isFalse(); redis.set(key, value); assertThat(redis.expire(key, 10)).isTrue(); - assertThat((long) redis.ttl(key)).isEqualTo(10); + assertThat(redis.ttl(key)).isBetween(5L, 10L); + + redis.expire(key, Duration.ofSeconds(20)); + assertThat(redis.ttl(key)).isBetween(10L, 20L); } @Test @@ -150,6 +154,9 @@ void expireat() { assertThat(redis.expireat(key, expiration)).isTrue(); assertThat(redis.ttl(key)).isGreaterThanOrEqualTo(8); + + assertThat(redis.expireat(key, Instant.now().plusSeconds(15))).isTrue(); + assertThat(redis.ttl(key)).isBetween(10L, 20L); } @Test @@ -229,6 +236,9 @@ void pexpire() { redis.set(key, value); assertThat(redis.pexpire(key, 5000)).isTrue(); assertThat(redis.pttl(key)).isGreaterThan(0).isLessThanOrEqualTo(5000); + + redis.pexpire(key, Duration.ofSeconds(20)); + assertThat(redis.ttl(key)).isBetween(10L, 20L); } @Test @@ -238,6 +248,9 @@ void pexpireat() { redis.set(key, value); assertThat(redis.pexpireat(key, expiration)).isTrue(); assertThat(redis.pttl(key)).isGreaterThan(0).isLessThanOrEqualTo(5000); + + assertThat(redis.pexpireat(key, Instant.now().plusSeconds(15))).isTrue(); + assertThat(redis.ttl(key)).isBetween(10L, 20L); } @Test diff --git a/src/test/java/io/lettuce/core/commands/StringCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/StringCommandIntegrationTests.java index e3760d6426..78273b24bf 100644 --- a/src/test/java/io/lettuce/core/commands/StringCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/StringCommandIntegrationTests.java @@ -19,6 +19,7 @@ import static io.lettuce.core.StringMatchResult.*; import static org.assertj.core.api.Assertions.*; +import java.time.Duration; import java.time.Instant; import java.util.LinkedHashMap; import java.util.List; @@ -157,6 +158,12 @@ void set() { assertThat(redis.get(key)).isEqualTo(value); assertThat(redis.ttl(key)).isGreaterThanOrEqualTo(9); + assertThat(redis.set(key, value, ex(Duration.ofSeconds(10)))).isEqualTo("OK"); + assertThat(redis.ttl(key)).isBetween(5L, 10L); + + assertThat(redis.set(key, value, px(Duration.ofSeconds(10)))).isEqualTo("OK"); + assertThat(redis.ttl(key)).isBetween(5L, 10L); + assertThat(redis.set(key, value, px(10000))).isEqualTo("OK"); assertThat(redis.get(key)).isEqualTo(value); assertThat(redis.ttl(key)).isGreaterThanOrEqualTo(9);