diff --git a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java index 7aa2e6a5b..94ffe72ce 100644 --- a/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java +++ b/src/main/java/org/springframework/data/redis/core/BoundZSetOperations.java @@ -481,6 +481,20 @@ public interface BoundZSetOperations extends BoundKeyOperations { @Nullable Set> differenceWithScores(Collection otherKeys); + /** + * Diff sorted {@code sets} and store result in destination {@code destKey}. + * + * @param otherKeys must not be {@literal null}. + * @param destKey must not be {@literal null}. + * @return {@literal null} when used in pipeline / transaction. + * @since 2.6 + * @see Redis Documentation: ZDIFFSTORE + */ + @Nullable + default Long differenceAndStore(K otherKey, K destKey) { + return differenceAndStore(Collections.singleton(otherKey), destKey); + } + /** * Diff sorted {@code sets} and store result in destination {@code destKey}. * diff --git a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java index 965887043..d84a3fe48 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java +++ b/src/main/java/org/springframework/data/redis/support/collections/DefaultRedisZSet.java @@ -105,6 +105,100 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R this.defaultScore = defaultScore; } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#difference(org.springframework.data.redis.support.collections.RedisZSet) + */ + @Override + public Set difference(RedisZSet set) { + return boundZSetOps.difference(set.getKey()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#difference(java.util.Collection) + */ + @Override + public Set difference(Collection> sets) { + return boundZSetOps.difference(CollectionUtils.extractKeys(sets)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#differenceWithScores(org.springframework.data.redis.support.collections.RedisZSet) + */ + @Override + public Set> differenceWithScores(RedisZSet set) { + return boundZSetOps.differenceWithScores(set.getKey()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#differenceWithScores(java.util.Collection) + */ + @Override + public Set> differenceWithScores(Collection> sets) { + return boundZSetOps.differenceWithScores(CollectionUtils.extractKeys(sets)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#differenceAndStore(org.springframework.data.redis.support.collections.RedisZSet, java.lang.String) + */ + @Override + public RedisZSet differenceAndStore(RedisZSet set, String destKey) { + + boundZSetOps.differenceAndStore(set.getKey(), destKey); + return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#differenceAndStore(java.util.Collection, java.lang.String) + */ + @Override + public RedisZSet differenceAndStore(Collection> sets, String destKey) { + + boundZSetOps.differenceAndStore(CollectionUtils.extractKeys(sets), destKey); + return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#intersect(org.springframework.data.redis.support.collections.RedisZSet) + */ + @Override + public Set intersect(RedisZSet set) { + return boundZSetOps.intersect(set.getKey()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#intersect(java.util.Collection) + */ + @Override + public Set intersect(Collection> sets) { + return boundZSetOps.intersect(CollectionUtils.extractKeys(sets)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#intersectWithScores(org.springframework.data.redis.support.collections.RedisZSet) + */ + @Override + public Set> intersectWithScores(RedisZSet set) { + return boundZSetOps.intersectWithScores(set.getKey()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#intersectWithScores(java.util.Collection) + */ + @Override + public Set> intersectWithScores(Collection> sets) { + return boundZSetOps.intersectWithScores(CollectionUtils.extractKeys(sets)); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.support.collections.RedisZSet#intersectAndStore(org.springframework.data.redis.support.collections.RedisZSet, java.lang.String) @@ -127,6 +221,62 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); } + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#union(org.springframework.data.redis.support.collections.RedisZSet) + */ + @Override + public Set union(RedisZSet set) { + return boundZSetOps.union(set.getKey()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#union(java.util.Collection) + */ + @Override + public Set union(Collection> sets) { + return boundZSetOps.union(CollectionUtils.extractKeys(sets)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#unionWithScores(org.springframework.data.redis.support.collections.RedisZSet) + */ + @Override + public Set> unionWithScores(RedisZSet set) { + return boundZSetOps.unionWithScores(set.getKey()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#unionWithScores(java.util.Collection) + */ + @Override + public Set> unionWithScores(Collection> sets) { + return boundZSetOps.unionWithScores(CollectionUtils.extractKeys(sets)); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#unionAndStore(org.springframework.data.redis.support.collections.RedisZSet, java.lang.String) + */ + @Override + public RedisZSet unionAndStore(RedisZSet set, String destKey) { + boundZSetOps.unionAndStore(set.getKey(), destKey); + return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.redis.support.collections.RedisZSet#unionAndStore(java.util.Collection, java.lang.String) + */ + @Override + public RedisZSet unionAndStore(Collection> sets, String destKey) { + boundZSetOps.unionAndStore(CollectionUtils.extractKeys(sets), destKey); + return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); + } + /* * (non-Javadoc) * @see org.springframework.data.redis.support.collections.RedisZSet#range(long, long) @@ -247,26 +397,6 @@ public class DefaultRedisZSet extends AbstractRedisCollection implements R return this; } - /* - * (non-Javadoc) - * @see org.springframework.data.redis.support.collections.RedisZSet#unionAndStore(org.springframework.data.redis.support.collections.RedisZSet, java.lang.String) - */ - @Override - public RedisZSet unionAndStore(RedisZSet set, String destKey) { - boundZSetOps.unionAndStore(set.getKey(), destKey); - return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); - } - - /* - * (non-Javadoc) - * @see org.springframework.data.redis.support.collections.RedisZSet#unionAndStore(java.util.Collection, java.lang.String) - */ - @Override - public RedisZSet unionAndStore(Collection> sets, String destKey) { - boundZSetOps.unionAndStore(CollectionUtils.extractKeys(sets), destKey); - return new DefaultRedisZSet<>(boundZSetOps.getOperations().boundZSetOps(destKey), getDefaultScore()); - } - /* * (non-Javadoc) * @see java.util.AbstractCollection#add(java.lang.Object) diff --git a/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java b/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java index 4750ab6bc..89002ebfb 100644 --- a/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java +++ b/src/main/java/org/springframework/data/redis/support/collections/RedisZSet.java @@ -66,6 +66,100 @@ public interface RedisZSet extends RedisCollection, Set { return new DefaultRedisZSet<>(key, operations, defaultScore); } + /** + * Diff this set and another {@link RedisZSet}. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the values that differ. + * @since 2.6 + */ + Set difference(RedisZSet set); + + /** + * Diff this set and other {@link RedisZSet}s. + * + * @param sets must not be {@literal null}. + * @return a {@link Set} containing the values that differ. + * @since 2.6 + */ + Set difference(Collection> sets); + + /** + * Diff this set and another {@link RedisZSet}. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the values that differ with their scores. + * @since 2.6 + */ + Set> differenceWithScores(RedisZSet set); + + /** + * Diff this set and other {@link RedisZSet}s. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the values that differ with their scores. + * @since 2.6 + */ + Set> differenceWithScores(Collection> sets); + + /** + * Create a new {@link RedisZSet} by diffing this sorted set and {@link RedisZSet} and store result in destination + * {@code destKey}. + * + * @param set must not be {@literal null}. + * @param destKey must not be {@literal null}. + * @return a new {@link RedisZSet} pointing at {@code destKey}. + * @since 2.6 + */ + RedisZSet differenceAndStore(RedisZSet set, String destKey); + + /** + * Create a new {@link RedisZSet} by diffing this sorted set and the collection {@link RedisZSet} and store result in + * destination {@code destKey}. + * + * @param sets must not be {@literal null}. + * @param destKey must not be {@literal null}. + * @return a new {@link RedisZSet} pointing at {@code destKey}. + * @since 2.6 + */ + RedisZSet differenceAndStore(Collection> sets, String destKey); + + /** + * Intersect this set and another {@link RedisZSet}. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the intersecting values. + * @since 2.6 + */ + Set intersect(RedisZSet set); + + /** + * Intersect this set and other {@link RedisZSet}s. + * + * @param sets must not be {@literal null}. + * @return a {@link Set} containing the intersecting values. + * @since 2.6 + */ + Set intersect(Collection> sets); + + /** + * Intersect this set and another {@link RedisZSet}. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the intersecting values with their scores. + * @since 2.6 + */ + Set> intersectWithScores(RedisZSet set); + + /** + * Intersect this set and other {@link RedisZSet}s. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the intersecting values with their scores. + * @since 2.6 + */ + Set> intersectWithScores(Collection> sets); + /** * Create a new {@link RedisZSet} by intersecting this sorted set and {@link RedisZSet} and store result in * destination {@code destKey}. @@ -86,6 +180,42 @@ public interface RedisZSet extends RedisCollection, Set { */ RedisZSet intersectAndStore(Collection> sets, String destKey); + /** + * Union this set and another {@link RedisZSet}. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the combined values. + * @since 2.6 + */ + Set union(RedisZSet set); + + /** + * Union this set and other {@link RedisZSet}s. + * + * @param sets must not be {@literal null}. + * @return a {@link Set} containing the combined values. + * @since 2.6 + */ + Set union(Collection> sets); + + /** + * Union this set and another {@link RedisZSet}. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the combined values with their scores. + * @since 2.6 + */ + Set> unionWithScores(RedisZSet set); + + /** + * Union this set and other {@link RedisZSet}s. + * + * @param set must not be {@literal null}. + * @return a {@link Set} containing the combined values with their scores. + * @since 2.6 + */ + Set> unionWithScores(Collection> sets); + /** * Create a new {@link RedisZSet} by union this sorted set and {@link RedisZSet} and store result in destination * {@code destKey}. diff --git a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java index 71355615c..26b08ab49 100644 --- a/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java +++ b/src/test/java/org/springframework/data/redis/support/collections/AbstractRedisZSetTestIntegration.java @@ -36,6 +36,7 @@ import org.springframework.data.redis.ObjectFactory; import org.springframework.data.redis.connection.RedisZSetCommands; import org.springframework.data.redis.core.BoundZSetOperations; import org.springframework.data.redis.core.Cursor; +import org.springframework.data.redis.core.DefaultTypedTuple; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ZSetOperations.TypedTuple; import org.springframework.data.redis.test.condition.EnabledOnCommand; @@ -303,35 +304,6 @@ public abstract class AbstractRedisZSetTestIntegration extends AbstractRedisC return new DefaultRedisZSet<>((BoundZSetOperations) zSet.getOperations().boundZSetOps(key)); } - @ParameterizedRedisTest - void testIntersectAndStore() { - - RedisZSet interSet1 = createZSetFor("test:zset:inter1"); - RedisZSet interSet2 = createZSetFor("test:zset:inter"); - - T t1 = getT(); - T t2 = getT(); - T t3 = getT(); - T t4 = getT(); - - zSet.add(t1, 1); - zSet.add(t2, 2); - zSet.add(t3, 3); - - interSet1.add(t2, 2); - interSet1.add(t4, 3); - interSet2.add(t2, 2); - interSet2.add(t3, 3); - - String resultName = "test:zset:inter:result:1"; - RedisZSet inter = zSet.intersectAndStore(Arrays.asList(interSet1, interSet2), resultName); - - assertThat(inter).hasSize(1); - assertThat(inter).contains(t2); - assertThat(inter.score(t2)).isEqualTo(Double.valueOf(6)); - assertThat(inter.getKey()).isEqualTo(resultName); - } - @ParameterizedRedisTest void testRange() { T t1 = getT(); @@ -640,6 +612,136 @@ public abstract class AbstractRedisZSetTestIntegration extends AbstractRedisC assertThat(iterator.next()).isEqualTo(t4); } + @ParameterizedRedisTest // GH-2041 + @EnabledOnCommand("ZDIFF") + void testDifference() { + + RedisZSet set1 = createZSetFor("test:zset:set1"); + RedisZSet set2 = createZSetFor("test:zset:set2"); + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + zSet.add(t1, 1); + zSet.add(t2, 2); + zSet.add(t3, 3); + + set1.add(t2, 2); + set1.add(t4, 3); + set2.add(t2, 2); + set2.add(t3, 3); + + assertThat(zSet.difference(Arrays.asList(set1, set2))).containsOnly(t1); + assertThat(zSet.differenceWithScores(Arrays.asList(set1, set2))).containsOnly(new DefaultTypedTuple<>(t1, 1d)); + } + + @ParameterizedRedisTest // GH-2041 + void testDifferenceAndStore() { + + RedisZSet set1 = createZSetFor("test:zset:set1"); + RedisZSet set2 = createZSetFor("test:zset:set2"); + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + zSet.add(t1, 1); + zSet.add(t2, 2); + zSet.add(t3, 3); + + set1.add(t2, 2); + set1.add(t4, 3); + set2.add(t2, 2); + set2.add(t3, 3); + + String resultName = "test:zset:inter:result:1"; + RedisZSet diff = zSet.differenceAndStore(Arrays.asList(set1, set2), resultName); + + assertThat(diff).containsOnly(t1); + } + + @ParameterizedRedisTest // GH-2042 + @EnabledOnCommand("ZINTER") + void testIntersect() { + + RedisZSet interSet1 = createZSetFor("test:zset:inter1"); + RedisZSet interSet2 = createZSetFor("test:zset:inter"); + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + zSet.add(t1, 1); + zSet.add(t2, 2); + zSet.add(t3, 3); + + interSet1.add(t2, 2); + interSet1.add(t4, 3); + interSet2.add(t2, 2); + interSet2.add(t3, 3); + + assertThat(zSet.intersect(Arrays.asList(interSet1, interSet2))).containsOnly(t2); + assertThat(zSet.intersectWithScores(Arrays.asList(interSet1, interSet2))) + .containsOnly(new DefaultTypedTuple<>(t2, 6d)); + } + + @ParameterizedRedisTest + void testIntersectAndStore() { + + RedisZSet interSet1 = createZSetFor("test:zset:inter1"); + RedisZSet interSet2 = createZSetFor("test:zset:inter"); + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + zSet.add(t1, 1); + zSet.add(t2, 2); + zSet.add(t3, 3); + + interSet1.add(t2, 2); + interSet1.add(t4, 3); + interSet2.add(t2, 2); + interSet2.add(t3, 3); + + String resultName = "test:zset:inter:result:1"; + RedisZSet inter = zSet.intersectAndStore(Arrays.asList(interSet1, interSet2), resultName); + + assertThat(inter).hasSize(1); + assertThat(inter).contains(t2); + assertThat(inter.score(t2)).isEqualTo(Double.valueOf(6)); + assertThat(inter.getKey()).isEqualTo(resultName); + } + + @ParameterizedRedisTest // GH-2042 + @EnabledOnCommand("ZUNION") + void testUnion() { + + RedisZSet set1 = createZSetFor("test:zset:union1"); + RedisZSet set2 = createZSetFor("test:zset:union2"); + + T t1 = getT(); + T t2 = getT(); + T t3 = getT(); + T t4 = getT(); + + zSet.add(t1, 1); + zSet.add(t2, 2); + zSet.add(t3, 3); + + set1.add(t2, 2); + set1.add(t4, 3); + set2.add(t2, 2); + set2.add(t3, 3); + + assertThat(zSet.union(Arrays.asList(set1, set2))).contains(t1, t2, t3, t4); + } + @SuppressWarnings("unchecked") @ParameterizedRedisTest void testUnionAndStore() {