Add reactive support for ZDIFF, ZDIFFSTORE, ZINTER, and ZUNION commands.

See: #2041 & #2042
Original Pull Request: #2097
This commit is contained in:
Mark Paluch
2021-06-24 14:55:12 +02:00
committed by Christoph Strobl
parent 8dc6f014ee
commit 38d3576052
8 changed files with 1615 additions and 425 deletions

View File

@@ -1174,34 +1174,6 @@ public interface RedisZSetCommands {
@Nullable
Set<byte[]> zInter(byte[]... sets);
/**
* Intersect sorted {@code sets}.
*
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @param sets must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
@Nullable
default Set<byte[]> zInter(Aggregate aggregate, int[] weights, byte[]... sets) {
return zInter(aggregate, Weights.of(weights), sets);
}
/**
* Intersect sorted {@code sets}.
*
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @param sets must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
@Nullable
Set<byte[]> zInter(Aggregate aggregate, Weights weights, byte[]... sets);
/**
* Intersect sorted {@code sets}.
*
@@ -1293,34 +1265,6 @@ public interface RedisZSetCommands {
@Nullable
Set<byte[]> zUnion(byte[]... sets);
/**
* Union sorted {@code sets}.
*
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @param sets must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
@Nullable
default Set<byte[]> zUnion(Aggregate aggregate, int[] weights, byte[]... sets) {
return zUnion(aggregate, Weights.of(weights), sets);
}
/**
* Union sorted {@code sets}.
*
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @param sets must not be {@literal null}.
* @return {@literal null} when used in pipeline / transaction.
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
@Nullable
Set<byte[]> zUnion(Aggregate aggregate, Weights weights, byte[]... sets);
/**
* Union sorted {@code sets}.
*

View File

@@ -41,11 +41,13 @@ class LettuceReactiveClusterZSetCommands extends LettuceReactiveZSetCommands imp
super(connection);
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.lettuce.LettuceReactiveZSetCommands#zUnionStore(org.reactivestreams.Publisher)
*/
@Override
public Flux<NumericResponse<ZUnionStoreCommand, Long>> zUnionStore(Publisher<ZUnionStoreCommand> commands) {
public Flux<NumericResponse<ZAggregateStoreCommand, Long>> zUnionStore(
Publisher<? extends ZAggregateStoreCommand> commands) {
return getConnection().execute(cmd -> Flux.from(commands).concatMap(command -> {
@@ -60,11 +62,13 @@ class LettuceReactiveClusterZSetCommands extends LettuceReactiveZSetCommands imp
}));
}
/* (non-Javadoc)
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.lettuce.LettuceReactiveZSetCommands#zInterStore(org.reactivestreams.Publisher)
*/
@Override
public Flux<NumericResponse<ZInterStoreCommand, Long>> zInterStore(Publisher<ZInterStoreCommand> commands) {
public Flux<NumericResponse<ZAggregateStoreCommand, Long>> zInterStore(
Publisher<? extends ZAggregateStoreCommand> commands) {
return getConnection().execute(cmd -> Flux.from(commands).concatMap(command -> {
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty.");

View File

@@ -200,22 +200,18 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
if (ObjectUtils.nullSafeEquals(command.getDirection(), Direction.ASC)) {
if (command.isWithScores()) {
result = cmd.zrangeWithScores(command.getKey(), start, stop)
.map(this::toTuple);
result = cmd.zrangeWithScores(command.getKey(), start, stop).map(this::toTuple);
} else {
result = cmd.zrange(command.getKey(), start, stop)
.map(value -> toTuple(value, Double.NaN));
result = cmd.zrange(command.getKey(), start, stop).map(value -> toTuple(value, Double.NaN));
}
} else {
if (command.isWithScores()) {
result = cmd.zrevrangeWithScores(command.getKey(), start, stop)
.map(this::toTuple);
result = cmd.zrevrangeWithScores(command.getKey(), start, stop).map(this::toTuple);
} else {
result = cmd.zrevrange(command.getKey(), start, stop)
.map(value -> toTuple(value, Double.NaN));
result = cmd.zrevrange(command.getKey(), start, stop).map(value -> toTuple(value, Double.NaN));
}
}
@@ -247,8 +243,7 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
if (command.isWithScores()) {
if (!isLimited) {
result = cmd.zrangebyscoreWithScores(command.getKey(), range)
.map(this::toTuple);
result = cmd.zrangebyscoreWithScores(command.getKey(), range).map(this::toTuple);
} else {
result = cmd
.zrangebyscoreWithScores(command.getKey(), range, LettuceConverters.toLimit(command.getLimit().get()))
@@ -257,8 +252,7 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
} else {
if (!isLimited) {
result = cmd.zrangebyscore(command.getKey(), range)
.map(value -> toTuple(value, Double.NaN));
result = cmd.zrangebyscore(command.getKey(), range).map(value -> toTuple(value, Double.NaN));
} else {
result = cmd.zrangebyscore(command.getKey(), range, LettuceConverters.toLimit(command.getLimit().get()))
@@ -272,20 +266,16 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
if (command.isWithScores()) {
if (!isLimited) {
result = cmd.zrevrangebyscoreWithScores(command.getKey(), range)
.map(this::toTuple);
result = cmd.zrevrangebyscoreWithScores(command.getKey(), range).map(this::toTuple);
} else {
result = cmd
.zrevrangebyscoreWithScores(command.getKey(), range,
LettuceConverters.toLimit(command.getLimit().get()))
.map(this::toTuple);
result = cmd.zrevrangebyscoreWithScores(command.getKey(), range,
LettuceConverters.toLimit(command.getLimit().get())).map(this::toTuple);
}
} else {
if (!isLimited) {
result = cmd.zrevrangebyscore(command.getKey(), range)
.map(value -> toTuple(value, Double.NaN));
result = cmd.zrevrangebyscore(command.getKey(), range).map(value -> toTuple(value, Double.NaN));
} else {
result = cmd.zrevrangebyscore(command.getKey(), range, LettuceConverters.toLimit(command.getLimit().get()))
@@ -518,12 +508,186 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zDiff(Publisher)
*/
@Override
public Flux<CommandResponse<ZDiffCommand, Flux<ByteBuffer>>> zDiff(Publisher<? extends ZDiffCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notEmpty(command.getKeys(), "Keys must not be null or empty!");
ByteBuffer[] sourceKeys = command.getKeys().toArray(new ByteBuffer[0]);
return new CommandResponse<>(command, cmd.zdiff(sourceKeys));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zDiffWithScores(Publisher)
*/
@Override
public Flux<CommandResponse<ZDiffCommand, Flux<Tuple>>> zDiffWithScores(Publisher<? extends ZDiffCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notEmpty(command.getKeys(), "Keys must not be null or empty!");
ByteBuffer[] sourceKeys = command.getKeys().toArray(new ByteBuffer[0]);
return new CommandResponse<>(command, cmd.zdiffWithScores(sourceKeys).map(this::toTuple));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zDiffStore(Publisher)
*/
@Override
public Flux<NumericResponse<ZDiffStoreCommand, Long>> zDiffStore(Publisher<ZDiffStoreCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
Assert.notNull(command.getKey(), "Destination key must not be null!");
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty!");
ByteBuffer[] sourceKeys = command.getSourceKeys().toArray(new ByteBuffer[0]);
return cmd.zdiffstore(command.getKey(), sourceKeys).map(value -> new NumericResponse<>(command, value));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zInter(Publisher)
*/
@Override
public Flux<CommandResponse<ZAggregateCommand, Flux<ByteBuffer>>> zInter(
Publisher<? extends ZAggregateCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty!");
ZStoreArgs args = null;
if (command.getAggregateFunction().isPresent() || !command.getWeights().isEmpty()) {
args = zStoreArgs(command.getAggregateFunction().isPresent() ? command.getAggregateFunction().get() : null,
command.getWeights());
}
ByteBuffer[] sourceKeys = command.getSourceKeys().toArray(new ByteBuffer[0]);
Flux<ByteBuffer> result = args != null ? cmd.zinter(args, sourceKeys) : cmd.zinter(sourceKeys);
return new CommandResponse<>(command, result);
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zInterWithScores(Publisher)
*/
@Override
public Flux<CommandResponse<ZAggregateCommand, Flux<Tuple>>> zInterWithScores(
Publisher<? extends ZAggregateCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty!");
ZStoreArgs args = null;
if (command.getAggregateFunction().isPresent() || !command.getWeights().isEmpty()) {
args = zStoreArgs(command.getAggregateFunction().isPresent() ? command.getAggregateFunction().get() : null,
command.getWeights());
}
ByteBuffer[] sourceKeys = command.getSourceKeys().toArray(new ByteBuffer[0]);
Flux<ScoredValue<ByteBuffer>> result = args != null ? cmd.zinterWithScores(args, sourceKeys)
: cmd.zinterWithScores(sourceKeys);
return new CommandResponse<>(command, result.map(this::toTuple));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zInterStore(org.reactivestreams.Publisher)
*/
@Override
public Flux<NumericResponse<ZAggregateStoreCommand, Long>> zInterStore(
Publisher<? extends ZAggregateStoreCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
Assert.notNull(command.getKey(), "Destination key must not be null!");
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty!");
ZStoreArgs args = null;
if (command.getAggregateFunction().isPresent() || !command.getWeights().isEmpty()) {
args = zStoreArgs(command.getAggregateFunction().isPresent() ? command.getAggregateFunction().get() : null,
command.getWeights());
}
ByteBuffer[] sourceKeys = command.getSourceKeys().toArray(new ByteBuffer[0]);
Mono<Long> result = args != null ? cmd.zinterstore(command.getKey(), args, sourceKeys)
: cmd.zinterstore(command.getKey(), sourceKeys);
return result.map(value -> new NumericResponse<>(command, value));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zUnion(org.reactivestreams.Publisher)
*/
@Override
public Flux<CommandResponse<ZAggregateCommand, Flux<ByteBuffer>>> zUnion(
Publisher<? extends ZAggregateCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty!");
ZStoreArgs args = null;
if (command.getAggregateFunction().isPresent() || !command.getWeights().isEmpty()) {
args = zStoreArgs(command.getAggregateFunction().isPresent() ? command.getAggregateFunction().get() : null,
command.getWeights());
}
ByteBuffer[] sourceKeys = command.getSourceKeys().stream().toArray(ByteBuffer[]::new);
Flux<ByteBuffer> result = args != null ? cmd.zunion(args, sourceKeys) : cmd.zunion(sourceKeys);
return new CommandResponse<>(command, result);
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zUnion(org.reactivestreams.Publisher)
*/
@Override
public Flux<CommandResponse<ZAggregateCommand, Flux<Tuple>>> zUnionWithScores(
Publisher<? extends ZAggregateCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).map(command -> {
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty!");
ZStoreArgs args = null;
if (command.getAggregateFunction().isPresent() || !command.getWeights().isEmpty()) {
args = zStoreArgs(command.getAggregateFunction().isPresent() ? command.getAggregateFunction().get() : null,
command.getWeights());
}
ByteBuffer[] sourceKeys = command.getSourceKeys().stream().toArray(ByteBuffer[]::new);
Flux<ScoredValue<ByteBuffer>> result = args != null ? cmd.zunionWithScores(args, sourceKeys)
: cmd.zunionWithScores(sourceKeys);
return new CommandResponse<>(command, result.map(this::toTuple));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zUnionStore(org.reactivestreams.Publisher)
*/
@Override
public Flux<NumericResponse<ZUnionStoreCommand, Long>> zUnionStore(Publisher<ZUnionStoreCommand> commands) {
public Flux<NumericResponse<ZAggregateStoreCommand, Long>> zUnionStore(
Publisher<? extends ZAggregateStoreCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
@@ -543,31 +707,6 @@ class LettuceReactiveZSetCommands implements ReactiveZSetCommands {
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zInterStore(org.reactivestreams.Publisher)
*/
@Override
public Flux<NumericResponse<ZInterStoreCommand, Long>> zInterStore(Publisher<ZInterStoreCommand> commands) {
return connection.execute(cmd -> Flux.from(commands).concatMap(command -> {
Assert.notNull(command.getKey(), "Destination key must not be null!");
Assert.notEmpty(command.getSourceKeys(), "Source keys must not be null or empty!");
ZStoreArgs args = null;
if (command.getAggregateFunction().isPresent() || !command.getWeights().isEmpty()) {
args = zStoreArgs(command.getAggregateFunction().isPresent() ? command.getAggregateFunction().get() : null,
command.getWeights());
}
ByteBuffer[] sourceKeys = command.getSourceKeys().stream().toArray(ByteBuffer[]::new);
Mono<Long> result = args != null ? cmd.zinterstore(command.getKey(), args, sourceKeys)
: cmd.zinterstore(command.getKey(), sourceKeys);
return result.map(value -> new NumericResponse<>(command, value));
}));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.connection.ReactiveZSetCommands#zRangeByLex(org.reactivestreams.Publisher)

View File

@@ -27,7 +27,6 @@ import java.util.List;
import java.util.function.Function;
import org.reactivestreams.Publisher;
import org.springframework.data.domain.Range;
import org.springframework.data.redis.connection.DefaultTuple;
import org.springframework.data.redis.connection.ReactiveZSetCommands;
@@ -501,6 +500,194 @@ class DefaultReactiveZSetOperations<K, V> implements ReactiveZSetOperations<K, V
return createMono(connection -> connection.zRemRangeByScore(rawKey(key), range));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#difference(K, Collection)
*/
@Override
public Flux<V> difference(K key, Collection<K> otherKeys) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(connection::zDiff).map(this::readValue));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#differenceWithScores(K, Collection)
*/
@Override
public Flux<TypedTuple<V>> differenceWithScores(K key, Collection<K> otherKeys) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(connection::zDiffWithScores).map(this::readTypedTuple));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#differenceAndStore(K, Collection, K)
*/
@Override
public Mono<Long> differenceAndStore(K key, Collection<K> otherKeys, K destKey) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
Assert.notNull(destKey, "Destination key must not be null!");
return createMono(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMap(serialized -> connection.zDiffStore(rawKey(destKey), serialized)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersect(K, Collection)
*/
@Override
public Flux<V> intersect(K key, Collection<K> otherKeys) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(connection::zInter).map(this::readValue));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersectWithScores(K, Collection)
*/
@Override
public Flux<TypedTuple<V>> intersectWithScores(K key, Collection<K> otherKeys) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(connection::zInterWithScores).map(this::readTypedTuple));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersectWithScores(K, Collection, Aggregate, Weights)
*/
@Override
public Flux<TypedTuple<V>> intersectWithScores(K key, Collection<K> otherKeys, Aggregate aggregate, Weights weights) {
// TODO: Inconsistent method signatures Aggregate/Weights vs Weights/Aggregate in Connection API
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
Assert.notNull(aggregate, "Aggregate must not be null!");
Assert.notNull(weights, "Weights must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(sets -> connection.zInterWithScores(sets, weights, aggregate)).map(this::readTypedTuple));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersectAndStore(java.lang.Object, java.util.Collection, java.lang.Object)
*/
@Override
public Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
Assert.notNull(destKey, "Destination key must not be null!");
return createMono(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMap(serialized -> connection.zInterStore(rawKey(destKey), serialized)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersectAndStore(java.lang.Object, java.util.Collection, java.lang.Object, org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, org.springframework.data.redis.connection.RedisZSetCommands.Weights)
*/
@Override
public Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey, Aggregate aggregate, Weights weights) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
Assert.notNull(destKey, "Destination key must not be null!");
Assert.notNull(aggregate, "Aggregate must not be null!");
Assert.notNull(weights, "Weights must not be null!");
return createMono(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMap(serialized -> connection.zInterStore(rawKey(destKey), serialized, weights, aggregate)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#union(K, Collection)
*/
@Override
public Flux<V> union(K key, Collection<K> otherKeys) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(connection::zUnion).map(this::readValue));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#unionWithScores(K, Collection)
*/
@Override
public Flux<TypedTuple<V>> unionWithScores(K key, Collection<K> otherKeys) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(connection::zUnionWithScores).map(this::readTypedTuple));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#unionWithScores(K, Collection, Aggregate, Weights)
*/
@Override
public Flux<TypedTuple<V>> unionWithScores(K key, Collection<K> otherKeys, Aggregate aggregate, Weights weights) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
Assert.notNull(aggregate, "Aggregate must not be null!");
Assert.notNull(weights, "Weights must not be null!");
return createFlux(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMapMany(sets -> connection.zUnionWithScores(sets, weights, aggregate)).map(this::readTypedTuple));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#unionAndStore(java.lang.Object, java.lang.Object, java.lang.Object)
@@ -551,56 +738,6 @@ class DefaultReactiveZSetOperations<K, V> implements ReactiveZSetOperations<K, V
.flatMap(serialized -> connection.zUnionStore(rawKey(destKey), serialized, weights, aggregate)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersectAndStore(java.lang.Object, java.lang.Object, java.lang.Object)
*/
@Override
public Mono<Long> intersectAndStore(K key, K otherKey, K destKey) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKey, "Other key must not be null!");
Assert.notNull(destKey, "Destination key must not be null!");
return intersectAndStore(key, Collections.singleton(otherKey), destKey);
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersectAndStore(java.lang.Object, java.util.Collection, java.lang.Object)
*/
@Override
public Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
Assert.notNull(destKey, "Destination key must not be null!");
return createMono(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMap(serialized -> connection.zInterStore(rawKey(destKey), serialized)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#intersectAndStore(java.lang.Object, java.util.Collection, java.lang.Object, org.springframework.data.redis.connection.RedisZSetCommands.Aggregate, org.springframework.data.redis.connection.RedisZSetCommands.Weights)
*/
@Override
public Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey, Aggregate aggregate, Weights weights) {
Assert.notNull(key, "Key must not be null!");
Assert.notNull(otherKeys, "Other keys must not be null!");
Assert.notNull(destKey, "Destination key must not be null!");
Assert.notNull(aggregate, "Aggregate must not be null!");
Assert.notNull(weights, "Weights must not be null!");
return createMono(connection -> Flux.fromIterable(getKeys(key, otherKeys)) //
.map(this::rawKey) //
.collectList() //
.flatMap(serialized -> connection.zInterStore(rawKey(destKey), serialized, weights, aggregate)));
}
/*
* (non-Javadoc)
* @see org.springframework.data.redis.core.ReactiveZSetOperations#rangeByLex(java.lang.Object, org.springframework.data.domain.Range)

View File

@@ -20,6 +20,7 @@ import reactor.core.publisher.Mono;
import java.time.Duration;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.data.domain.Range;
@@ -412,6 +413,283 @@ public interface ReactiveZSetOperations<K, V> {
*/
Mono<Long> removeRangeByScore(K key, Range<Double> range);
/**
* Diff sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zdiff">Redis Documentation: ZDIFF</a>
*/
default Flux<V> difference(K key, K otherKey) {
return difference(key, Collections.singleton(otherKey));
}
/**
* Diff sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zdiff">Redis Documentation: ZDIFF</a>
*/
Flux<V> difference(K key, Collection<K> otherKeys);
/**
* Diff sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zdiff">Redis Documentation: ZDIFF</a>
*/
default Flux<TypedTuple<V>> differenceWithScores(K key, K otherKey) {
return differenceWithScores(key, Collections.singleton(otherKey));
}
/**
* Diff sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zdiff">Redis Documentation: ZDIFF</a>
*/
Flux<TypedTuple<V>> differenceWithScores(K key, Collection<K> otherKeys);
/**
* Diff sorted {@code sets} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zdiffstore">Redis Documentation: ZDIFFSTORE</a>
*/
default Mono<Long> differenceAndStore(K key, K otherKey, K destKey) {
return differenceAndStore(key, Collections.singleton(otherKey), destKey);
}
/**
* Diff sorted {@code sets} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zdiffstore">Redis Documentation: ZDIFFSTORE</a>
*/
Mono<Long> differenceAndStore(K key, Collection<K> otherKeys, K destKey);
/**
* Intersect sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
default Flux<V> intersect(K key, K otherKey) {
return intersect(key, Collections.singleton(otherKey));
}
/**
* Intersect sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
Flux<V> intersect(K key, Collection<K> otherKeys);
/**
* Intersect sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
default Flux<TypedTuple<V>> intersectWithScores(K key, K otherKey) {
return intersectWithScores(key, Collections.singleton(otherKey));
}
/**
* Intersect sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
Flux<TypedTuple<V>> intersectWithScores(K key, Collection<K> otherKeys);
/**
* Intersect sorted sets at {@code key} and {@code otherKeys} .
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
default Flux<TypedTuple<V>> intersectWithScores(K key, Collection<K> otherKeys, Aggregate aggregate) {
return intersectWithScores(key, otherKeys, aggregate, Weights.fromSetCount(1 + otherKeys.size()));
}
/**
* Intersect sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zinter">Redis Documentation: ZINTER</a>
*/
Flux<TypedTuple<V>> intersectWithScores(K key, Collection<K> otherKeys, Aggregate aggregate, Weights weights);
/**
* Intersect sorted sets at {@code key} and {@code otherKey} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
default Mono<Long> intersectAndStore(K key, K otherKey, K destKey) {
return intersectAndStore(key, Collections.singleton(otherKey), destKey);
}
/**
* Intersect sorted sets at {@code key} and {@code otherKeys} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey);
/**
* Intersect sorted sets at {@code key} and {@code otherKeys} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @return
* @since 2.1
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
default Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey, Aggregate aggregate) {
return intersectAndStore(key, otherKeys, destKey, aggregate, Weights.fromSetCount(1 + otherKeys.size()));
}
/**
* Intersect sorted sets at {@code key} and {@code otherKeys} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @return
* @since 2.1
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey, Aggregate aggregate, Weights weights);
/**
* Union sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
default Flux<V> union(K key, K otherKey) {
return union(key, Collections.singleton(otherKey));
}
/**
* Union sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
Flux<V> union(K key, Collection<K> otherKeys);
/**
* Union sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
default Flux<TypedTuple<V>> unionWithScores(K key, K otherKey) {
return unionWithScores(key, Collections.singleton(otherKey));
}
/**
* Union sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
Flux<TypedTuple<V>> unionWithScores(K key, Collection<K> otherKeys);
/**
* Union sorted sets at {@code key} and {@code otherKeys} .
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
default Flux<TypedTuple<V>> unionWithScores(K key, Collection<K> otherKeys, Aggregate aggregate) {
return unionWithScores(key, otherKeys, aggregate, Weights.fromSetCount(1 + otherKeys.size()));
}
/**
* Union sorted {@code sets}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @return
* @since 2.6
* @see <a href="https://redis.io/commands/zunion">Redis Documentation: ZUNION</a>
*/
Flux<TypedTuple<V>> unionWithScores(K key, Collection<K> otherKeys, Aggregate aggregate, Weights weights);
/**
* Union sorted sets at {@code key} and {@code otherKeys} and store result in destination {@code destKey}.
*
@@ -463,57 +741,6 @@ public interface ReactiveZSetOperations<K, V> {
*/
Mono<Long> unionAndStore(K key, Collection<K> otherKeys, K destKey, Aggregate aggregate, Weights weights);
/**
* Intersect sorted sets at {@code key} and {@code otherKey} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKey must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
Mono<Long> intersectAndStore(K key, K otherKey, K destKey);
/**
* Intersect sorted sets at {@code key} and {@code otherKeys} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @return
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey);
/**
* Intersect sorted sets at {@code key} and {@code otherKeys} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @return
* @since 2.1
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
default Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey, Aggregate aggregate) {
return intersectAndStore(key, otherKeys, destKey, aggregate, Weights.fromSetCount(1 + otherKeys.size()));
}
/**
* Intersect sorted sets at {@code key} and {@code otherKeys} and store result in destination {@code destKey}.
*
* @param key must not be {@literal null}.
* @param otherKeys must not be {@literal null}.
* @param destKey must not be {@literal null}.
* @param aggregate must not be {@literal null}.
* @param weights must not be {@literal null}.
* @return
* @since 2.1
* @see <a href="https://redis.io/commands/zinterstore">Redis Documentation: ZINTERSTORE</a>
*/
Mono<Long> intersectAndStore(K key, Collection<K> otherKeys, K destKey, Aggregate aggregate, Weights weights);
/**
* Get all elements with lexicographical ordering from {@literal ZSET} at {@code key} with a value between
* {@link Range#getLowerBound()} and {@link Range#getUpperBound()}.