From 279d78d97b6778287b71759a97270fc187233096 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev <tihomir.mateev@gmail.com> Date: Mon, 22 Apr 2024 15:26:21 +0300 Subject: [PATCH 1/7] HEXPIRE implemented with integration tests --- .../core/AbstractRedisAsyncCommands.java | 21 +++++++ .../core/AbstractRedisReactiveCommands.java | 21 +++++++ .../io/lettuce/core/RedisCommandBuilder.java | 17 ++++++ .../core/api/async/RedisKeyAsyncCommands.java | 50 ++++++++++++++++ .../reactive/RedisKeyReactiveCommands.java | 51 +++++++++++++++++ .../core/api/sync/RedisKeyCommands.java | 50 ++++++++++++++++ .../async/NodeSelectionKeyAsyncCommands.java | 50 ++++++++++++++++ .../api/sync/NodeSelectionKeyCommands.java | 50 ++++++++++++++++ .../io/lettuce/core/protocol/CommandType.java | 2 +- .../coroutines/RedisKeyCoroutinesCommands.kt | 52 ++++++++++++++++- .../RedisKeyCoroutinesCommandsImpl.kt | 18 ++++++ .../io/lettuce/core/api/RedisKeyCommands.java | 50 ++++++++++++++++ .../commands/KeyCommandIntegrationTests.java | 57 +++++++++++++++++-- 13 files changed, 481 insertions(+), 8 deletions(-) diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index f2c6c625ce..03d0e69f28 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -794,6 +794,27 @@ public RedisFuture<Boolean> expire(K key, Duration seconds, ExpireArgs expireArg return expire(key, seconds.toMillis() / 1000, expireArgs); } + @Override + public RedisFuture<Boolean> hexpire(K key, long seconds, List<V> fields) { + return hexpire(key, seconds, null, fields); + } + + @Override + public RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields) { + return dispatch(commandBuilder.hexpire(key, seconds, expireArgs, fields)); + } + + @Override + public RedisFuture<Boolean> hexpire(K key, Duration seconds, List<V> fields) { + return hexpire(key, seconds, null, fields); + } + + @Override + public RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields) { + LettuceAssert.notNull(seconds, "Timeout must not be null"); + return hexpire(key, seconds.toMillis() / 1000, expireArgs, fields); + } + @Override public RedisFuture<Boolean> expireat(K key, long timestamp) { return expireat(key, timestamp, null); diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java index 47b473495e..567401bc97 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java @@ -854,6 +854,27 @@ public Mono<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs) { return expire(key, seconds.toMillis() / 1000, expireArgs); } + @Override + public Mono<Boolean> hexpire(K key, long seconds, List<V> fields) { + return hexpire(key, seconds, null, fields); + } + + @Override + public Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields) { + return createMono(() -> commandBuilder.hexpire(key, seconds, expireArgs, fields)); + } + + @Override + public Mono<Boolean> hexpire(K key, Duration seconds, List<V> fields) { + return hexpire(key, seconds, null, fields); + } + + @Override + public Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields) { + LettuceAssert.notNull(seconds, "Timeout must not be null"); + return hexpire(key, seconds.toMillis() / 1000, expireArgs, fields); + } + @Override public Mono<Boolean> expireat(K key, long timestamp) { return expireat(key, timestamp, null); diff --git a/src/main/java/io/lettuce/core/RedisCommandBuilder.java b/src/main/java/io/lettuce/core/RedisCommandBuilder.java index 3d3d2be0be..9b82a026e8 100644 --- a/src/main/java/io/lettuce/core/RedisCommandBuilder.java +++ b/src/main/java/io/lettuce/core/RedisCommandBuilder.java @@ -978,6 +978,23 @@ Command<K, V, Boolean> expire(K key, long seconds, ExpireArgs expireArgs) { return createCommand(EXPIRE, new BooleanOutput<>(codec), args); } + Command<K, V, Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields) { + notNullKey(key); + notEmpty(fields == null ? new Object[]{} : fields.toArray()); + + CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).add(seconds); + + if (expireArgs != null) { + expireArgs.build(args); + } + + args.add(fields.size()); + + fields.forEach(args::addValue); + + return createCommand(HEXPIRE, new BooleanOutput<>(codec), args); + } + Command<K, V, Boolean> expireat(K key, long timestamp, ExpireArgs expireArgs) { notNullKey(key); 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 cceffb8a71..5a6078d5b6 100644 --- a/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java +++ b/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java @@ -137,6 +137,56 @@ public interface RedisKeyAsyncCommands<K, V> { */ RedisFuture<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, long seconds, List<V> fields); + + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, Duration seconds, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); + /** * Set the expiration for a key as a UNIX timestamp. * 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 1fbfdda1a8..b3f1ef89f8 100644 --- a/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java +++ b/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java @@ -22,6 +22,7 @@ import java.time.Duration; import java.time.Instant; import java.util.Date; +import java.util.List; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -147,6 +148,56 @@ public interface RedisKeyReactiveCommands<K, V> { */ Mono<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, long seconds, List<V> fields); + + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, Duration seconds, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); + /** * Set the expiration for a key as a UNIX timestamp. * 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 516e4ab072..07faab4c2e 100644 --- a/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java +++ b/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java @@ -146,6 +146,56 @@ public interface RedisKeyCommands<K, V> { */ Boolean expire(K key, Duration seconds, ExpireArgs expireArgs); + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, List<V> fields); + + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); + /** * Set the expiration for a key as a UNIX timestamp. * 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 44bbd168a3..422111c0ea 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 @@ -146,6 +146,56 @@ public interface NodeSelectionKeyAsyncCommands<K, V> { */ AsyncExecutions<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, long seconds, List<V> fields); + + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, Duration seconds, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); + /** * Set the expiration for a key as a UNIX timestamp. * 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 d09dd4f39a..b523434d24 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 @@ -146,6 +146,56 @@ public interface NodeSelectionKeyCommands<K, V> { */ Executions<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, long seconds, List<V> fields); + + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, Duration seconds, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); + /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/main/java/io/lettuce/core/protocol/CommandType.java b/src/main/java/io/lettuce/core/protocol/CommandType.java index 7a9d87524d..bd4c04c982 100644 --- a/src/main/java/io/lettuce/core/protocol/CommandType.java +++ b/src/main/java/io/lettuce/core/protocol/CommandType.java @@ -46,7 +46,7 @@ public enum CommandType implements ProtocolKeyword { // Keys - COPY, DEL, DUMP, EXISTS, EXPIRE, EXPIREAT, EXPIRETIME, KEYS, MIGRATE, MOVE, OBJECT, PERSIST, PEXPIRE, PEXPIREAT, PEXPIRETIME, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK, + COPY, DEL, DUMP, EXISTS, HEXPIRE, EXPIRE, EXPIREAT, EXPIRETIME, KEYS, MIGRATE, MOVE, OBJECT, PERSIST, PEXPIRE, PEXPIREAT, PEXPIRETIME, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK, // String 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 6d3f92bcad..f979c8bc4e 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020-Present, Redis Ltd. and Contributors + * Copyright 2017-Present, Redis Ltd. and Contributors * All rights reserved. * * Licensed under the MIT License. @@ -136,6 +136,56 @@ interface RedisKeyCoroutinesCommands<K : Any, V : Any> { */ suspend fun expire(key: K, seconds: Duration, expireArgs: ExpireArgs): Boolean? + /** + * Set the time to live (in seconds) for a [List] of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields a [List] of fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Long, fields: List<V>): Boolean? + + /** + * Set the time to live (in seconds) for a [List] of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields a [List] of fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, fields: List<V>): Boolean? + + /** + * Set the time to live for a [List] of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL [Duration] + * @param fields a [List] of fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Duration, fields: List<V>): Boolean? + + /** + * Set the time to live for a [List] of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL [Duration] + * @param expireArgs the [ExpireArgs]. + * @param fields a [List] of fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Duration, expireArgs: ExpireArgs, fields: List<V>): Boolean? + /** * Set the expiration for a key as a UNIX timestamp. * 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 5b62a92d3c..d088d03ad8 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt @@ -74,6 +74,24 @@ internal class RedisKeyCoroutinesCommandsImpl<K : Any, V : Any>(internal val ops ): Boolean? = ops.expire(key, seconds, expireArgs).awaitFirstOrNull() + override suspend fun hexpire(key: K, seconds: Long, fields: List<V>): Boolean? = + ops.hexpire(key, seconds, fields).awaitFirstOrNull() + + override suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, fields: List<V>): Boolean? = + ops.hexpire(key, seconds, expireArgs, fields).awaitFirstOrNull() + + + override suspend fun hexpire(key: K, seconds: Duration, fields: List<V>): Boolean? = + ops.hexpire(key, seconds, fields).awaitFirstOrNull() + + override suspend fun hexpire( + key: K, + seconds: Duration, + expireArgs: ExpireArgs, + fields: List<V> + ): Boolean? = + ops.hexpire(key, seconds, expireArgs, fields).awaitFirstOrNull() + override suspend fun expireat(key: K, timestamp: Date): Boolean? = ops.expireat(key, timestamp).awaitFirstOrNull() diff --git a/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java b/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java index bdd3568991..6f8ba3c27b 100644 --- a/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java +++ b/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java @@ -138,6 +138,56 @@ public interface RedisKeyCommands<K, V> { */ Boolean expire(K key, Duration seconds, ExpireArgs expireArgs); + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, List<V> fields); + + /** + * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, List<V> fields); + + /** + * Set the time to live for a {@link List} of fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields a {@link List} of fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); + /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java index 45d7e3840d..fb12d44db5 100644 --- a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java @@ -20,15 +20,11 @@ package io.lettuce.core.commands; import static org.assertj.core.api.Assertions.*; +import static org.awaitility.Awaitility.await; import java.time.Duration; import java.time.Instant; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import javax.inject.Inject; @@ -62,6 +58,12 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class KeyCommandIntegrationTests extends TestSupport { + public static final String MY_KEY = "hKey"; + + public static final String MY_FIELD = "hField"; + + public static final String MY_VALUE = "hValue"; + private final RedisCommands<String, String> redis; @Inject @@ -192,6 +194,49 @@ void expiretime() { assertThat(redis.expiretime(key)).isEqualTo(expiration.getTime() / 1000); } + @Test + @EnabledOnCommand("HEXPIRE") + void hexpire() { + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); + // the below settings are required until the solution is able to support listpack entries + // see TODOs in https://github.com/redis/redis/pull/13172 for more details + assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + + assertThat(redis.hexpire("myKey", 1, Collections.singletonList("myField"))).isTrue(); + + await().until(() -> redis.hget("myKey", "myField") == null); + } + + @Test + @EnabledOnCommand("HEXPIRE") + void hexpireExpireArgs() { + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); + // the below settings are required until the solution is able to support listpack entries + // see TODOs in https://github.com/redis/redis/pull/13172 for more details + assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + + assertThat(redis.hexpire("myKey", + Duration.ofSeconds(1), + ExpireArgs.Builder.nx(), + Collections.singletonList("myField"))).isTrue(); + assertThat(redis.hexpire("myKey", + Duration.ofSeconds(1), + ExpireArgs.Builder.xx(), + Collections.singletonList("myField"))).isTrue(); + assertThat(redis.hexpire("myKey", + Duration.ofSeconds(10), + ExpireArgs.Builder.gt(), + Collections.singletonList("myField"))).isTrue(); + assertThat(redis.hexpire("myKey", + Duration.ofSeconds(1), + ExpireArgs.Builder.lt(), + Collections.singletonList("myField"))).isTrue(); + + await().until(() -> redis.hget("myKey", "myField") == null); + } + @Test void keys() { assertThat(redis.keys("*")).isEqualTo(list()); From 0e867eb09a6b5bdec2fd75739badc1d8370b21d5 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev <tihomir.mateev@gmail.com> Date: Mon, 22 Apr 2024 15:59:05 +0300 Subject: [PATCH 2/7] Polishing to integration test, added unit test --- .../core/RedisCommandBuilderUnitTests.java | 15 +++++++++++++ .../commands/KeyCommandIntegrationTests.java | 22 +++++++++---------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java index 9d2b676aae..2136ff0a92 100644 --- a/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java @@ -3,7 +3,10 @@ import static org.assertj.core.api.Assertions.*; import java.nio.charset.StandardCharsets; +import java.util.Collections; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.EmptyByteBuf; import org.junit.jupiter.api.Test; import io.lettuce.core.codec.StringCodec; @@ -16,6 +19,8 @@ * @author Mark Paluch */ class RedisCommandBuilderUnitTests { + public static final String MY_KEY = "hKey"; + public static final String MY_FIELD = "hField"; RedisCommandBuilder<String, String> sut = new RedisCommandBuilder<>(StringCodec.UTF8); @@ -29,4 +34,14 @@ void shouldCorrectlyConstructXreadgroup() { .isEqualTo("stream"); } + @Test + void shouldCorrectlyConstructHexpire() { + + Command<String, String, ?> command = sut.hexpire(MY_KEY, 1, ExpireArgs.Builder.nx(), Collections.singletonList(MY_FIELD)); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*6\r\n" + "$7\r\n" + "HEXPIRE\r\n" + "$4\r\n" + "hKey\r\n" + + "$1\r\n" + "1\r\n" + "$2\r\n" + "NX\r\n" + "$1\r\n" + "1\r\n" + "$6\r\n" + "hField\r\n"); + } } diff --git a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java index fb12d44db5..6a67e9706e 100644 --- a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java @@ -203,9 +203,9 @@ void hexpire() { assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); - assertThat(redis.hexpire("myKey", 1, Collections.singletonList("myField"))).isTrue(); + assertThat(redis.hexpire(MY_KEY, 1, Collections.singletonList(MY_FIELD))).isTrue(); - await().until(() -> redis.hget("myKey", "myField") == null); + await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); } @Test @@ -217,24 +217,24 @@ void hexpireExpireArgs() { assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); - assertThat(redis.hexpire("myKey", + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.nx(), - Collections.singletonList("myField"))).isTrue(); - assertThat(redis.hexpire("myKey", + Collections.singletonList(MY_FIELD))).isTrue(); + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.xx(), - Collections.singletonList("myField"))).isTrue(); - assertThat(redis.hexpire("myKey", + Collections.singletonList(MY_FIELD))).isTrue(); + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(10), ExpireArgs.Builder.gt(), - Collections.singletonList("myField"))).isTrue(); - assertThat(redis.hexpire("myKey", + Collections.singletonList(MY_FIELD))).isTrue(); + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.lt(), - Collections.singletonList("myField"))).isTrue(); + Collections.singletonList(MY_FIELD))).isTrue(); - await().until(() -> redis.hget("myKey", "myField") == null); + await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); } @Test From 31c1787fcfd0178503a5f36fa00f1cb4323a8a6b Mon Sep 17 00:00:00 2001 From: Tihomir Mateev <tihomir.mateev@gmail.com> Date: Tue, 23 Apr 2024 21:50:57 +0300 Subject: [PATCH 3/7] Move new commands to RedisHashCommands, added HEXPIREAT, HEXPIRETIME and HPERSIST --- .../core/AbstractRedisAsyncCommands.java | 87 +++++-- .../core/AbstractRedisReactiveCommands.java | 88 +++++-- .../io/lettuce/core/RedisCommandBuilder.java | 221 ++++++++++++++++-- .../api/async/RedisHashAsyncCommands.java | 158 ++++++++++++- .../core/api/async/RedisKeyAsyncCommands.java | 68 ++---- .../reactive/RedisHashReactiveCommands.java | 160 ++++++++++++- .../reactive/RedisKeyReactiveCommands.java | 51 ---- .../core/api/sync/RedisHashCommands.java | 158 ++++++++++++- .../core/api/sync/RedisKeyCommands.java | 50 ---- .../async/NodeSelectionHashAsyncCommands.java | 158 ++++++++++++- .../async/NodeSelectionKeyAsyncCommands.java | 50 ---- .../api/sync/NodeSelectionHashCommands.java | 158 ++++++++++++- .../api/sync/NodeSelectionKeyCommands.java | 60 +---- .../io/lettuce/core/protocol/CommandType.java | 2 +- .../coroutines/RedisHashCoroutinesCommands.kt | 159 ++++++++++++- .../RedisHashCoroutinesCommandsImpl.kt | 58 +++++ .../coroutines/RedisKeyCoroutinesCommands.kt | 62 +---- .../RedisKeyCoroutinesCommandsImpl.kt | 18 -- .../lettuce/core/api/RedisHashCommands.java | 147 ++++++++++++ .../io/lettuce/core/api/RedisKeyCommands.java | 50 ---- .../core/RedisCommandBuilderUnitTests.java | 65 ++++-- .../commands/HashCommandIntegrationTests.java | 117 ++++++++-- .../commands/KeyCommandIntegrationTests.java | 80 ++----- 23 files changed, 1686 insertions(+), 539 deletions(-) diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index 03d0e69f28..10331085fb 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -19,18 +19,21 @@ */ package io.lettuce.core; -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; -import java.util.Set; - import io.lettuce.core.GeoArgs.Unit; import io.lettuce.core.api.StatefulConnection; -import io.lettuce.core.api.async.*; +import io.lettuce.core.api.async.BaseRedisAsyncCommands; +import io.lettuce.core.api.async.RedisAclAsyncCommands; +import io.lettuce.core.api.async.RedisGeoAsyncCommands; +import io.lettuce.core.api.async.RedisHLLAsyncCommands; +import io.lettuce.core.api.async.RedisHashAsyncCommands; +import io.lettuce.core.api.async.RedisKeyAsyncCommands; +import io.lettuce.core.api.async.RedisListAsyncCommands; +import io.lettuce.core.api.async.RedisScriptingAsyncCommands; +import io.lettuce.core.api.async.RedisServerAsyncCommands; +import io.lettuce.core.api.async.RedisSetAsyncCommands; +import io.lettuce.core.api.async.RedisSortedSetAsyncCommands; +import io.lettuce.core.api.async.RedisStringAsyncCommands; +import io.lettuce.core.api.async.RedisTransactionalAsyncCommands; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.codec.Base16; import io.lettuce.core.codec.RedisCodec; @@ -50,6 +53,19 @@ import io.lettuce.core.protocol.ProtocolKeyword; import io.lettuce.core.protocol.RedisCommand; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static io.lettuce.core.protocol.CommandType.EXEC; +import static io.lettuce.core.protocol.CommandType.GEORADIUS; +import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER; +import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER_RO; +import static io.lettuce.core.protocol.CommandType.GEORADIUS_RO; + /** * An asynchronous and thread-safe API for a Redis connection. * @@ -795,22 +811,22 @@ public RedisFuture<Boolean> expire(K key, Duration seconds, ExpireArgs expireArg } @Override - public RedisFuture<Boolean> hexpire(K key, long seconds, List<V> fields) { + public RedisFuture<Boolean> hexpire(K key, long seconds, K... fields) { return hexpire(key, seconds, null, fields); } @Override - public RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields) { + public RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields) { return dispatch(commandBuilder.hexpire(key, seconds, expireArgs, fields)); } @Override - public RedisFuture<Boolean> hexpire(K key, Duration seconds, List<V> fields) { + public RedisFuture<Boolean> hexpire(K key, Duration seconds, K... fields) { return hexpire(key, seconds, null, fields); } @Override - public RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields) { + public RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields) { LettuceAssert.notNull(seconds, "Timeout must not be null"); return hexpire(key, seconds.toMillis() / 1000, expireArgs, fields); } @@ -847,11 +863,49 @@ public RedisFuture<Boolean> expireat(K key, Instant timestamp, ExpireArgs expire return expireat(key, timestamp.toEpochMilli() / 1000, expireArgs); } + @Override + public RedisFuture<Boolean> hexpireat(K key, long timestamp, K... fields) { + return hexpireat(key, timestamp, null, fields); + } + + @Override + public RedisFuture<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields) { + return dispatch(commandBuilder.hexpireat(key, timestamp, expireArgs, fields)); + + } + + @Override + public RedisFuture<Boolean> hexpireat(K key, Date timestamp, K... fields) { + return hexpireat(key, timestamp, null, fields); + } + + @Override + public RedisFuture<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return hexpireat(key, timestamp.getTime() / 1000, expireArgs, fields); + } + + @Override + public RedisFuture<Boolean> hexpireat(K key, Instant timestamp, K... fields) { + return hexpireat(key, timestamp, null, fields); + } + + @Override + public RedisFuture<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return hexpireat(key, timestamp.toEpochMilli() / 1000, expireArgs, fields); + } + @Override public RedisFuture<Long> expiretime(K key) { return dispatch(commandBuilder.expiretime(key)); } + @Override + public RedisFuture<Long> hexpiretime(K key, K... fields) { + return dispatch(commandBuilder.hexpiretime(key, fields)); + } + @Override public <T> RedisFuture<T> fcall(String function, ScriptOutputType type, K... keys) { return dispatch(commandBuilder.fcall(function, type, false, keys)); @@ -1510,6 +1564,11 @@ public RedisFuture<Boolean> persist(K key) { return dispatch(commandBuilder.persist(key)); } + @Override + public RedisFuture<Boolean> hpersist(K key, K... fields) { + return dispatch(commandBuilder.hpersist(key, fields)); + } + @Override public RedisFuture<Boolean> pexpire(K key, long milliseconds) { return pexpire(key, milliseconds, null); diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java index 567401bc97..42efa41acf 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java @@ -19,19 +19,21 @@ */ package io.lettuce.core; -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; -import java.util.Set; -import java.util.function.Supplier; - import io.lettuce.core.GeoArgs.Unit; import io.lettuce.core.api.StatefulConnection; -import io.lettuce.core.api.reactive.*; +import io.lettuce.core.api.reactive.BaseRedisReactiveCommands; +import io.lettuce.core.api.reactive.RedisAclReactiveCommands; +import io.lettuce.core.api.reactive.RedisGeoReactiveCommands; +import io.lettuce.core.api.reactive.RedisHLLReactiveCommands; +import io.lettuce.core.api.reactive.RedisHashReactiveCommands; +import io.lettuce.core.api.reactive.RedisKeyReactiveCommands; +import io.lettuce.core.api.reactive.RedisListReactiveCommands; +import io.lettuce.core.api.reactive.RedisScriptingReactiveCommands; +import io.lettuce.core.api.reactive.RedisServerReactiveCommands; +import io.lettuce.core.api.reactive.RedisSetReactiveCommands; +import io.lettuce.core.api.reactive.RedisSortedSetReactiveCommands; +import io.lettuce.core.api.reactive.RedisStringReactiveCommands; +import io.lettuce.core.api.reactive.RedisTransactionalReactiveCommands; import io.lettuce.core.cluster.api.reactive.RedisClusterReactiveCommands; import io.lettuce.core.codec.Base16; import io.lettuce.core.codec.RedisCodec; @@ -59,6 +61,20 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; + +import static io.lettuce.core.protocol.CommandType.EXEC; +import static io.lettuce.core.protocol.CommandType.GEORADIUS; +import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER; +import static io.lettuce.core.protocol.CommandType.GEORADIUSBYMEMBER_RO; +import static io.lettuce.core.protocol.CommandType.GEORADIUS_RO; + /** * A reactive and thread-safe API for a Redis connection. * @@ -855,22 +871,22 @@ public Mono<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs) { } @Override - public Mono<Boolean> hexpire(K key, long seconds, List<V> fields) { + public Mono<Boolean> hexpire(K key, long seconds, K... fields) { return hexpire(key, seconds, null, fields); } @Override - public Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields) { + public Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields) { return createMono(() -> commandBuilder.hexpire(key, seconds, expireArgs, fields)); } @Override - public Mono<Boolean> hexpire(K key, Duration seconds, List<V> fields) { + public Mono<Boolean> hexpire(K key, Duration seconds, K... fields) { return hexpire(key, seconds, null, fields); } @Override - public Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields) { + public Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields) { LettuceAssert.notNull(seconds, "Timeout must not be null"); return hexpire(key, seconds.toMillis() / 1000, expireArgs, fields); } @@ -907,11 +923,48 @@ public Mono<Boolean> expireat(K key, Instant timestamp, ExpireArgs expireArgs) { return expireat(key, timestamp.toEpochMilli() / 1000, expireArgs); } + @Override + public Mono<Boolean> hexpireat(K key, long timestamp, K... fields) { + return hexpireat(key, timestamp, null, fields); + } + + @Override + public Mono<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields) { + return createMono(() -> commandBuilder.hexpireat(key, timestamp, expireArgs, fields)); + } + + @Override + public Mono<Boolean> hexpireat(K key, Date timestamp, K... fields) { + return hexpireat(key, timestamp, null, fields); + } + + @Override + public Mono<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return hexpireat(key, timestamp.getTime() / 1000, expireArgs, fields); + } + + @Override + public Mono<Boolean> hexpireat(K key, Instant timestamp, K... fields) { + return hexpireat(key, timestamp, null, fields); + } + + @Override + public Mono<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields) { + LettuceAssert.notNull(timestamp, "Timestamp must not be null"); + return hexpireat(key, timestamp.toEpochMilli() / 1000, expireArgs, fields); + } + @Override public Mono<Long> expiretime(K key) { return createMono(() -> commandBuilder.expiretime(key)); } + @Override + public Mono<Long> hexpiretime(K key, K... fields) { + return createMono(() -> commandBuilder.hexpiretime(key, fields)); + } + @Override public <T> Flux<T> fcall(String function, ScriptOutputType type, K... keys) { return createFlux(() -> commandBuilder.fcall(function, type, false, keys)); @@ -1577,6 +1630,11 @@ public Mono<Boolean> persist(K key) { return createMono(() -> commandBuilder.persist(key)); } + @Override + public Mono<Boolean> hpersist(K key, K... fields) { + return createMono(() -> commandBuilder.hpersist(key, fields)); + } + @Override public Mono<Boolean> pexpire(K key, long milliseconds) { return pexpire(key, milliseconds, null); diff --git a/src/main/java/io/lettuce/core/RedisCommandBuilder.java b/src/main/java/io/lettuce/core/RedisCommandBuilder.java index 9b82a026e8..48b68fe1df 100644 --- a/src/main/java/io/lettuce/core/RedisCommandBuilder.java +++ b/src/main/java/io/lettuce/core/RedisCommandBuilder.java @@ -19,19 +19,6 @@ */ package io.lettuce.core; -import static io.lettuce.core.internal.LettuceStrings.*; -import static io.lettuce.core.protocol.CommandKeyword.*; -import static io.lettuce.core.protocol.CommandType.*; -import static io.lettuce.core.protocol.CommandType.COPY; -import static io.lettuce.core.protocol.CommandType.SAVE; - -import java.nio.ByteBuffer; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; - import io.lettuce.core.Range.Boundary; import io.lettuce.core.XReadArgs.StreamOffset; import io.lettuce.core.codec.RedisCodec; @@ -40,7 +27,64 @@ import io.lettuce.core.models.stream.ClaimedMessages; import io.lettuce.core.models.stream.PendingMessage; import io.lettuce.core.models.stream.PendingMessages; -import io.lettuce.core.output.*; +import io.lettuce.core.output.ArrayOutput; +import io.lettuce.core.output.BooleanListOutput; +import io.lettuce.core.output.BooleanOutput; +import io.lettuce.core.output.ByteArrayOutput; +import io.lettuce.core.output.ClaimedMessagesOutput; +import io.lettuce.core.output.CommandOutput; +import io.lettuce.core.output.DateOutput; +import io.lettuce.core.output.DoubleListOutput; +import io.lettuce.core.output.DoubleOutput; +import io.lettuce.core.output.EnumSetOutput; +import io.lettuce.core.output.GenericMapOutput; +import io.lettuce.core.output.GeoCoordinatesListOutput; +import io.lettuce.core.output.GeoCoordinatesValueListOutput; +import io.lettuce.core.output.GeoWithinListOutput; +import io.lettuce.core.output.IntegerListOutput; +import io.lettuce.core.output.IntegerOutput; +import io.lettuce.core.output.KeyListOutput; +import io.lettuce.core.output.KeyOutput; +import io.lettuce.core.output.KeyScanOutput; +import io.lettuce.core.output.KeyScanStreamingOutput; +import io.lettuce.core.output.KeyStreamingChannel; +import io.lettuce.core.output.KeyStreamingOutput; +import io.lettuce.core.output.KeyValueListOutput; +import io.lettuce.core.output.KeyValueListScoredValueOutput; +import io.lettuce.core.output.KeyValueOfScoredValueOutput; +import io.lettuce.core.output.KeyValueOutput; +import io.lettuce.core.output.KeyValueScanStreamingOutput; +import io.lettuce.core.output.KeyValueScoredValueOutput; +import io.lettuce.core.output.KeyValueStreamingChannel; +import io.lettuce.core.output.KeyValueStreamingOutput; +import io.lettuce.core.output.KeyValueValueListOutput; +import io.lettuce.core.output.ListOfGenericMapsOutput; +import io.lettuce.core.output.MapOutput; +import io.lettuce.core.output.MapScanOutput; +import io.lettuce.core.output.NestedMultiOutput; +import io.lettuce.core.output.ObjectOutput; +import io.lettuce.core.output.PendingMessageListOutput; +import io.lettuce.core.output.PendingMessagesOutput; +import io.lettuce.core.output.ScoredValueListOutput; +import io.lettuce.core.output.ScoredValueOutput; +import io.lettuce.core.output.ScoredValueScanOutput; +import io.lettuce.core.output.ScoredValueScanStreamingOutput; +import io.lettuce.core.output.ScoredValueStreamingChannel; +import io.lettuce.core.output.ScoredValueStreamingOutput; +import io.lettuce.core.output.StatusOutput; +import io.lettuce.core.output.StreamMessageListOutput; +import io.lettuce.core.output.StreamReadOutput; +import io.lettuce.core.output.StringListOutput; +import io.lettuce.core.output.StringMatchResultOutput; +import io.lettuce.core.output.StringValueListOutput; +import io.lettuce.core.output.ValueListOutput; +import io.lettuce.core.output.ValueOutput; +import io.lettuce.core.output.ValueScanOutput; +import io.lettuce.core.output.ValueScanStreamingOutput; +import io.lettuce.core.output.ValueSetOutput; +import io.lettuce.core.output.ValueStreamingChannel; +import io.lettuce.core.output.ValueStreamingOutput; +import io.lettuce.core.output.ValueValueListOutput; import io.lettuce.core.protocol.BaseRedisCommandBuilder; import io.lettuce.core.protocol.Command; import io.lettuce.core.protocol.CommandArgs; @@ -48,6 +92,111 @@ import io.lettuce.core.protocol.CommandType; import io.lettuce.core.protocol.RedisCommand; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static io.lettuce.core.internal.LettuceStrings.string; +import static io.lettuce.core.protocol.CommandKeyword.ADDSLOTS; +import static io.lettuce.core.protocol.CommandKeyword.ADDSLOTSRANGE; +import static io.lettuce.core.protocol.CommandKeyword.AFTER; +import static io.lettuce.core.protocol.CommandKeyword.AND; +import static io.lettuce.core.protocol.CommandKeyword.BEFORE; +import static io.lettuce.core.protocol.CommandKeyword.BUMPEPOCH; +import static io.lettuce.core.protocol.CommandKeyword.BYLEX; +import static io.lettuce.core.protocol.CommandKeyword.BYSCORE; +import static io.lettuce.core.protocol.CommandKeyword.CACHING; +import static io.lettuce.core.protocol.CommandKeyword.CAT; +import static io.lettuce.core.protocol.CommandKeyword.CHANNELS; +import static io.lettuce.core.protocol.CommandKeyword.CONSUMERS; +import static io.lettuce.core.protocol.CommandKeyword.COUNT; +import static io.lettuce.core.protocol.CommandKeyword.COUNTKEYSINSLOT; +import static io.lettuce.core.protocol.CommandKeyword.CREATE; +import static io.lettuce.core.protocol.CommandKeyword.DELSLOTS; +import static io.lettuce.core.protocol.CommandKeyword.DELSLOTSRANGE; +import static io.lettuce.core.protocol.CommandKeyword.DELUSER; +import static io.lettuce.core.protocol.CommandKeyword.DRYRUN; +import static io.lettuce.core.protocol.CommandKeyword.ENCODING; +import static io.lettuce.core.protocol.CommandKeyword.FAILOVER; +import static io.lettuce.core.protocol.CommandKeyword.FLUSH; +import static io.lettuce.core.protocol.CommandKeyword.FLUSHSLOTS; +import static io.lettuce.core.protocol.CommandKeyword.FORCE; +import static io.lettuce.core.protocol.CommandKeyword.FORGET; +import static io.lettuce.core.protocol.CommandKeyword.FREQ; +import static io.lettuce.core.protocol.CommandKeyword.GENPASS; +import static io.lettuce.core.protocol.CommandKeyword.GETKEYSINSLOT; +import static io.lettuce.core.protocol.CommandKeyword.GETNAME; +import static io.lettuce.core.protocol.CommandKeyword.GETREDIR; +import static io.lettuce.core.protocol.CommandKeyword.GETUSER; +import static io.lettuce.core.protocol.CommandKeyword.GROUPS; +import static io.lettuce.core.protocol.CommandKeyword.HARD; +import static io.lettuce.core.protocol.CommandKeyword.HTSTATS; +import static io.lettuce.core.protocol.CommandKeyword.ID; +import static io.lettuce.core.protocol.CommandKeyword.IDLETIME; +import static io.lettuce.core.protocol.CommandKeyword.IMPORTING; +import static io.lettuce.core.protocol.CommandKeyword.KEYSLOT; +import static io.lettuce.core.protocol.CommandKeyword.KILL; +import static io.lettuce.core.protocol.CommandKeyword.LEN; +import static io.lettuce.core.protocol.CommandKeyword.LIMIT; +import static io.lettuce.core.protocol.CommandKeyword.LIST; +import static io.lettuce.core.protocol.CommandKeyword.LOAD; +import static io.lettuce.core.protocol.CommandKeyword.LOG; +import static io.lettuce.core.protocol.CommandKeyword.MAXLEN; +import static io.lettuce.core.protocol.CommandKeyword.MEET; +import static io.lettuce.core.protocol.CommandKeyword.MIGRATING; +import static io.lettuce.core.protocol.CommandKeyword.NO; +import static io.lettuce.core.protocol.CommandKeyword.NODE; +import static io.lettuce.core.protocol.CommandKeyword.NODES; +import static io.lettuce.core.protocol.CommandKeyword.NOSAVE; +import static io.lettuce.core.protocol.CommandKeyword.NOT; +import static io.lettuce.core.protocol.CommandKeyword.NOVALUES; +import static io.lettuce.core.protocol.CommandKeyword.NUMPAT; +import static io.lettuce.core.protocol.CommandKeyword.NUMSUB; +import static io.lettuce.core.protocol.CommandKeyword.OFF; +import static io.lettuce.core.protocol.CommandKeyword.ON; +import static io.lettuce.core.protocol.CommandKeyword.ONE; +import static io.lettuce.core.protocol.CommandKeyword.OR; +import static io.lettuce.core.protocol.CommandKeyword.PAUSE; +import static io.lettuce.core.protocol.CommandKeyword.REFCOUNT; +import static io.lettuce.core.protocol.CommandKeyword.RELOAD; +import static io.lettuce.core.protocol.CommandKeyword.REPLACE; +import static io.lettuce.core.protocol.CommandKeyword.REPLICAS; +import static io.lettuce.core.protocol.CommandKeyword.REPLICATE; +import static io.lettuce.core.protocol.CommandKeyword.RESET; +import static io.lettuce.core.protocol.CommandKeyword.RESETSTAT; +import static io.lettuce.core.protocol.CommandKeyword.RESTART; +import static io.lettuce.core.protocol.CommandKeyword.REV; +import static io.lettuce.core.protocol.CommandKeyword.REWRITE; +import static io.lettuce.core.protocol.CommandKeyword.SAVECONFIG; +import static io.lettuce.core.protocol.CommandKeyword.SEGFAULT; +import static io.lettuce.core.protocol.CommandKeyword.SETINFO; +import static io.lettuce.core.protocol.CommandKeyword.SETNAME; +import static io.lettuce.core.protocol.CommandKeyword.SETSLOT; +import static io.lettuce.core.protocol.CommandKeyword.SETUSER; +import static io.lettuce.core.protocol.CommandKeyword.SHARDCHANNELS; +import static io.lettuce.core.protocol.CommandKeyword.SHARDNUMSUB; +import static io.lettuce.core.protocol.CommandKeyword.SHARDS; +import static io.lettuce.core.protocol.CommandKeyword.SLAVES; +import static io.lettuce.core.protocol.CommandKeyword.SLOTS; +import static io.lettuce.core.protocol.CommandKeyword.SOFT; +import static io.lettuce.core.protocol.CommandKeyword.STABLE; +import static io.lettuce.core.protocol.CommandKeyword.STREAM; +import static io.lettuce.core.protocol.CommandKeyword.TAKEOVER; +import static io.lettuce.core.protocol.CommandKeyword.TRACKING; +import static io.lettuce.core.protocol.CommandKeyword.UNBLOCK; +import static io.lettuce.core.protocol.CommandKeyword.USAGE; +import static io.lettuce.core.protocol.CommandKeyword.USERS; +import static io.lettuce.core.protocol.CommandKeyword.WHOAMI; +import static io.lettuce.core.protocol.CommandKeyword.WITHSCORE; +import static io.lettuce.core.protocol.CommandKeyword.WITHSCORES; +import static io.lettuce.core.protocol.CommandKeyword.WITHVALUES; +import static io.lettuce.core.protocol.CommandKeyword.XOR; +import static io.lettuce.core.protocol.CommandKeyword.YES; +import static io.lettuce.core.protocol.CommandType.*; + /** * @param <K> * @param <V> @@ -978,9 +1127,9 @@ Command<K, V, Boolean> expire(K key, long seconds, ExpireArgs expireArgs) { return createCommand(EXPIRE, new BooleanOutput<>(codec), args); } - Command<K, V, Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields) { + Command<K, V, Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields) { notNullKey(key); - notEmpty(fields == null ? new Object[]{} : fields.toArray()); + notEmpty(fields); CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).add(seconds); @@ -988,13 +1137,28 @@ Command<K, V, Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List< expireArgs.build(args); } - args.add(fields.size()); - - fields.forEach(args::addValue); + args.add(fields.length); + args.addKeys(fields); return createCommand(HEXPIRE, new BooleanOutput<>(codec), args); } + Command<K, V, Boolean> hexpireat(K key, long seconds, ExpireArgs expireArgs, K... fields) { + notNullKey(key); + notEmpty(fields); + + CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).add(seconds); + + if (expireArgs != null) { + expireArgs.build(args); + } + + args.add(fields.length); + args.addKeys(fields); + + return createCommand(HEXPIREAT, new BooleanOutput<>(codec), args); + } + Command<K, V, Boolean> expireat(K key, long timestamp, ExpireArgs expireArgs) { notNullKey(key); @@ -1014,6 +1178,15 @@ Command<K, V, Long> expiretime(K key) { return createCommand(EXPIRETIME, new IntegerOutput<>(codec), args); } + Command<K, V, Long> hexpiretime(K key, K... fields) { + notNullKey(key); + + CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key); + args.add(fields.length); + args.addKeys(fields); + return createCommand(HEXPIRETIME, new IntegerOutput<>(codec), args); + } + Command<K, V, String> flushall() { return createCommand(FLUSHALL, new StatusOutput<>(codec)); } @@ -2060,6 +2233,16 @@ Command<K, V, Boolean> persist(K key) { return createCommand(PERSIST, new BooleanOutput<>(codec), key); } + Command<K, V, Boolean> hpersist(K key, K... fields) { + notNullKey(key); + + CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key); + args.add(fields.length); + args.addKeys(fields); + + return createCommand(HPERSIST, new BooleanOutput<>(codec), args); + } + Command<K, V, Boolean> pexpire(K key, long milliseconds, ExpireArgs expireArgs) { notNullKey(key); diff --git a/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java b/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java index cc9b8b1489..9f514450fa 100644 --- a/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java +++ b/src/main/java/io/lettuce/core/api/async/RedisHashAsyncCommands.java @@ -19,9 +19,7 @@ */ package io.lettuce.core.api.async; -import java.util.List; -import java.util.Map; - +import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanCursor; import io.lettuce.core.KeyValue; import io.lettuce.core.MapScanCursor; @@ -33,6 +31,12 @@ import io.lettuce.core.output.KeyValueStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; + /** * Asynchronous executed commands for Hashes (Key-Value pairs). * @@ -429,4 +433,152 @@ public interface RedisHashAsyncCommands<K, V> { * @return Long count of the keys. */ RedisFuture<Long> hvals(ValueStreamingChannel<V> channel, K key); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, long seconds, K... fields); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, Duration seconds, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpireat(K key, long timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpireat(K key, Date timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpireat(K key, Instant timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + RedisFuture<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Get the time to live for one or more fields in as unix timestamp in seconds. + * + * @param key the key. + * @param fields one or more fields to get the TTL for. + * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if + * the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist. + * @since 7.0 + */ + RedisFuture<Long> hexpiretime(K key, K... fields); + + /** + * Remove the expiration from one or more fields. + * + * @param key the key. + * @param fields one or more fields to remove the TTL for. + * @return Boolean integer-reply specifically: + * + * {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an + * associated timeout. + */ + RedisFuture<Boolean> hpersist(K key, K... fields); } 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 5a6078d5b6..b5253b4e9d 100644 --- a/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java +++ b/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java @@ -19,15 +19,25 @@ */ package io.lettuce.core.api.async; +import io.lettuce.core.CopyArgs; +import io.lettuce.core.ExpireArgs; +import io.lettuce.core.KeyScanArgs; +import io.lettuce.core.KeyScanCursor; +import io.lettuce.core.MigrateArgs; +import io.lettuce.core.RedisFuture; +import io.lettuce.core.RestoreArgs; +import io.lettuce.core.ScanArgs; +import io.lettuce.core.ScanCursor; +import io.lettuce.core.SortArgs; +import io.lettuce.core.StreamScanCursor; +import io.lettuce.core.output.KeyStreamingChannel; +import io.lettuce.core.output.ValueStreamingChannel; + import java.time.Duration; import java.time.Instant; import java.util.Date; import java.util.List; -import io.lettuce.core.*; -import io.lettuce.core.output.KeyStreamingChannel; -import io.lettuce.core.output.ValueStreamingChannel; - /** * Asynchronous executed commands for Keys (Key manipulation/querying). * @@ -137,56 +147,6 @@ public interface RedisKeyAsyncCommands<K, V> { */ RedisFuture<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - RedisFuture<Boolean> hexpire(K key, long seconds, List<V> fields); - - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param expireArgs the expire arguments. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - RedisFuture<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - RedisFuture<Boolean> hexpire(K key, Duration seconds, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param expireArgs the {@link ExpireArgs}. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - RedisFuture<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); - /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java b/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java index 080087510a..e02fe5b80a 100644 --- a/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java +++ b/src/main/java/io/lettuce/core/api/reactive/RedisHashReactiveCommands.java @@ -19,10 +19,7 @@ */ package io.lettuce.core.api.reactive; -import java.util.Map; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; +import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanCursor; import io.lettuce.core.KeyValue; import io.lettuce.core.MapScanCursor; @@ -32,6 +29,13 @@ import io.lettuce.core.output.KeyStreamingChannel; import io.lettuce.core.output.KeyValueStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.Map; /** * Reactive executed commands for Hashes (Key-Value pairs). @@ -451,4 +455,152 @@ public interface RedisHashReactiveCommands<K, V> { */ @Deprecated Mono<Long> hvals(ValueStreamingChannel<V> channel, K key); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, long seconds, K... fields); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, Duration seconds, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpireat(K key, long timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpireat(K key, Date timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpireat(K key, Instant timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Mono<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Get the time to live for one or more fields in as unix timestamp in seconds. + * + * @param key the key. + * @param fields one or more fields to get the TTL for. + * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if + * the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist. + * @since 7.0 + */ + Mono<Long> hexpiretime(K key, K... fields); + + /** + * Remove the expiration from one or more fields. + * + * @param key the key. + * @param fields one or more fields to remove the TTL for. + * @return Boolean integer-reply specifically: + * + * {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an + * associated timeout. + */ + Mono<Boolean> hpersist(K key, K... fields); } 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 b3f1ef89f8..1fbfdda1a8 100644 --- a/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java +++ b/src/main/java/io/lettuce/core/api/reactive/RedisKeyReactiveCommands.java @@ -22,7 +22,6 @@ import java.time.Duration; import java.time.Instant; import java.util.Date; -import java.util.List; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -148,56 +147,6 @@ public interface RedisKeyReactiveCommands<K, V> { */ Mono<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Mono<Boolean> hexpire(K key, long seconds, List<V> fields); - - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param expireArgs the expire arguments. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Mono<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Mono<Boolean> hexpire(K key, Duration seconds, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param expireArgs the {@link ExpireArgs}. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Mono<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); - /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java b/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java index 816ec08227..ab41a1cafd 100644 --- a/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java +++ b/src/main/java/io/lettuce/core/api/sync/RedisHashCommands.java @@ -19,9 +19,7 @@ */ package io.lettuce.core.api.sync; -import java.util.List; -import java.util.Map; - +import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanCursor; import io.lettuce.core.KeyValue; import io.lettuce.core.MapScanCursor; @@ -32,6 +30,12 @@ import io.lettuce.core.output.KeyValueStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; + /** * Synchronous executed commands for Hashes (Key-Value pairs). * @@ -430,4 +434,152 @@ public interface RedisHashCommands<K, V> { * @return Long count of the keys. */ Long hvals(ValueStreamingChannel<V> channel, K key); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, K... fields); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, long timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Date timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Instant timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Get the time to live for one or more fields in as unix timestamp in seconds. + * + * @param key the key. + * @param fields one or more fields to get the TTL for. + * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if + * the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist. + * @since 7.0 + */ + Long hexpiretime(K key, K... fields); + + /** + * Remove the expiration from one or more fields. + * + * @param key the key. + * @param fields one or more fields to remove the TTL for. + * @return Boolean integer-reply specifically: + * + * {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an + * associated timeout. + */ + Boolean hpersist(K key, K... fields); } 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 07faab4c2e..516e4ab072 100644 --- a/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java +++ b/src/main/java/io/lettuce/core/api/sync/RedisKeyCommands.java @@ -146,56 +146,6 @@ public interface RedisKeyCommands<K, V> { */ Boolean expire(K key, Duration seconds, ExpireArgs expireArgs); - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, long seconds, List<V> fields); - - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param expireArgs the expire arguments. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, Duration seconds, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param expireArgs the {@link ExpireArgs}. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); - /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java index dd99fd23b0..442444c6ed 100644 --- a/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionHashAsyncCommands.java @@ -19,9 +19,7 @@ */ package io.lettuce.core.cluster.api.async; -import java.util.List; -import java.util.Map; - +import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanCursor; import io.lettuce.core.KeyValue; import io.lettuce.core.MapScanCursor; @@ -32,6 +30,12 @@ import io.lettuce.core.output.KeyValueStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; + /** * Asynchronous executed commands on a node selection for Hashes (Key-Value pairs). * @@ -428,4 +432,152 @@ public interface NodeSelectionHashAsyncCommands<K, V> { * @return Long count of the keys. */ AsyncExecutions<Long> hvals(ValueStreamingChannel<V> channel, K key); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, long seconds, K... fields); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, Duration seconds, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpireat(K key, long timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpireat(K key, Date timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpireat(K key, Instant timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + AsyncExecutions<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Get the time to live for one or more fields in as unix timestamp in seconds. + * + * @param key the key. + * @param fields one or more fields to get the TTL for. + * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if + * the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist. + * @since 7.0 + */ + AsyncExecutions<Long> hexpiretime(K key, K... fields); + + /** + * Remove the expiration from one or more fields. + * + * @param key the key. + * @param fields one or more fields to remove the TTL for. + * @return Boolean integer-reply specifically: + * + * {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an + * associated timeout. + */ + AsyncExecutions<Boolean> hpersist(K key, K... fields); } 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 422111c0ea..44bbd168a3 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 @@ -146,56 +146,6 @@ public interface NodeSelectionKeyAsyncCommands<K, V> { */ AsyncExecutions<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - AsyncExecutions<Boolean> hexpire(K key, long seconds, List<V> fields); - - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param expireArgs the expire arguments. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - AsyncExecutions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - AsyncExecutions<Boolean> hexpire(K key, Duration seconds, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param expireArgs the {@link ExpireArgs}. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - AsyncExecutions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); - /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java index 4d9a3c694b..f2aeaf52b4 100644 --- a/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java +++ b/src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionHashCommands.java @@ -19,9 +19,7 @@ */ package io.lettuce.core.cluster.api.sync; -import java.util.List; -import java.util.Map; - +import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanCursor; import io.lettuce.core.KeyValue; import io.lettuce.core.MapScanCursor; @@ -32,6 +30,12 @@ import io.lettuce.core.output.KeyValueStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; + /** * Synchronous executed commands on a node selection for Hashes (Key-Value pairs). * @@ -428,4 +432,152 @@ public interface NodeSelectionHashCommands<K, V> { * @return Long count of the keys. */ Executions<Long> hvals(ValueStreamingChannel<V> channel, K key); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, long seconds, K... fields); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, Duration seconds, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpireat(K key, long timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpireat(K key, Date timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpireat(K key, Instant timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Executions<Boolean> hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Get the time to live for one or more fields in as unix timestamp in seconds. + * + * @param key the key. + * @param fields one or more fields to get the TTL for. + * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if + * the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist. + * @since 7.0 + */ + Executions<Long> hexpiretime(K key, K... fields); + + /** + * Remove the expiration from one or more fields. + * + * @param key the key. + * @param fields one or more fields to remove the TTL for. + * @return Boolean integer-reply specifically: + * + * {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an + * associated timeout. + */ + Executions<Boolean> hpersist(K key, K... fields); } 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 b523434d24..398fcf1f65 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 @@ -19,11 +19,6 @@ */ package io.lettuce.core.cluster.api.sync; -import java.time.Duration; -import java.time.Instant; -import java.util.Date; -import java.util.List; - import io.lettuce.core.CopyArgs; import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanArgs; @@ -37,6 +32,11 @@ import io.lettuce.core.output.KeyStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; + /** * Synchronous executed commands on a node selection for Keys (Key manipulation/querying). * @@ -146,56 +146,6 @@ public interface NodeSelectionKeyCommands<K, V> { */ Executions<Boolean> expire(K key, Duration seconds, ExpireArgs expireArgs); - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Executions<Boolean> hexpire(K key, long seconds, List<V> fields); - - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param expireArgs the expire arguments. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Executions<Boolean> hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Executions<Boolean> hexpire(K key, Duration seconds, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param expireArgs the {@link ExpireArgs}. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Executions<Boolean> hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); - /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/main/java/io/lettuce/core/protocol/CommandType.java b/src/main/java/io/lettuce/core/protocol/CommandType.java index bd4c04c982..7207a50dab 100644 --- a/src/main/java/io/lettuce/core/protocol/CommandType.java +++ b/src/main/java/io/lettuce/core/protocol/CommandType.java @@ -46,7 +46,7 @@ public enum CommandType implements ProtocolKeyword { // Keys - COPY, DEL, DUMP, EXISTS, HEXPIRE, EXPIRE, EXPIREAT, EXPIRETIME, KEYS, MIGRATE, MOVE, OBJECT, PERSIST, PEXPIRE, PEXPIREAT, PEXPIRETIME, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK, + COPY, DEL, DUMP, EXISTS, HEXPIRE, EXPIRE, HEXPIREAT, EXPIREAT, HEXPIRETIME, EXPIRETIME, KEYS, MIGRATE, MOVE, OBJECT, HPERSIST, PERSIST, PEXPIRE, PEXPIREAT, PEXPIRETIME, PTTL, RANDOMKEY, RENAME, RENAMENX, RESTORE, TOUCH, TTL, TYPE, SCAN, UNLINK, // String diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt index 6ab7746601..34a4228f49 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommands.kt @@ -20,8 +20,17 @@ package io.lettuce.core.api.coroutines -import io.lettuce.core.* +import io.lettuce.core.ExperimentalLettuceCoroutinesApi +import io.lettuce.core.ExpireArgs import kotlinx.coroutines.flow.Flow +import io.lettuce.core.KeyScanCursor +import io.lettuce.core.KeyValue +import io.lettuce.core.MapScanCursor +import io.lettuce.core.ScanArgs +import io.lettuce.core.ScanCursor +import java.time.Duration +import java.time.Instant +import java.util.* /** * Coroutine executed commands for Hashes (Key-Value pairs). @@ -298,5 +307,153 @@ interface RedisHashCoroutinesCommands<K : Any, V : Any> { */ fun hvals(key: K): Flow<V> + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Long, vararg fields: K): Boolean? + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL [Duration] + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Duration, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL [Duration] + * @param expireArgs the [ExpireArgs]. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpire(key: K, seconds: Duration, expireArgs: ExpireArgs, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpireat(key: K, timestamp: Long, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpireat(key: K, timestamp: Long, expireArgs: ExpireArgs, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpireat(key: K, timestamp: Date, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpireat(key: K, timestamp: Date, expireArgs: ExpireArgs, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpireat(key: K, timestamp: Instant, vararg fields: K): Boolean? + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + suspend fun hexpireat(key: K, timestamp: Instant, expireArgs: ExpireArgs, vararg fields: K): Boolean? + + /** + * Get the time to live for one or more fields in as unix timestamp in seconds. + * + * @param key the key. + * @param fields one or more fields to get the TTL for. + * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns `-1` if + * the key exists but has no associated expiration time. The command returns `-2` if the key does not exist. + * @since 7.0 + */ + suspend fun hexpiretime(key: K, vararg fields: K): Long? + + /** + * Remove the expiration from one or more fields. + * + * @param key the key. + * @param fields one or more fields to remove the TTL for. + * @return Boolean integer-reply specifically: + * + * `true` if the timeout was removed. `false` if `key` does not exist or does not have an + * associated timeout. + */ + suspend fun hpersist(key: K, vararg fields: K): Boolean? + } diff --git a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt index ec1a488735..8a1d959e54 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisHashCoroutinesCommandsImpl.kt @@ -26,6 +26,9 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.toList import kotlinx.coroutines.reactive.asFlow import kotlinx.coroutines.reactive.awaitFirstOrNull +import java.time.Duration +import java.time.Instant +import java.util.* /** @@ -113,5 +116,60 @@ internal class RedisHashCoroutinesCommandsImpl<K : Any, V : Any>(internal val op override fun hvals(key: K): Flow<V> = ops.hvals(key).asFlow() + override suspend fun hexpire(key: K, seconds: Long, vararg fields: K): Boolean? = + ops.hexpire(key, seconds, *fields).awaitFirstOrNull() + + override suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, vararg fields: K): Boolean? = + ops.hexpire(key, seconds, expireArgs, *fields).awaitFirstOrNull() + + override suspend fun hexpire(key: K, seconds: Duration, vararg fields: K): Boolean? = + ops.hexpire(key, seconds, *fields).awaitFirstOrNull() + + override suspend fun hexpire( + key: K, + seconds: Duration, + expireArgs: ExpireArgs, + vararg fields: K + ): Boolean? = + ops.hexpire(key, seconds, expireArgs, *fields).awaitFirstOrNull() + + override suspend fun hexpireat(key: K, timestamp: Date, vararg fields: K): Boolean? = + ops.hexpireat(key, timestamp, *fields).awaitFirstOrNull() + + override suspend fun hexpireat( + key: K, + timestamp: Long, + expireArgs: ExpireArgs, + vararg fields: K + ): Boolean? = + ops.hexpireat(key, timestamp, expireArgs, *fields).awaitFirstOrNull() + + override suspend fun hexpireat(key: K, timestamp: Instant, vararg fields: K): Boolean? = + ops.hexpireat(key, timestamp, *fields).awaitFirstOrNull() + + override suspend fun hexpireat( + key: K, + timestamp: Instant, + expireArgs: ExpireArgs, + vararg fields: K + ): Boolean? = + ops.hexpireat(key, timestamp, expireArgs, *fields).awaitFirstOrNull() + + override suspend fun hexpireat(key: K, timestamp: Long, vararg fields: K): Boolean? = + ops.hexpireat(key, timestamp, *fields).awaitFirstOrNull() + + override suspend fun hexpireat( + key: K, + timestamp: Date, + expireArgs: ExpireArgs, + vararg fields: K + ): Boolean? = + ops.hexpireat(key, timestamp, expireArgs, *fields).awaitFirstOrNull() + + override suspend fun hexpiretime(key: K, vararg fields: K): Long? = + ops.hexpiretime(key).awaitFirstOrNull() + + override suspend fun hpersist(key: K, vararg fields: K): Boolean? = ops.hpersist(key).awaitFirstOrNull() + } 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 f979c8bc4e..72aa35c614 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt @@ -20,11 +20,19 @@ package io.lettuce.core.api.coroutines -import io.lettuce.core.* +import io.lettuce.core.CopyArgs +import io.lettuce.core.ExperimentalLettuceCoroutinesApi +import io.lettuce.core.ExpireArgs +import io.lettuce.core.KeyScanCursor +import io.lettuce.core.MigrateArgs +import io.lettuce.core.RestoreArgs +import io.lettuce.core.ScanArgs +import io.lettuce.core.ScanCursor +import io.lettuce.core.SortArgs import kotlinx.coroutines.flow.Flow import java.time.Duration import java.time.Instant -import java.util.* +import java.util.Date /** * Coroutine executed commands for Keys (Key manipulation/querying). @@ -136,56 +144,6 @@ interface RedisKeyCoroutinesCommands<K : Any, V : Any> { */ suspend fun expire(key: K, seconds: Duration, expireArgs: ExpireArgs): Boolean? - /** - * Set the time to live (in seconds) for a [List] of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param fields a [List] of fields to set the TTL for. - * @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 7.0 - */ - suspend fun hexpire(key: K, seconds: Long, fields: List<V>): Boolean? - - /** - * Set the time to live (in seconds) for a [List] of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param expireArgs the expire arguments. - * @param fields a [List] of fields to set the TTL for. - * @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 7.0 - */ - suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, fields: List<V>): Boolean? - - /** - * Set the time to live for a [List] of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL [Duration] - * @param fields a [List] of fields to set the TTL for. - * @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 7.0 - */ - suspend fun hexpire(key: K, seconds: Duration, fields: List<V>): Boolean? - - /** - * Set the time to live for a [List] of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL [Duration] - * @param expireArgs the [ExpireArgs]. - * @param fields a [List] of fields to set the TTL for. - * @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 7.0 - */ - suspend fun hexpire(key: K, seconds: Duration, expireArgs: ExpireArgs, fields: List<V>): Boolean? - /** * Set the expiration for a key as a UNIX timestamp. * 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 d088d03ad8..5b62a92d3c 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommandsImpl.kt @@ -74,24 +74,6 @@ internal class RedisKeyCoroutinesCommandsImpl<K : Any, V : Any>(internal val ops ): Boolean? = ops.expire(key, seconds, expireArgs).awaitFirstOrNull() - override suspend fun hexpire(key: K, seconds: Long, fields: List<V>): Boolean? = - ops.hexpire(key, seconds, fields).awaitFirstOrNull() - - override suspend fun hexpire(key: K, seconds: Long, expireArgs: ExpireArgs, fields: List<V>): Boolean? = - ops.hexpire(key, seconds, expireArgs, fields).awaitFirstOrNull() - - - override suspend fun hexpire(key: K, seconds: Duration, fields: List<V>): Boolean? = - ops.hexpire(key, seconds, fields).awaitFirstOrNull() - - override suspend fun hexpire( - key: K, - seconds: Duration, - expireArgs: ExpireArgs, - fields: List<V> - ): Boolean? = - ops.hexpire(key, seconds, expireArgs, fields).awaitFirstOrNull() - override suspend fun expireat(key: K, timestamp: Date): Boolean? = ops.expireat(key, timestamp).awaitFirstOrNull() diff --git a/src/main/templates/io/lettuce/core/api/RedisHashCommands.java b/src/main/templates/io/lettuce/core/api/RedisHashCommands.java index ddef1ce24f..96dfe525eb 100644 --- a/src/main/templates/io/lettuce/core/api/RedisHashCommands.java +++ b/src/main/templates/io/lettuce/core/api/RedisHashCommands.java @@ -428,4 +428,151 @@ public interface RedisHashCommands<K, V> { */ Long hvals(ValueStreamingChannel<V> channel, K key); + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, K... fields); + + /** + * Set the time to live (in seconds) for one or more fields, belonging to a certain key. + * + * @param key the key of the fields. + * @param seconds the seconds type: long. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key. + * + * @param key the key. + * @param seconds the TTL {@link Duration} + * @param expireArgs the {@link ExpireArgs}. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, long timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, long timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Date timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Date timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Instant timestamp, K... fields); + + /** + * Set the time to live for one or more fields, belonging to a certain key as a UNIX timestamp. + * + * @param key the key. + * @param timestamp the timestamp type: posix time. + * @param expireArgs the expire arguments. + * @param fields one or more fields to set the TTL for. + * @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 7.0 + */ + Boolean hexpireat(K key, Instant timestamp, ExpireArgs expireArgs, K... fields); + + /** + * Get the time to live for one or more fields in as unix timestamp in seconds. + * + * @param key the key. + * @param fields one or more fields to get the TTL for. + * @return Long integer-reply in seconds, or a negative value in order to signal an error. The command returns {@code -1} if + * the key exists but has no associated expiration time. The command returns {@code -2} if the key does not exist. + * @since 7.0 + */ + Long hexpiretime(K key, K... fields); + + /** + * Remove the expiration from one or more fields. + * + * @param key the key. + * @param fields one or more fields to remove the TTL for. + * @return Boolean integer-reply specifically: + * + * {@code true} if the timeout was removed. {@code false} if {@code key} does not exist or does not have an + * associated timeout. + */ + Boolean hpersist(K key, K... fields); } diff --git a/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java b/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java index 6f8ba3c27b..bdd3568991 100644 --- a/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java +++ b/src/main/templates/io/lettuce/core/api/RedisKeyCommands.java @@ -138,56 +138,6 @@ public interface RedisKeyCommands<K, V> { */ Boolean expire(K key, Duration seconds, ExpireArgs expireArgs); - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, long seconds, List<V> fields); - - /** - * Set the time to live (in seconds) for a {@link List} of fields, belonging to a certain key. - * - * @param key the key of the fields. - * @param seconds the seconds type: long. - * @param expireArgs the expire arguments. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, long seconds, ExpireArgs expireArgs, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, Duration seconds, List<V> fields); - - /** - * Set the time to live for a {@link List} of fields, belonging to a certain key. - * - * @param key the key. - * @param seconds the TTL {@link Duration} - * @param expireArgs the {@link ExpireArgs}. - * @param fields a {@link List} of fields to set the TTL for. - * @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 7.0 - */ - Boolean hexpire(K key, Duration seconds, ExpireArgs expireArgs, List<V> fields); - /** * Set the expiration for a key as a UNIX timestamp. * diff --git a/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java b/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java index 2136ff0a92..01b5be2241 100644 --- a/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java +++ b/src/test/java/io/lettuce/core/RedisCommandBuilderUnitTests.java @@ -1,17 +1,14 @@ package io.lettuce.core; -import static org.assertj.core.api.Assertions.*; - -import java.nio.charset.StandardCharsets; -import java.util.Collections; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.EmptyByteBuf; -import org.junit.jupiter.api.Test; - import io.lettuce.core.codec.StringCodec; import io.lettuce.core.protocol.Command; +import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import org.junit.jupiter.api.Test; + +import java.nio.charset.StandardCharsets; + +import static org.assertj.core.api.Assertions.assertThat; /** * Unit tests for {@link RedisCommandBuilder}. @@ -20,7 +17,10 @@ */ class RedisCommandBuilderUnitTests { public static final String MY_KEY = "hKey"; - public static final String MY_FIELD = "hField"; + public static final String MY_FIELD1 = "hField1"; + public static final String MY_FIELD2 = "hField2"; + public static final String MY_FIELD3 = "hField3"; + RedisCommandBuilder<String, String> sut = new RedisCommandBuilder<>(StringCodec.UTF8); @@ -37,11 +37,50 @@ void shouldCorrectlyConstructXreadgroup() { @Test void shouldCorrectlyConstructHexpire() { - Command<String, String, ?> command = sut.hexpire(MY_KEY, 1, ExpireArgs.Builder.nx(), Collections.singletonList(MY_FIELD)); + Command<String, String, ?> command = + sut.hexpire(MY_KEY, 1, ExpireArgs.Builder.nx(), MY_FIELD1, MY_FIELD2, MY_FIELD3); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*8\r\n" + "$7\r\n" + "HEXPIRE\r\n" + "$4\r\n" + + "hKey\r\n" + "$1\r\n" + "1\r\n" + "$2\r\n" + "NX\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n" + + "$7\r\n" + "hField2\r\n" + "$7\r\n" + "hField3\r\n"); + } + + @Test + void shouldCorrectlyConstructHexpireat() { + + Command<String, String, ?> command = + sut.hexpireat(MY_KEY, 1, ExpireArgs.Builder.nx(), MY_FIELD1, MY_FIELD2, MY_FIELD3); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*8\r\n" + "$9\r\n" + "HEXPIREAT\r\n" + "$4\r\n" + + "hKey\r\n" + "$1\r\n" + "1\r\n" + "$2\r\n" + "NX\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n" + + "$7\r\n" + "hField2\r\n" + "$7\r\n" + "hField3\r\n"); + } + + @Test + void shouldCorrectlyConstructHexpiretime() { + + Command<String, String, ?> command = sut.hexpiretime(MY_KEY, MY_FIELD1, MY_FIELD2, MY_FIELD3); + ByteBuf buf = Unpooled.directBuffer(); + command.encode(buf); + + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*6\r\n" + "$11\r\n" + "HEXPIRETIME\r\n" + "$4\r\n" + + "hKey\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n" + "$7\r\n" + "hField2\r\n" + "$7\r\n" + + "hField3\r\n"); + } + + @Test + void shouldCorrectlyConstructHpersist() { + + Command<String, String, ?> command = sut.hpersist(MY_KEY, MY_FIELD1, MY_FIELD2, MY_FIELD3); ByteBuf buf = Unpooled.directBuffer(); command.encode(buf); - assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*6\r\n" + "$7\r\n" + "HEXPIRE\r\n" + "$4\r\n" + "hKey\r\n" - + "$1\r\n" + "1\r\n" + "$2\r\n" + "NX\r\n" + "$1\r\n" + "1\r\n" + "$6\r\n" + "hField\r\n"); + assertThat(buf.toString(StandardCharsets.UTF_8)).isEqualTo("*6\r\n" + "$8\r\n" + "HPERSIST\r\n" + "$4\r\n" + + "hKey\r\n" + "$1\r\n" + "3\r\n" + "$7\r\n" + "hField1\r\n" + "$7\r\n" + "hField2\r\n" + "$7\r\n" + + "hField3\r\n"); } } diff --git a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java index e346b29128..0ae5c8e820 100644 --- a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java @@ -19,24 +19,9 @@ */ package io.lettuce.core.commands; -import static org.assertj.core.api.Assertions.*; - -import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.inject.Inject; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.extension.ExtendWith; - -import io.lettuce.core.KeyValue; +import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanCursor; +import io.lettuce.core.KeyValue; import io.lettuce.core.MapScanCursor; import io.lettuce.core.ScanArgs; import io.lettuce.core.ScanCursor; @@ -47,6 +32,25 @@ import io.lettuce.test.LettuceExtension; import io.lettuce.test.ListStreamingAdapter; import io.lettuce.test.condition.EnabledOnCommand; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; + +import javax.inject.Inject; +import java.time.Duration; +import java.time.Instant; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.offset; +import static org.awaitility.Awaitility.await; /** * Integration tests for {@link io.lettuce.core.api.sync.RedisHashCommands}. @@ -58,6 +62,9 @@ @ExtendWith(LettuceExtension.class) @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class HashCommandIntegrationTests extends TestSupport { + public static final String MY_KEY = "hKey"; + public static final String MY_FIELD = "hField"; + public static final String MY_VALUE = "hValue"; private final RedisCommands<String, String> redis; @@ -541,6 +548,82 @@ void hscanNoValuesMatch() { assertThat(cursor.getKeys()).hasSize(11); } + @Test + @EnabledOnCommand("HEXPIRE") + void hexpire() { + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); + // the below settings are required until the solution is able to support listpack entries + // see TODOs in https://github.com/redis/redis/pull/13172 for more details + assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + + assertThat(redis.hexpire(MY_KEY, 1, MY_FIELD)).isTrue(); + + await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); + } + + @Test + @EnabledOnCommand("HEXPIRE") + void hexpireExpireArgs() { + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); + // the below settings are required until the solution is able to support listpack entries + // see TODOs in https://github.com/redis/redis/pull/13172 for more details + assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.nx(), MY_FIELD)).isTrue(); + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.xx(), MY_FIELD)).isTrue(); + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(10), ExpireArgs.Builder.gt(), MY_FIELD)).isTrue(); + assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.lt(), MY_FIELD)).isTrue(); + + await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); + } + + @Test + @EnabledOnCommand("HEXPIREAT") + void hexpireat() { + // the below settings are required until the solution is able to support listpack entries + // see TODOs in https://github.com/redis/redis/pull/13172 for more details + assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); + + assertThat(redis.hexpireat(MY_KEY,Instant.now().plusSeconds(1) , MY_FIELD)).isTrue(); + + await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); + } + + @Test + @EnabledOnCommand("HEXPIRETIME") + void hexpiretime() { + Date expiration = new Date(System.currentTimeMillis() + 10000); + // the below settings are required until the solution is able to support listpack entries + // see TODOs in https://github.com/redis/redis/pull/13172 for more details + assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); + assertThat(redis.hexpireat(MY_KEY, expiration, MY_FIELD)).isTrue(); + + assertThat(redis.hexpiretime(MY_KEY, MY_FIELD)).isEqualTo(expiration.getTime() / 1000); + } + + @Test + @EnabledOnCommand("HPERSIST") + void persist() { + // the below settings are required until the solution is able to support listpack entries + // see TODOs in https://github.com/redis/redis/pull/13172 for more details + assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + + assertThat(redis.hpersist(MY_KEY, MY_FIELD)).isFalse(); + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); + assertThat(redis.hpersist(MY_KEY, MY_FIELD)).isFalse(); + assertThat(redis.hexpire(MY_KEY, 1, MY_FIELD)).isTrue(); + assertThat(redis.hpersist(MY_KEY, MY_FIELD)).isTrue(); + } + void setup100KeyValues(Map<String, String> expect) { for (int i = 0; i < 100; i++) { expect.put(key + i, value + 1); diff --git a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java index 6a67e9706e..2188595fc1 100644 --- a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java @@ -19,20 +19,6 @@ */ package io.lettuce.core.commands; -import static org.assertj.core.api.Assertions.*; -import static org.awaitility.Awaitility.await; - -import java.time.Duration; -import java.time.Instant; -import java.util.*; - -import javax.inject.Inject; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.extension.ExtendWith; - import io.lettuce.core.CopyArgs; import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanArgs; @@ -46,6 +32,23 @@ import io.lettuce.test.LettuceExtension; import io.lettuce.test.ListStreamingAdapter; import io.lettuce.test.condition.EnabledOnCommand; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; + +import javax.inject.Inject; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Integration tests for {@link io.lettuce.core.api.sync.RedisKeyCommands}. @@ -58,12 +61,6 @@ @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class KeyCommandIntegrationTests extends TestSupport { - public static final String MY_KEY = "hKey"; - - public static final String MY_FIELD = "hField"; - - public static final String MY_VALUE = "hValue"; - private final RedisCommands<String, String> redis; @Inject @@ -194,49 +191,6 @@ void expiretime() { assertThat(redis.expiretime(key)).isEqualTo(expiration.getTime() / 1000); } - @Test - @EnabledOnCommand("HEXPIRE") - void hexpire() { - assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); - // the below settings are required until the solution is able to support listpack entries - // see TODOs in https://github.com/redis/redis/pull/13172 for more details - assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); - assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); - - assertThat(redis.hexpire(MY_KEY, 1, Collections.singletonList(MY_FIELD))).isTrue(); - - await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); - } - - @Test - @EnabledOnCommand("HEXPIRE") - void hexpireExpireArgs() { - assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); - // the below settings are required until the solution is able to support listpack entries - // see TODOs in https://github.com/redis/redis/pull/13172 for more details - assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); - assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); - - assertThat(redis.hexpire(MY_KEY, - Duration.ofSeconds(1), - ExpireArgs.Builder.nx(), - Collections.singletonList(MY_FIELD))).isTrue(); - assertThat(redis.hexpire(MY_KEY, - Duration.ofSeconds(1), - ExpireArgs.Builder.xx(), - Collections.singletonList(MY_FIELD))).isTrue(); - assertThat(redis.hexpire(MY_KEY, - Duration.ofSeconds(10), - ExpireArgs.Builder.gt(), - Collections.singletonList(MY_FIELD))).isTrue(); - assertThat(redis.hexpire(MY_KEY, - Duration.ofSeconds(1), - ExpireArgs.Builder.lt(), - Collections.singletonList(MY_FIELD))).isTrue(); - - await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); - } - @Test void keys() { assertThat(redis.keys("*")).isEqualTo(list()); From e42c7ba3923bb46455369a36347f2a473a31b874 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev <tihomir.mateev@gmail.com> Date: Thu, 25 Apr 2024 10:11:54 +0300 Subject: [PATCH 4/7] Make sure we reset the configuration setting after the new hash commands were tested --- .../core/commands/HashCommandIntegrationTests.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java index 0ae5c8e820..6c1fae02e7 100644 --- a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java @@ -32,6 +32,7 @@ import io.lettuce.test.LettuceExtension; import io.lettuce.test.ListStreamingAdapter; import io.lettuce.test.condition.EnabledOnCommand; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; @@ -78,6 +79,13 @@ void setUp() { this.redis.flushall(); } + @AfterEach + void tearDown() { + // resets the configuration settings to default, would not be needed once listpack is supported + assertThat(redis.configSet("hash-max-listpack-entries","128")).isEqualTo("OK"); + assertThat(redis.configSet("set-max-listpack-value","64")).isEqualTo("OK"); + } + @Test void hdel() { assertThat(redis.hdel(key, "one")).isEqualTo(0); @@ -551,12 +559,12 @@ void hscanNoValuesMatch() { @Test @EnabledOnCommand("HEXPIRE") void hexpire() { - assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); // the below settings are required until the solution is able to support listpack entries // see TODOs in https://github.com/redis/redis/pull/13172 for more details assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); assertThat(redis.hexpire(MY_KEY, 1, MY_FIELD)).isTrue(); await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); @@ -565,12 +573,12 @@ void hexpire() { @Test @EnabledOnCommand("HEXPIRE") void hexpireExpireArgs() { - assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); // the below settings are required until the solution is able to support listpack entries // see TODOs in https://github.com/redis/redis/pull/13172 for more details assertThat(redis.configSet("hash-max-listpack-entries","0")).isEqualTo("OK"); assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); + assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.nx(), MY_FIELD)).isTrue(); assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(1), ExpireArgs.Builder.xx(), MY_FIELD)).isTrue(); assertThat(redis.hexpire(MY_KEY, Duration.ofSeconds(10), ExpireArgs.Builder.gt(), MY_FIELD)).isTrue(); @@ -588,7 +596,6 @@ void hexpireat() { assertThat(redis.configSet("set-max-listpack-value","0")).isEqualTo("OK"); assertThat(redis.hset(MY_KEY, MY_FIELD, MY_VALUE)).isTrue(); - assertThat(redis.hexpireat(MY_KEY,Instant.now().plusSeconds(1) , MY_FIELD)).isTrue(); await().until(() -> redis.hget(MY_KEY, MY_FIELD) == null); From d9e940fb223f0c91e6996fe52247910d78cb2c89 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev <tihomir.mateev@gmail.com> Date: Thu, 25 Apr 2024 14:54:19 +0300 Subject: [PATCH 5/7] Broke one test because of wrong configuration setting; the other is unstable, trying to fix it --- .../core/RedisClientIntegrationTests.java | 27 ++++++++++--------- .../commands/HashCommandIntegrationTests.java | 2 +- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java b/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java index 2b78d3f99c..57eb8d2bbc 100644 --- a/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java +++ b/src/test/java/io/lettuce/core/RedisClientIntegrationTests.java @@ -1,17 +1,5 @@ package io.lettuce.core; -import static org.assertj.core.api.Assertions.*; - -import java.lang.reflect.Field; -import java.net.SocketAddress; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -import org.junit.jupiter.api.Test; - import io.lettuce.core.api.StatefulRedisConnection; import io.lettuce.core.event.command.CommandFailedEvent; import io.lettuce.core.event.command.CommandListener; @@ -27,6 +15,17 @@ import io.lettuce.test.resource.TestClientResources; import io.lettuce.test.settings.TestSettings; import io.netty.util.concurrent.EventExecutorGroup; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Field; +import java.net.SocketAddress; +import java.time.Duration; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import static org.assertj.core.api.Assertions.assertThat; /** * Integration tests for {@link RedisClient}. @@ -138,7 +137,9 @@ void shouldPropagateCommandTimeoutToCommandListener() throws InterruptedExceptio assertThat(commandListener.started).hasSize(1); assertThat(commandListener.succeeded).isEmpty(); - assertThat(commandListener.failed).hasSize(1).extracting(it -> it.getCommand().getType()).contains(CommandType.BLPOP); + + Wait.untilTrue(() -> commandListener.failed.size() == 1); + assertThat(commandListener.failed).extracting(it -> it.getCommand().getType()).contains(CommandType.BLPOP); FastShutdown.shutdown(client); } diff --git a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java index 6c1fae02e7..b87102505d 100644 --- a/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/HashCommandIntegrationTests.java @@ -82,7 +82,7 @@ void setUp() { @AfterEach void tearDown() { // resets the configuration settings to default, would not be needed once listpack is supported - assertThat(redis.configSet("hash-max-listpack-entries","128")).isEqualTo("OK"); + assertThat(redis.configSet("hash-max-listpack-entries","512")).isEqualTo("OK"); assertThat(redis.configSet("set-max-listpack-value","64")).isEqualTo("OK"); } From cc380e188b2687e89de4cea27fa8e574274e3da9 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev <tihomir.mateev@gmail.com> Date: Thu, 25 Apr 2024 15:48:52 +0300 Subject: [PATCH 6/7] Polishing imports --- .../core/AbstractRedisAsyncCommands.java | 14 +- .../core/AbstractRedisReactiveCommands.java | 14 +- .../io/lettuce/core/RedisCommandBuilder.java | 157 +----------------- .../core/api/async/RedisKeyAsyncCommands.java | 18 +- .../api/sync/NodeSelectionKeyCommands.java | 10 +- .../coroutines/RedisKeyCoroutinesCommands.kt | 12 +- .../commands/KeyCommandIntegrationTests.java | 35 ++-- 7 files changed, 35 insertions(+), 225 deletions(-) diff --git a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java index 10331085fb..8b09c6b2e2 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java @@ -21,19 +21,7 @@ import io.lettuce.core.GeoArgs.Unit; import io.lettuce.core.api.StatefulConnection; -import io.lettuce.core.api.async.BaseRedisAsyncCommands; -import io.lettuce.core.api.async.RedisAclAsyncCommands; -import io.lettuce.core.api.async.RedisGeoAsyncCommands; -import io.lettuce.core.api.async.RedisHLLAsyncCommands; -import io.lettuce.core.api.async.RedisHashAsyncCommands; -import io.lettuce.core.api.async.RedisKeyAsyncCommands; -import io.lettuce.core.api.async.RedisListAsyncCommands; -import io.lettuce.core.api.async.RedisScriptingAsyncCommands; -import io.lettuce.core.api.async.RedisServerAsyncCommands; -import io.lettuce.core.api.async.RedisSetAsyncCommands; -import io.lettuce.core.api.async.RedisSortedSetAsyncCommands; -import io.lettuce.core.api.async.RedisStringAsyncCommands; -import io.lettuce.core.api.async.RedisTransactionalAsyncCommands; +import io.lettuce.core.api.async.*; import io.lettuce.core.cluster.api.async.RedisClusterAsyncCommands; import io.lettuce.core.codec.Base16; import io.lettuce.core.codec.RedisCodec; diff --git a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java index 42efa41acf..47006ac03d 100644 --- a/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java +++ b/src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java @@ -21,19 +21,7 @@ import io.lettuce.core.GeoArgs.Unit; import io.lettuce.core.api.StatefulConnection; -import io.lettuce.core.api.reactive.BaseRedisReactiveCommands; -import io.lettuce.core.api.reactive.RedisAclReactiveCommands; -import io.lettuce.core.api.reactive.RedisGeoReactiveCommands; -import io.lettuce.core.api.reactive.RedisHLLReactiveCommands; -import io.lettuce.core.api.reactive.RedisHashReactiveCommands; -import io.lettuce.core.api.reactive.RedisKeyReactiveCommands; -import io.lettuce.core.api.reactive.RedisListReactiveCommands; -import io.lettuce.core.api.reactive.RedisScriptingReactiveCommands; -import io.lettuce.core.api.reactive.RedisServerReactiveCommands; -import io.lettuce.core.api.reactive.RedisSetReactiveCommands; -import io.lettuce.core.api.reactive.RedisSortedSetReactiveCommands; -import io.lettuce.core.api.reactive.RedisStringReactiveCommands; -import io.lettuce.core.api.reactive.RedisTransactionalReactiveCommands; +import io.lettuce.core.api.reactive.*; import io.lettuce.core.cluster.api.reactive.RedisClusterReactiveCommands; import io.lettuce.core.codec.Base16; import io.lettuce.core.codec.RedisCodec; diff --git a/src/main/java/io/lettuce/core/RedisCommandBuilder.java b/src/main/java/io/lettuce/core/RedisCommandBuilder.java index 48b68fe1df..143fc6cd89 100644 --- a/src/main/java/io/lettuce/core/RedisCommandBuilder.java +++ b/src/main/java/io/lettuce/core/RedisCommandBuilder.java @@ -27,64 +27,7 @@ import io.lettuce.core.models.stream.ClaimedMessages; import io.lettuce.core.models.stream.PendingMessage; import io.lettuce.core.models.stream.PendingMessages; -import io.lettuce.core.output.ArrayOutput; -import io.lettuce.core.output.BooleanListOutput; -import io.lettuce.core.output.BooleanOutput; -import io.lettuce.core.output.ByteArrayOutput; -import io.lettuce.core.output.ClaimedMessagesOutput; -import io.lettuce.core.output.CommandOutput; -import io.lettuce.core.output.DateOutput; -import io.lettuce.core.output.DoubleListOutput; -import io.lettuce.core.output.DoubleOutput; -import io.lettuce.core.output.EnumSetOutput; -import io.lettuce.core.output.GenericMapOutput; -import io.lettuce.core.output.GeoCoordinatesListOutput; -import io.lettuce.core.output.GeoCoordinatesValueListOutput; -import io.lettuce.core.output.GeoWithinListOutput; -import io.lettuce.core.output.IntegerListOutput; -import io.lettuce.core.output.IntegerOutput; -import io.lettuce.core.output.KeyListOutput; -import io.lettuce.core.output.KeyOutput; -import io.lettuce.core.output.KeyScanOutput; -import io.lettuce.core.output.KeyScanStreamingOutput; -import io.lettuce.core.output.KeyStreamingChannel; -import io.lettuce.core.output.KeyStreamingOutput; -import io.lettuce.core.output.KeyValueListOutput; -import io.lettuce.core.output.KeyValueListScoredValueOutput; -import io.lettuce.core.output.KeyValueOfScoredValueOutput; -import io.lettuce.core.output.KeyValueOutput; -import io.lettuce.core.output.KeyValueScanStreamingOutput; -import io.lettuce.core.output.KeyValueScoredValueOutput; -import io.lettuce.core.output.KeyValueStreamingChannel; -import io.lettuce.core.output.KeyValueStreamingOutput; -import io.lettuce.core.output.KeyValueValueListOutput; -import io.lettuce.core.output.ListOfGenericMapsOutput; -import io.lettuce.core.output.MapOutput; -import io.lettuce.core.output.MapScanOutput; -import io.lettuce.core.output.NestedMultiOutput; -import io.lettuce.core.output.ObjectOutput; -import io.lettuce.core.output.PendingMessageListOutput; -import io.lettuce.core.output.PendingMessagesOutput; -import io.lettuce.core.output.ScoredValueListOutput; -import io.lettuce.core.output.ScoredValueOutput; -import io.lettuce.core.output.ScoredValueScanOutput; -import io.lettuce.core.output.ScoredValueScanStreamingOutput; -import io.lettuce.core.output.ScoredValueStreamingChannel; -import io.lettuce.core.output.ScoredValueStreamingOutput; -import io.lettuce.core.output.StatusOutput; -import io.lettuce.core.output.StreamMessageListOutput; -import io.lettuce.core.output.StreamReadOutput; -import io.lettuce.core.output.StringListOutput; -import io.lettuce.core.output.StringMatchResultOutput; -import io.lettuce.core.output.StringValueListOutput; -import io.lettuce.core.output.ValueListOutput; -import io.lettuce.core.output.ValueOutput; -import io.lettuce.core.output.ValueScanOutput; -import io.lettuce.core.output.ValueScanStreamingOutput; -import io.lettuce.core.output.ValueSetOutput; -import io.lettuce.core.output.ValueStreamingChannel; -import io.lettuce.core.output.ValueStreamingOutput; -import io.lettuce.core.output.ValueValueListOutput; +import io.lettuce.core.output.*; import io.lettuce.core.protocol.BaseRedisCommandBuilder; import io.lettuce.core.protocol.Command; import io.lettuce.core.protocol.CommandArgs; @@ -100,102 +43,10 @@ import java.util.Set; import static io.lettuce.core.internal.LettuceStrings.string; -import static io.lettuce.core.protocol.CommandKeyword.ADDSLOTS; -import static io.lettuce.core.protocol.CommandKeyword.ADDSLOTSRANGE; -import static io.lettuce.core.protocol.CommandKeyword.AFTER; -import static io.lettuce.core.protocol.CommandKeyword.AND; -import static io.lettuce.core.protocol.CommandKeyword.BEFORE; -import static io.lettuce.core.protocol.CommandKeyword.BUMPEPOCH; -import static io.lettuce.core.protocol.CommandKeyword.BYLEX; -import static io.lettuce.core.protocol.CommandKeyword.BYSCORE; -import static io.lettuce.core.protocol.CommandKeyword.CACHING; -import static io.lettuce.core.protocol.CommandKeyword.CAT; -import static io.lettuce.core.protocol.CommandKeyword.CHANNELS; -import static io.lettuce.core.protocol.CommandKeyword.CONSUMERS; -import static io.lettuce.core.protocol.CommandKeyword.COUNT; -import static io.lettuce.core.protocol.CommandKeyword.COUNTKEYSINSLOT; -import static io.lettuce.core.protocol.CommandKeyword.CREATE; -import static io.lettuce.core.protocol.CommandKeyword.DELSLOTS; -import static io.lettuce.core.protocol.CommandKeyword.DELSLOTSRANGE; -import static io.lettuce.core.protocol.CommandKeyword.DELUSER; -import static io.lettuce.core.protocol.CommandKeyword.DRYRUN; -import static io.lettuce.core.protocol.CommandKeyword.ENCODING; -import static io.lettuce.core.protocol.CommandKeyword.FAILOVER; -import static io.lettuce.core.protocol.CommandKeyword.FLUSH; -import static io.lettuce.core.protocol.CommandKeyword.FLUSHSLOTS; -import static io.lettuce.core.protocol.CommandKeyword.FORCE; -import static io.lettuce.core.protocol.CommandKeyword.FORGET; -import static io.lettuce.core.protocol.CommandKeyword.FREQ; -import static io.lettuce.core.protocol.CommandKeyword.GENPASS; -import static io.lettuce.core.protocol.CommandKeyword.GETKEYSINSLOT; -import static io.lettuce.core.protocol.CommandKeyword.GETNAME; -import static io.lettuce.core.protocol.CommandKeyword.GETREDIR; -import static io.lettuce.core.protocol.CommandKeyword.GETUSER; -import static io.lettuce.core.protocol.CommandKeyword.GROUPS; -import static io.lettuce.core.protocol.CommandKeyword.HARD; -import static io.lettuce.core.protocol.CommandKeyword.HTSTATS; -import static io.lettuce.core.protocol.CommandKeyword.ID; -import static io.lettuce.core.protocol.CommandKeyword.IDLETIME; -import static io.lettuce.core.protocol.CommandKeyword.IMPORTING; -import static io.lettuce.core.protocol.CommandKeyword.KEYSLOT; -import static io.lettuce.core.protocol.CommandKeyword.KILL; -import static io.lettuce.core.protocol.CommandKeyword.LEN; -import static io.lettuce.core.protocol.CommandKeyword.LIMIT; -import static io.lettuce.core.protocol.CommandKeyword.LIST; -import static io.lettuce.core.protocol.CommandKeyword.LOAD; -import static io.lettuce.core.protocol.CommandKeyword.LOG; -import static io.lettuce.core.protocol.CommandKeyword.MAXLEN; -import static io.lettuce.core.protocol.CommandKeyword.MEET; -import static io.lettuce.core.protocol.CommandKeyword.MIGRATING; -import static io.lettuce.core.protocol.CommandKeyword.NO; -import static io.lettuce.core.protocol.CommandKeyword.NODE; -import static io.lettuce.core.protocol.CommandKeyword.NODES; -import static io.lettuce.core.protocol.CommandKeyword.NOSAVE; -import static io.lettuce.core.protocol.CommandKeyword.NOT; -import static io.lettuce.core.protocol.CommandKeyword.NOVALUES; -import static io.lettuce.core.protocol.CommandKeyword.NUMPAT; -import static io.lettuce.core.protocol.CommandKeyword.NUMSUB; -import static io.lettuce.core.protocol.CommandKeyword.OFF; -import static io.lettuce.core.protocol.CommandKeyword.ON; -import static io.lettuce.core.protocol.CommandKeyword.ONE; -import static io.lettuce.core.protocol.CommandKeyword.OR; -import static io.lettuce.core.protocol.CommandKeyword.PAUSE; -import static io.lettuce.core.protocol.CommandKeyword.REFCOUNT; -import static io.lettuce.core.protocol.CommandKeyword.RELOAD; -import static io.lettuce.core.protocol.CommandKeyword.REPLACE; -import static io.lettuce.core.protocol.CommandKeyword.REPLICAS; -import static io.lettuce.core.protocol.CommandKeyword.REPLICATE; -import static io.lettuce.core.protocol.CommandKeyword.RESET; -import static io.lettuce.core.protocol.CommandKeyword.RESETSTAT; -import static io.lettuce.core.protocol.CommandKeyword.RESTART; -import static io.lettuce.core.protocol.CommandKeyword.REV; -import static io.lettuce.core.protocol.CommandKeyword.REWRITE; -import static io.lettuce.core.protocol.CommandKeyword.SAVECONFIG; -import static io.lettuce.core.protocol.CommandKeyword.SEGFAULT; -import static io.lettuce.core.protocol.CommandKeyword.SETINFO; -import static io.lettuce.core.protocol.CommandKeyword.SETNAME; -import static io.lettuce.core.protocol.CommandKeyword.SETSLOT; -import static io.lettuce.core.protocol.CommandKeyword.SETUSER; -import static io.lettuce.core.protocol.CommandKeyword.SHARDCHANNELS; -import static io.lettuce.core.protocol.CommandKeyword.SHARDNUMSUB; -import static io.lettuce.core.protocol.CommandKeyword.SHARDS; -import static io.lettuce.core.protocol.CommandKeyword.SLAVES; -import static io.lettuce.core.protocol.CommandKeyword.SLOTS; -import static io.lettuce.core.protocol.CommandKeyword.SOFT; -import static io.lettuce.core.protocol.CommandKeyword.STABLE; -import static io.lettuce.core.protocol.CommandKeyword.STREAM; -import static io.lettuce.core.protocol.CommandKeyword.TAKEOVER; -import static io.lettuce.core.protocol.CommandKeyword.TRACKING; -import static io.lettuce.core.protocol.CommandKeyword.UNBLOCK; -import static io.lettuce.core.protocol.CommandKeyword.USAGE; -import static io.lettuce.core.protocol.CommandKeyword.USERS; -import static io.lettuce.core.protocol.CommandKeyword.WHOAMI; -import static io.lettuce.core.protocol.CommandKeyword.WITHSCORE; -import static io.lettuce.core.protocol.CommandKeyword.WITHSCORES; -import static io.lettuce.core.protocol.CommandKeyword.WITHVALUES; -import static io.lettuce.core.protocol.CommandKeyword.XOR; -import static io.lettuce.core.protocol.CommandKeyword.YES; +import static io.lettuce.core.protocol.CommandKeyword.*; import static io.lettuce.core.protocol.CommandType.*; +import static io.lettuce.core.protocol.CommandType.COPY; +import static io.lettuce.core.protocol.CommandType.SAVE; /** * @param <K> 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 b5253b4e9d..cceffb8a71 100644 --- a/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java +++ b/src/main/java/io/lettuce/core/api/async/RedisKeyAsyncCommands.java @@ -19,25 +19,15 @@ */ package io.lettuce.core.api.async; -import io.lettuce.core.CopyArgs; -import io.lettuce.core.ExpireArgs; -import io.lettuce.core.KeyScanArgs; -import io.lettuce.core.KeyScanCursor; -import io.lettuce.core.MigrateArgs; -import io.lettuce.core.RedisFuture; -import io.lettuce.core.RestoreArgs; -import io.lettuce.core.ScanArgs; -import io.lettuce.core.ScanCursor; -import io.lettuce.core.SortArgs; -import io.lettuce.core.StreamScanCursor; -import io.lettuce.core.output.KeyStreamingChannel; -import io.lettuce.core.output.ValueStreamingChannel; - import java.time.Duration; import java.time.Instant; import java.util.Date; import java.util.List; +import io.lettuce.core.*; +import io.lettuce.core.output.KeyStreamingChannel; +import io.lettuce.core.output.ValueStreamingChannel; + /** * Asynchronous executed commands for Keys (Key manipulation/querying). * 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 398fcf1f65..d09dd4f39a 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 @@ -19,6 +19,11 @@ */ package io.lettuce.core.cluster.api.sync; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.List; + import io.lettuce.core.CopyArgs; import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanArgs; @@ -32,11 +37,6 @@ import io.lettuce.core.output.KeyStreamingChannel; import io.lettuce.core.output.ValueStreamingChannel; -import java.time.Duration; -import java.time.Instant; -import java.util.Date; -import java.util.List; - /** * Synchronous executed commands on a node selection for Keys (Key manipulation/querying). * 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 72aa35c614..87c92abb2e 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt @@ -20,19 +20,11 @@ package io.lettuce.core.api.coroutines -import io.lettuce.core.CopyArgs -import io.lettuce.core.ExperimentalLettuceCoroutinesApi -import io.lettuce.core.ExpireArgs -import io.lettuce.core.KeyScanCursor -import io.lettuce.core.MigrateArgs -import io.lettuce.core.RestoreArgs -import io.lettuce.core.ScanArgs -import io.lettuce.core.ScanCursor -import io.lettuce.core.SortArgs +import io.lettuce.core.* import kotlinx.coroutines.flow.Flow import java.time.Duration import java.time.Instant -import java.util.Date +import java.util.* /** * Coroutine executed commands for Keys (Key manipulation/querying). diff --git a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java index 2188595fc1..45d7e3840d 100644 --- a/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java +++ b/src/test/java/io/lettuce/core/commands/KeyCommandIntegrationTests.java @@ -19,6 +19,24 @@ */ package io.lettuce.core.commands; +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; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.inject.Inject; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.extension.ExtendWith; + import io.lettuce.core.CopyArgs; import io.lettuce.core.ExpireArgs; import io.lettuce.core.KeyScanArgs; @@ -32,23 +50,6 @@ import io.lettuce.test.LettuceExtension; import io.lettuce.test.ListStreamingAdapter; import io.lettuce.test.condition.EnabledOnCommand; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.extension.ExtendWith; - -import javax.inject.Inject; -import java.time.Duration; -import java.time.Instant; -import java.util.Date; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; /** * Integration tests for {@link io.lettuce.core.api.sync.RedisKeyCommands}. From 667afc169ccc2cae262029ee060c8e17f240a511 Mon Sep 17 00:00:00 2001 From: Tihomir Mateev <tihomir.mateev@gmail.com> Date: Thu, 25 Apr 2024 15:51:36 +0300 Subject: [PATCH 7/7] Polishin : Copyright change not needed --- .../lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 87c92abb2e..6d3f92bcad 100644 --- a/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt +++ b/src/main/kotlin/io/lettuce/core/api/coroutines/RedisKeyCoroutinesCommands.kt @@ -1,5 +1,5 @@ /* - * Copyright 2017-Present, Redis Ltd. and Contributors + * Copyright 2020-Present, Redis Ltd. and Contributors * All rights reserved. * * Licensed under the MIT License.