diff --git a/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java b/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java index 9112dc4a6..df88b3e1e 100644 --- a/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java +++ b/redisson/src/main/java/org/redisson/RedissonScoredSortedSet.java @@ -278,7 +278,7 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc @Override public RFuture addIfExistsAsync(double score, V object) { - return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_BOOL, getRawName(), "XX", BigDecimal.valueOf(score).toPlainString(), encode(object)); + return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_BOOL, getRawName(), "XX", "CH", BigDecimal.valueOf(score).toPlainString(), encode(object)); } @Override @@ -369,6 +369,93 @@ public class RedissonScoredSortedSet extends RedissonExpirable implements RSc return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_INT, params.toArray()); } + @Override + public int addAllIfAbsent(Map objects) { + return get(addAllIfAbsentAsync(objects)); + } + + @Override + public RFuture addAllIfAbsentAsync(Map objects) { + if (objects.isEmpty()) { + return RedissonPromise.newSucceededFuture(0); + } + List params = new ArrayList<>(objects.size()*2+1); + params.add(getRawName()); + params.add("NX"); + for (Entry entry : objects.entrySet()) { + params.add(BigDecimal.valueOf(entry.getValue()).toPlainString()); + params.add(encode(entry.getKey())); + } + + return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_INT, params.toArray()); + } + + @Override + public int addAllIfExist(Map objects) { + return get(addAllIfExistAsync(objects)); + } + + @Override + public RFuture addAllIfExistAsync(Map objects) { + if (objects.isEmpty()) { + return RedissonPromise.newSucceededFuture(0); + } + List params = new ArrayList<>(objects.size()*2+1); + params.add(getRawName()); + params.add("XX"); + params.add("CH"); + for (Entry entry : objects.entrySet()) { + params.add(BigDecimal.valueOf(entry.getValue()).toPlainString()); + params.add(encode(entry.getKey())); + } + + return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_INT, params.toArray()); + } + + @Override + public int addAllIfGreater(Map objects) { + return get(addAllIfGreaterAsync(objects)); + } + + @Override + public RFuture addAllIfGreaterAsync(Map objects) { + if (objects.isEmpty()) { + return RedissonPromise.newSucceededFuture(0); + } + List params = new ArrayList<>(objects.size()*2+1); + params.add(getRawName()); + params.add("GT"); + params.add("CH"); + for (Entry entry : objects.entrySet()) { + params.add(BigDecimal.valueOf(entry.getValue()).toPlainString()); + params.add(encode(entry.getKey())); + } + + return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_INT, params.toArray()); + } + + @Override + public int addAllIfLess(Map objects) { + return get(addAllIfLessAsync(objects)); + } + + @Override + public RFuture addAllIfLessAsync(Map objects) { + if (objects.isEmpty()) { + return RedissonPromise.newSucceededFuture(0); + } + List params = new ArrayList<>(objects.size()*2+1); + params.add(getRawName()); + params.add("LT"); + params.add("CH"); + for (Entry entry : objects.entrySet()) { + params.add(BigDecimal.valueOf(entry.getValue()).toPlainString()); + params.add(encode(entry.getKey())); + } + + return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_INT, params.toArray()); + } + @Override public RFuture tryAddAsync(double score, V object) { return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.ZADD_BOOL, getRawName(), "NX", BigDecimal.valueOf(score).toPlainString(), encode(object)); diff --git a/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java b/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java index ff56c9023..3c4338c20 100644 --- a/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java +++ b/redisson/src/main/java/org/redisson/api/RScoredSortedSet.java @@ -243,6 +243,46 @@ public interface RScoredSortedSet extends RScoredSortedSetAsync, Iterable< */ int addAll(Map objects); + /** + * Adds elements to this set only if they haven't been added before. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + int addAllIfAbsent(Map objects); + + /** + * Adds elements to this set only if they already exist. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + int addAllIfExist(Map objects); + + /** + * Adds elements to this set only if new scores greater than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + int addAllIfGreater(Map objects); + + /** + * Adds elements to this set only if new scores less than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + int addAllIfLess(Map objects); + /** * Removes values by score range. * diff --git a/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java b/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java index 700e832f3..cc55183d4 100644 --- a/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java +++ b/redisson/src/main/java/org/redisson/api/RScoredSortedSetAsync.java @@ -204,6 +204,46 @@ public interface RScoredSortedSetAsync extends RExpirableAsync, RSortableAsyn */ RFuture addAllAsync(Map objects); + /** + * Adds elements to this set only if they haven't been added before. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + RFuture addAllIfAbsentAsync(Map objects); + + /** + * Adds elements to this set only if they already exist. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + RFuture addAllIfExistAsync(Map objects); + + /** + * Adds elements to this set only if new scores greater than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + RFuture addAllIfGreaterAsync(Map objects); + + /** + * Adds elements to this set only if new scores less than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + RFuture addAllIfLessAsync(Map objects); + /** * Removes values by score range. * diff --git a/redisson/src/main/java/org/redisson/api/RScoredSortedSetReactive.java b/redisson/src/main/java/org/redisson/api/RScoredSortedSetReactive.java index 204011549..b51561a41 100644 --- a/redisson/src/main/java/org/redisson/api/RScoredSortedSetReactive.java +++ b/redisson/src/main/java/org/redisson/api/RScoredSortedSetReactive.java @@ -15,18 +15,17 @@ */ package org.redisson.api; +import org.redisson.api.RScoredSortedSet.Aggregate; +import org.redisson.client.protocol.ScoredEntry; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import org.redisson.api.RScoredSortedSet.Aggregate; -import org.redisson.client.protocol.ScoredEntry; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * Reactive interface for SortedSet object * @@ -299,7 +298,47 @@ public interface RScoredSortedSetReactive extends RExpirableReactive, RSortab * @return amount of added elements, not including already existing in this sorted set */ Mono addAll(Map objects); - + + /** + * Adds elements to this set only if they haven't been added before. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Mono addAllIfAbsent(Map objects); + + /** + * Adds elements to this set only if they already exist. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Mono addAllIfExist(Map objects); + + /** + * Adds elements to this set only if new scores greater than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Mono addAllIfGreater(Map objects); + + /** + * Adds elements to this set only if new scores less than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Mono addAllIfLess(Map objects); + /** * Adds element to this set, overrides previous score if it has been already added. * Finally return the rank of the item diff --git a/redisson/src/main/java/org/redisson/api/RScoredSortedSetRx.java b/redisson/src/main/java/org/redisson/api/RScoredSortedSetRx.java index db9c40533..342f7f0f6 100644 --- a/redisson/src/main/java/org/redisson/api/RScoredSortedSetRx.java +++ b/redisson/src/main/java/org/redisson/api/RScoredSortedSetRx.java @@ -15,19 +15,18 @@ */ package org.redisson.api; +import io.reactivex.rxjava3.core.Flowable; +import io.reactivex.rxjava3.core.Maybe; +import io.reactivex.rxjava3.core.Single; +import org.redisson.api.RScoredSortedSet.Aggregate; +import org.redisson.client.protocol.ScoredEntry; + import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import org.redisson.api.RScoredSortedSet.Aggregate; -import org.redisson.client.protocol.ScoredEntry; - -import io.reactivex.rxjava3.core.Flowable; -import io.reactivex.rxjava3.core.Maybe; -import io.reactivex.rxjava3.core.Single; - /** * RxJava2 interface for scored sorted set data structure. * @@ -300,7 +299,47 @@ public interface RScoredSortedSetRx extends RExpirableRx, RSortableRx> * @return amount of added elements, not including already existing in this sorted set */ Single addAll(Map objects); - + + /** + * Adds elements to this set only if they haven't been added before. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Single addAllIfAbsent(Map objects); + + /** + * Adds elements to this set only if they already exist. + *

+ * Requires Redis 3.0.2 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Single addAllIfExist(Map objects); + + /** + * Adds elements to this set only if new scores greater than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Single addAllIfGreater(Map objects); + + /** + * Adds elements to this set only if new scores less than current score of existed elements. + *

+ * Requires Redis 6.2.0 and higher. + * + * @param objects map of elements to add + * @return amount of added elements + */ + Single addAllIfLess(Map objects); + /** * Adds element to this set, overrides previous score if it has been already added. * Finally return the rank of the item diff --git a/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java b/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java index 9106fedaf..c98773537 100644 --- a/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java +++ b/redisson/src/test/java/org/redisson/RedissonScoredSortedSetTest.java @@ -1,29 +1,5 @@ package org.redisson; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.entry; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.Test; @@ -34,6 +10,19 @@ import org.redisson.client.codec.StringCodec; import org.redisson.client.protocol.ScoredEntry; import org.redisson.config.Config; +import java.io.IOException; +import java.util.*; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class RedissonScoredSortedSetTest extends BaseTest { @Test @@ -422,6 +411,87 @@ public class RedissonScoredSortedSetTest extends BaseTest { new ScoredEntry(0.1, "1"), new ScoredEntry(0.2, "2"), new ScoredEntry(0.3, "3")); } + @Test + public void testAddAllIfAbsent() { + RScoredSortedSet set = redisson.getScoredSortedSet("simple"); + set.add(10, "1981"); + set.add(11, "1984"); + + Map map = new HashMap<>(); + map.put("1981", 111D); + map.put("1982", 112D); + map.put("1983", 113D); + map.put("1984", 114D); + + assertThat(set.addAllIfAbsent(map)).isEqualTo(2); + assertThat(set.getScore("1981")).isEqualTo(10); + assertThat(set.getScore("1984")).isEqualTo(11); + assertThat(set).contains("1981", "1982", "1983", "1984"); + } + + @Test + public void testAddAllIfExist() { + RScoredSortedSet set = redisson.getScoredSortedSet("simple"); + set.add(10, "1981"); + set.add(11, "1984"); + + Map map = new HashMap<>(); + map.put("1981", 111D); + map.put("1982", 112D); + map.put("1983", 113D); + map.put("1984", 114D); + + assertThat(set.addAllIfExist(map)).isEqualTo(2); + assertThat(set.getScore("1981")).isEqualTo(111D); + assertThat(set.getScore("1984")).isEqualTo(114D); + } + + @Test + public void testAddAllIfGreater() { + RScoredSortedSet set = redisson.getScoredSortedSet("simple"); + set.add(10, "1981"); + set.add(11, "1984"); + set.add(13, "1985"); + + Map map = new HashMap<>(); + map.put("1981", 111D); + map.put("1982", 112D); + map.put("1983", 113D); + map.put("1984", 8D); + map.put("1985", 3D); + + assertThat(set.addAllIfGreater(map)).isEqualTo(3); + assertThat(set.size()).isEqualTo(5); + assertThat(set.getScore("1981")).isEqualTo(111D); + assertThat(set.getScore("1982")).isEqualTo(112D); + assertThat(set.getScore("1983")).isEqualTo(113D); + assertThat(set.getScore("1984")).isEqualTo(11D); + assertThat(set.getScore("1985")).isEqualTo(13D); + } + + @Test + public void testAddAllIfLess() { + RScoredSortedSet set = redisson.getScoredSortedSet("simple"); + set.add(10D, "1981"); + set.add(11D, "1984"); + set.add(13D, "1985"); + + Map map = new HashMap<>(); + map.put("1981", 111D); + map.put("1982", 112D); + map.put("1983", 113D); + map.put("1984", 8D); + map.put("1985", 3D); + + assertThat(set.addAllIfLess(map)).isEqualTo(4); + assertThat(set.size()).isEqualTo(5); + assertThat(set.getScore("1981")).isEqualTo(10D); + assertThat(set.getScore("1982")).isEqualTo(112D); + assertThat(set.getScore("1983")).isEqualTo(113D); + assertThat(set.getScore("1984")).isEqualTo(8D); + assertThat(set.getScore("1985")).isEqualTo(3D); + } + @Test public void testAddIfGreater() { RScoredSortedSet set = redisson.getScoredSortedSet("simple"); @@ -449,7 +519,7 @@ public class RedissonScoredSortedSetTest extends BaseTest { assertThat(set.addIfExists(123.81, "1980")).isFalse(); assertThat(set.getScore("1980")).isNull(); set.add(111, "1980"); - assertThat(set.addIfExists(32, "1980")).isFalse(); + assertThat(set.addIfExists(32, "1980")).isTrue(); assertThat(set.getScore("1980")).isEqualTo(32); }