From 4c4c96e9cf62577544c949a681a0b9ca22ab1016 Mon Sep 17 00:00:00 2001 From: Christoph Strobl Date: Wed, 30 Jun 2021 11:11:36 +0200 Subject: [PATCH] Support HRANDFIELD command via RedisMap. Add randomKey() and randomEntry() to RedisHash. Update documentation and align methods with java terminology around keys vs. fields in hashes. Move Converters off their custom Map.Entry implementation and use SimpleImmutableEntry instead. Switch code that creates Map.Entry to the newly introduced Converters.entryOf method. See: #2048 Original Pull Request: #2104 --- .../DefaultStringRedisConnection.java | 18 +-------- .../redis/connection/convert/Converters.java | 39 +----------------- .../data/redis/core/BoundHashOperations.java | 30 +++++++------- .../core/DefaultBoundHashOperations.java | 16 ++++---- .../redis/core/DefaultHashOperations.java | 27 +++---------- .../core/DefaultReactiveHashOperations.java | 12 +++--- .../core/DefaultReactiveStreamOperations.java | 6 +-- .../data/redis/core/HashOperations.java | 20 +++++----- .../redis/core/ReactiveHashOperations.java | 24 +++++------ .../support/collections/DefaultRedisMap.java | 18 +++++++++ .../redis/support/collections/RedisMap.java | 35 ++++++++++++++++ .../support/collections/RedisProperties.java | 18 +++++++++ ...DefaultHashOperationsIntegrationTests.java | 8 ++-- ...eactiveHashOperationsIntegrationTests.java | 18 ++++----- .../AbstractRedisMapIntegrationTests.java | 40 ++++++++++++++++++- 15 files changed, 185 insertions(+), 144 deletions(-) diff --git a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java index 89962ad55..40dffba45 100644 --- a/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java +++ b/src/main/java/org/springframework/data/redis/connection/DefaultStringRedisConnection.java @@ -108,23 +108,7 @@ public class DefaultStringRedisConnection implements StringRedisConnection, Deco private boolean deserializePipelineAndTxResults = false; private Entry convertEntry(Entry source) { - return new Entry() { - - @Override - public String getKey() { - return bytesToString.convert(source.getKey()); - } - - @Override - public String getValue() { - return bytesToString.convert(source.getValue()); - } - - @Override - public String setValue(String value) { - throw new UnsupportedOperationException("Cannot set value for entry"); - } - }; + return Converters.entryOf(bytesToString.convert(source.getKey()), bytesToString.convert(source.getValue())); } private class DeserializingConverter implements Converter { diff --git a/src/main/java/org/springframework/data/redis/connection/convert/Converters.java b/src/main/java/org/springframework/data/redis/connection/convert/Converters.java index 80fc7dbe1..604fcbc49 100644 --- a/src/main/java/org/springframework/data/redis/connection/convert/Converters.java +++ b/src/main/java/org/springframework/data/redis/connection/convert/Converters.java @@ -18,16 +18,7 @@ package org.springframework.data.redis.connection.convert; import java.io.StringReader; import java.nio.ByteBuffer; import java.time.Duration; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import org.apache.commons.logging.Log; @@ -472,7 +463,7 @@ abstract public class Converters { * @since 2.6 */ public static Map.Entry entryOf(K key, V value) { - return new SimpleEntry<>(key, value); + return new AbstractMap.SimpleImmutableEntry<>(key, value); } /** @@ -653,30 +644,4 @@ abstract public class Converters { } } - - private static class SimpleEntry implements Map.Entry { - - private final K key; - private final V value; - - public SimpleEntry(K key, V value) { - this.key = key; - this.value = value; - } - - @Override - public K getKey() { - return key; - } - - @Override - public V getValue() { - return value; - } - - @Override - public V setValue(V value) { - throw new UnsupportedOperationException(); - } - } } diff --git a/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java b/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java index 47ce81ca5..7f29d359d 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundHashOperations.java @@ -89,49 +89,49 @@ public interface BoundHashOperations extends BoundKeyOperations { Double increment(HK key, double delta); /** - * Return a random field from the hash value stored at the bound key. + * Return a random key (aka field) from the hash value stored at the bound key. * - * @return {@literal null} if key does not exist or when used in pipeline / transaction. + * @return {@literal null} if the hash does not exist or when used in pipeline / transaction. * @since 2.6 * @see Redis Documentation: HRANDFIELD */ @Nullable - HK randomField(); + HK randomKey(); /** - * Return a random field from the hash value stored at the bound key. + * Return a random entry from the hash value stored at the bound key. * * @return {@literal null} if key does not exist or when used in pipeline / transaction. * @since 2.6 * @see Redis Documentation: HRANDFIELD */ @Nullable - Map.Entry randomValue(); + Map.Entry randomEntry(); /** - * Return a random field from the hash value stored at the bound key. If the provided {@code count} argument is - * positive, return a list of distinct fields, capped either at {@code count} or the hash size. If {@code count} is - * negative, the behavior changes and the command is allowed to return the same field multiple times. In this case, - * the number of returned fields is the absolute value of the specified count. + * Return a random keys (aka fields) from the hash value stored at the bound key. If the provided {@code count} argument is + * positive, return a list of distinct keys, capped either at {@code count} or the hash size. If {@code count} is + * negative, the behavior changes and the command is allowed to return the same key multiple times. In this case, + * the number of returned keys is the absolute value of the specified count. * - * @param count number of fields to return. + * @param count number of keys to return. * @return {@literal null} if key does not exist or when used in pipeline / transaction. * @since 2.6 * @see Redis Documentation: HRANDFIELD */ @Nullable - List randomFields(long count); + List randomKeys(long count); /** - * Return a random field from the hash value stored at the bound key. + * Return a random entry from the hash value stored at the bound key. * - * @param count number of fields to return. Must be positive. - * @return {@literal null} if key does not exist or when used in pipeline / transaction. + * @param count number of entries to return. Must be positive. + * @return {@literal null} if the hash does not exist or when used in pipeline / transaction. * @since 2.6 * @see Redis Documentation: HRANDFIELD */ @Nullable - Map randomValues(long count); + Map randomEntries(long count); /** * Get key set (fields) of hash at the bound key. diff --git a/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java index 0493c294e..fcab7066f 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultBoundHashOperations.java @@ -116,8 +116,8 @@ class DefaultBoundHashOperations extends DefaultBoundKeyOperations */ @Nullable @Override - public HK randomField() { - return ops.randomField(getKey()); + public HK randomKey() { + return ops.randomKey(getKey()); } /* @@ -126,8 +126,8 @@ class DefaultBoundHashOperations extends DefaultBoundKeyOperations */ @Nullable @Override - public Entry randomValue() { - return ops.randomValue(getKey()); + public Entry randomEntry() { + return ops.randomEntry(getKey()); } /* @@ -136,8 +136,8 @@ class DefaultBoundHashOperations extends DefaultBoundKeyOperations */ @Nullable @Override - public List randomFields(long count) { - return ops.randomFields(getKey(), count); + public List randomKeys(long count) { + return ops.randomKeys(getKey(), count); } /* @@ -146,8 +146,8 @@ class DefaultBoundHashOperations extends DefaultBoundKeyOperations */ @Nullable @Override - public Map randomValues(long count) { - return ops.randomValues(getKey(), count); + public Map randomEntries(long count) { + return ops.randomEntries(getKey(), count); } /* diff --git a/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java index dc096ffb8..45f493630 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultHashOperations.java @@ -99,7 +99,7 @@ class DefaultHashOperations extends AbstractOperations imp */ @Nullable @Override - public HK randomField(K key) { + public HK randomKey(K key) { byte[] rawKey = rawKey(key); return deserializeHashKey(execute(connection -> connection.hRandField(rawKey), true)); @@ -111,7 +111,7 @@ class DefaultHashOperations extends AbstractOperations imp */ @Nullable @Override - public Entry randomValue(K key) { + public Entry randomEntry(K key) { byte[] rawKey = rawKey(key); Entry rawEntry = execute(connection -> connection.hRandFieldWithValues(rawKey), true); @@ -125,7 +125,7 @@ class DefaultHashOperations extends AbstractOperations imp */ @Nullable @Override - public List randomFields(K key, long count) { + public List randomKeys(K key, long count) { byte[] rawKey = rawKey(key); List rawValues = execute(connection -> connection.hRandField(rawKey, count), true); @@ -138,7 +138,7 @@ class DefaultHashOperations extends AbstractOperations imp */ @Nullable @Override - public Map randomValues(K key, long count) { + public Map randomEntries(K key, long count) { Assert.isTrue(count > 0, "Count must not be negative"); byte[] rawKey = rawKey(key); @@ -324,24 +324,7 @@ class DefaultHashOperations extends AbstractOperations imp @Override public Entry convert(final Entry source) { - - return new Entry() { - - @Override - public HK getKey() { - return deserializeHashKey(source.getKey()); - } - - @Override - public HV getValue() { - return deserializeHashValue(source.getValue()); - } - - @Override - public HV setValue(HV value) { - throw new UnsupportedOperationException("Values cannot be set when scanning through entries."); - } - }; + return Converters.entryOf(deserializeHashKey(source.getKey()), deserializeHashValue(source.getValue())); } })); diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java index a2fa529d5..08b3ba083 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveHashOperations.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.core; +import org.springframework.data.redis.connection.convert.Converters; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -149,7 +150,7 @@ class DefaultReactiveHashOperations implements ReactiveHashOperations * @see org.springframework.data.redis.core.ReactiveHashOperations#randomField(H) */ @Override - public Mono randomField(H key) { + public Mono randomKey(H key) { Assert.notNull(key, "Key must not be null!"); @@ -162,7 +163,7 @@ class DefaultReactiveHashOperations implements ReactiveHashOperations * @see org.springframework.data.redis.core.ReactiveHashOperations#randomValue(H) */ @Override - public Mono> randomValue(H key) { + public Mono> randomEntry(H key) { Assert.notNull(key, "Key must not be null!"); @@ -175,7 +176,7 @@ class DefaultReactiveHashOperations implements ReactiveHashOperations * @see org.springframework.data.redis.core.ReactiveHashOperations#randomFields(H, long) */ @Override - public Flux randomFields(H key, long count) { + public Flux randomKeys(H key, long count) { Assert.notNull(key, "Key must not be null!"); @@ -188,7 +189,7 @@ class DefaultReactiveHashOperations implements ReactiveHashOperations * @see org.springframework.data.redis.core.ReactiveHashOperations#randomValues(H, long) */ @Override - public Flux> randomValues(H key, long count) { + public Flux> randomEntries(H key, long count) { Assert.notNull(key, "Key must not be null!"); @@ -353,8 +354,7 @@ class DefaultReactiveHashOperations implements ReactiveHashOperations } private Map.Entry deserializeHashEntry(Map.Entry source) { - return Collections.singletonMap(readHashKey(source.getKey()), readHashValue(source.getValue())).entrySet() - .iterator().next(); + return Converters.entryOf(readHashKey(source.getKey()), readHashValue(source.getValue())); } private List deserializeHashValues(List source) { diff --git a/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java b/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java index 6a95cec50..0fc811c99 100644 --- a/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java +++ b/src/main/java/org/springframework/data/redis/core/DefaultReactiveStreamOperations.java @@ -15,6 +15,7 @@ */ package org.springframework.data.redis.core; +import org.springframework.data.redis.connection.convert.Converters; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; @@ -422,8 +423,7 @@ class DefaultReactiveStreamOperations implements ReactiveStreamOperat } private Entry deserializeRecordFields(Entry it) { - return Collections.singletonMap(readHashKey(it.getKey()), deserializeHashValue(it.getValue())).entrySet().iterator() - .next(); + return Converters.entryOf(readHashKey(it.getKey()), deserializeHashValue(it.getValue())); } private ByteBufferRecord serializeRecord(MapRecord record) { @@ -432,6 +432,6 @@ class DefaultReactiveStreamOperations implements ReactiveStreamOperat } private Entry serializeRecordFields(Entry it) { - return Collections.singletonMap(rawHashKey(it.getKey()), rawValue(it.getValue())).entrySet().iterator().next(); + return Converters.entryOf(rawHashKey(it.getKey()), rawValue(it.getValue())); } } diff --git a/src/main/java/org/springframework/data/redis/core/HashOperations.java b/src/main/java/org/springframework/data/redis/core/HashOperations.java index 60b763e16..fac681758 100644 --- a/src/main/java/org/springframework/data/redis/core/HashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/HashOperations.java @@ -89,7 +89,7 @@ public interface HashOperations { Double increment(H key, HK hashKey, double delta); /** - * Return a random field from the hash value stored at {@code key}. + * Return a random hash key (aka field) from the hash value stored at {@code key}. * * @param key must not be {@literal null}. * @return {@literal null} if key does not exist or when used in pipeline / transaction. @@ -97,10 +97,10 @@ public interface HashOperations { * @see Redis Documentation: HRANDFIELD */ @Nullable - HK randomField(H key); + HK randomKey(H key); /** - * Return a random field from the hash value stored at {@code key}. + * Return a random entry from the hash value stored at {@code key}. * * @param key must not be {@literal null}. * @return {@literal null} if key does not exist or when used in pipeline / transaction. @@ -108,12 +108,12 @@ public interface HashOperations { * @see Redis Documentation: HRANDFIELD */ @Nullable - Map.Entry randomValue(H key); + Map.Entry randomEntry(H key); /** - * Return a random field from the hash value stored at {@code key}. If the provided {@code count} argument is - * positive, return a list of distinct fields, capped either at {@code count} or the hash size. If {@code count} is - * negative, the behavior changes and the command is allowed to return the same field multiple times. In this case, + * Return random hash keys (aka fields) from the hash value stored at {@code key}. If the provided {@code count} argument is + * positive, return a list of distinct hash keys, capped either at {@code count} or the hash size. If {@code count} is + * negative, the behavior changes and the command is allowed to return the same hash key multiple times. In this case, * the number of returned fields is the absolute value of the specified count. * * @param key must not be {@literal null}. @@ -123,10 +123,10 @@ public interface HashOperations { * @see Redis Documentation: HRANDFIELD */ @Nullable - List randomFields(H key, long count); + List randomKeys(H key, long count); /** - * Return a random field from the hash value stored at {@code key}. + * Return a random entries from the hash value stored at {@code key}. * * @param key must not be {@literal null}. * @param count number of fields to return. Must be positive. @@ -135,7 +135,7 @@ public interface HashOperations { * @see Redis Documentation: HRANDFIELD */ @Nullable - Map randomValues(H key, long count); + Map randomEntries(H key, long count); /** * Get key set (fields) of hash at {@code key}. diff --git a/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java b/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java index 562f6647d..da550099f 100644 --- a/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java +++ b/src/main/java/org/springframework/data/redis/core/ReactiveHashOperations.java @@ -88,29 +88,29 @@ public interface ReactiveHashOperations { Mono increment(H key, HK hashKey, double delta); /** - * Return a random field from the hash value stored at {@code key}. + * Return a random hash key (aka field) from the hash value stored at {@code key}. * * @param key must not be {@literal null}. * @return * @since 2.6 * @see Redis Documentation: HRANDFIELD */ - Mono randomField(H key); + Mono randomKey(H key); /** - * Return a random field from the hash value stored at {@code key}. + * Return a random entry from the hash value stored at {@code key}. * * @param key must not be {@literal null}. * @return * @since 2.6 * @see Redis Documentation: HRANDFIELD */ - Mono> randomValue(H key); + Mono> randomEntry(H key); /** - * Return a random field from the hash value stored at {@code key}. If the provided {@code count} argument is - * positive, return a list of distinct fields, capped either at {@code count} or the hash size. If {@code count} is - * negative, the behavior changes and the command is allowed to return the same field multiple times. In this case, + * Return random hash keys (aka fields) from the hash value stored at {@code key}. If the provided {@code count} argument is + * positive, return a list of distinct hash keys, capped either at {@code count} or the hash size. If {@code count} is + * negative, the behavior changes and the command is allowed to return the same hash key multiple times. In this case, * the number of returned fields is the absolute value of the specified count. * * @param key must not be {@literal null}. @@ -119,12 +119,12 @@ public interface ReactiveHashOperations { * @since 2.6 * @see Redis Documentation: HRANDFIELD */ - Flux randomFields(H key, long count); + Flux randomKeys(H key, long count); /** - * Return a random field from the hash value stored at {@code key}. If the provided {@code count} argument is - * positive, return a list of distinct fields, capped either at {@code count} or the hash size. If {@code count} is - * negative, the behavior changes and the command is allowed to return the same field multiple times. In this case, + * Return random entries from the hash stored at {@code key}. If the provided {@code count} argument is + * positive, return a list of distinct entries, capped either at {@code count} or the hash size. If {@code count} is + * negative, the behavior changes and the command is allowed to return the same entry multiple times. In this case, * the number of returned fields is the absolute value of the specified count. * * @param key must not be {@literal null}. @@ -133,7 +133,7 @@ public interface ReactiveHashOperations { * @since 2.6 * @see Redis Documentation: HRANDFIELD */ - Flux> randomValues(H key, long count); + Flux> randomEntries(H key, long count); /** * Get key set (fields) of hash at {@code key}. diff --git a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java index fbc41c6fb..e32120473 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java +++ b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisMap.java @@ -81,6 +81,24 @@ public class DefaultRedisMap implements RedisMap { return hashOps.increment(key, delta); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisMap#randomKey() + */ + @Override + public K randomKey() { + return hashOps.randomKey(); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisMap#randomEntry() + */ + @Override + public Entry randomEntry() { + return hashOps.randomEntry(); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.support.collections.RedisStore#getOperations() diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisMap.java b/src/main/java/org/springframework/data/redis/support/collections/RedisMap.java index 3fff2aba9..696aea272 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisMap.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisMap.java @@ -19,6 +19,8 @@ import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentMap; +import org.springframework.lang.Nullable; + /** * Map view of a Redis hash. * @@ -27,10 +29,43 @@ import java.util.concurrent.ConcurrentMap; */ public interface RedisMap extends RedisStore, ConcurrentMap { + /** + * Increment {@code value} of the hash {@code key} by the given {@code delta}. + * + * @param key must not be {@literal null}. + * @param delta + * @return {@literal null} if hash does not exist. + * @since 1.0 + */ Long increment(K key, long delta); + /** + * Increment {@code value} of the hash {@code key} by the given {@code delta}. + * + * @param key must not be {@literal null}. + * @param delta + * @return {@literal null} if hash does not exist. + * @since 1.1 + */ Double increment(K key, double delta); + /** + * Get a random key from the hash. + * + * @return {@literal null} if the hash does not exist. + * @since 2.6 + */ + K randomKey(); + + /** + * Get a random entry from the hash. + * + * @return {@literal null} if the hash does not exist. + * @since 2.6 + */ + @Nullable + Map.Entry randomEntry(); + /** * @since 1.4 * @return diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java b/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java index 9dd7fc1c6..04614026b 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisProperties.java @@ -304,6 +304,24 @@ public class RedisProperties extends Properties implements RedisMap randomEntry() { + return (Entry) delegate.randomEntry(); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.support.collections.RedisStore#getOperations() diff --git a/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java index d023f082d..7d6bf4359 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultHashOperationsIntegrationTests.java @@ -173,8 +173,8 @@ public class DefaultHashOperationsIntegrationTests { hashOps.put(key, key1, val1); hashOps.put(key, key2, val2); - assertThat(hashOps.randomField(key)).isIn(key1, key2); - assertThat(hashOps.randomFields(key, 2)).hasSize(2).contains(key1, key2); + assertThat(hashOps.randomKey(key)).isIn(key1, key2); + assertThat(hashOps.randomKeys(key, 2)).hasSize(2).contains(key1, key2); } @ParameterizedRedisTest // GH-2048 @@ -190,7 +190,7 @@ public class DefaultHashOperationsIntegrationTests { hashOps.put(key, key1, val1); hashOps.put(key, key2, val2); - Map.Entry entry = hashOps.randomValue(key); + Map.Entry entry = hashOps.randomEntry(key); if (entry.getKey().equals(key1)) { assertThat(entry.getValue()).isEqualTo(val1); @@ -198,7 +198,7 @@ public class DefaultHashOperationsIntegrationTests { assertThat(entry.getValue()).isEqualTo(val2); } - Map values = hashOps.randomValues(key, 10); + Map values = hashOps.randomEntries(key, 10); assertThat(values).hasSize(2).containsEntry(key1, val1).containsEntry(key2, val2); } } diff --git a/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java b/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java index 171e6ec1e..9c714b422 100644 --- a/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/core/DefaultReactiveHashOperationsIntegrationTests.java @@ -18,11 +18,11 @@ package org.springframework.data.redis.core; import static org.assertj.core.api.Assertions.*; import static org.assertj.core.api.Assumptions.*; +import org.springframework.data.redis.connection.convert.Converters; import reactor.test.StepVerifier; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -251,13 +251,13 @@ public class DefaultReactiveHashOperationsIntegrationTests { .expectNext(true) // .verifyComplete(); - hashOperations.randomField(key) // + hashOperations.randomKey(key) // .as(StepVerifier::create) // .assertNext(actual -> { assertThat(actual).isIn(hashkey1, hashkey2); }).verifyComplete(); - hashOperations.randomFields(key, -10) // + hashOperations.randomKeys(key, -10) // .collectList().as(StepVerifier::create) // .assertNext(actual -> { assertThat(actual).hasSize(10); @@ -286,7 +286,7 @@ public class DefaultReactiveHashOperationsIntegrationTests { .expectNext(true) // .verifyComplete(); - hashOperations.randomValue(key) // + hashOperations.randomEntry(key) // .as(StepVerifier::create) // .assertNext(actual -> { @@ -297,7 +297,7 @@ public class DefaultReactiveHashOperationsIntegrationTests { } }).verifyComplete(); - hashOperations.randomValues(key, -10) // + hashOperations.randomEntries(key, -10) // .collectList().as(StepVerifier::create) // .assertNext(actual -> { assertThat(actual).hasSize(10); @@ -462,8 +462,8 @@ public class DefaultReactiveHashOperationsIntegrationTests { .as(StepVerifier::create) // .consumeNextWith(list -> { - Entry entry1 = Collections.singletonMap(hashkey1, hashvalue1).entrySet().iterator().next(); - Entry entry2 = Collections.singletonMap(hashkey2, hashvalue2).entrySet().iterator().next(); + Entry entry1 = Converters.entryOf(hashkey1, hashvalue1); + Entry entry2 = Converters.entryOf(hashkey2, hashvalue2); assertThat(list).containsExactlyInAnyOrder(entry1, entry2); }) // @@ -489,8 +489,8 @@ public class DefaultReactiveHashOperationsIntegrationTests { .as(StepVerifier::create) // .consumeNextWith(list -> { - Entry entry1 = Collections.singletonMap(hashkey1, hashvalue1).entrySet().iterator().next(); - Entry entry2 = Collections.singletonMap(hashkey2, hashvalue2).entrySet().iterator().next(); + Entry entry1 = Converters.entryOf(hashkey1, hashvalue1); + Entry entry2 = Converters.entryOf(hashkey2, hashvalue2); assertThat(list).containsExactlyInAnyOrder(entry1, entry2); }) // diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java index 4ae49dcc6..dc1472c8b 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisMapIntegrationTests.java @@ -20,6 +20,7 @@ import static org.assertj.core.api.Assumptions.*; import java.io.IOException; import java.text.DecimalFormat; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; @@ -28,17 +29,19 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import org.assertj.core.api.Assumptions; import org.junit.jupiter.api.BeforeEach; - import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.redis.DoubleAsStringObjectFactory; import org.springframework.data.redis.LongAsStringObjectFactory; import org.springframework.data.redis.ObjectFactory; +import org.springframework.data.redis.RawObjectFactory; import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.RedisCallback; import org.springframework.data.redis.core.RedisOperations; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.test.condition.EnabledOnCommand; import org.springframework.data.redis.test.extension.parametrized.MethodSource; import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest; @@ -458,4 +461,39 @@ public abstract class AbstractRedisMapIntegrationTests { } cursor.close(); } + + @ParameterizedRedisTest // GH-2048 + @EnabledOnCommand("HRANDFIELD") + public void randomKeyFromHash() { + + K k1 = getKey(); + K k2 = getKey(); + + V v1 = getValue(); + V v2 = getValue(); + + map.put(k1, v1); + map.put(k2, v2); + + assertThat(map.randomKey()).isIn(k1, k2); + } + + @ParameterizedRedisTest // GH-2048 + @EnabledOnCommand("HRANDFIELD") + public void randomEntryFromHash() { + + Assumptions.assumeThat(this.valueFactory).isNotInstanceOf(RawObjectFactory.class); + + K k1 = getKey(); + K k2 = getKey(); + + V v1 = getValue(); + V v2 = getValue(); + + map.put(k1, v1); + map.put(k2, v2); + + assertThat(map.randomEntry()).isIn(new AbstractMap.SimpleImmutableEntry(k1, v1), + new AbstractMap.SimpleImmutableEntry(k2, v2)); + } }