Correctly apply Reactive zadd NX/XX command flags.

We now correctly apply if exists/if not exists constraints on the reactive zadd command.

Previously, we only considered upsert which wasn't sufficient to apply xx/nx.

Closes #2731
This commit is contained in:
Mark Paluch
2023-10-12 10:03:02 +02:00
parent 05e32f8f2f
commit bb1d129b40
3 changed files with 245 additions and 78 deletions

View File

@@ -19,14 +19,20 @@ import static org.assertj.core.api.Assertions.*;
import static org.assertj.core.api.Assumptions.*;
import static org.springframework.data.domain.Range.Bound.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.Arrays;
import java.util.function.Function;
import org.springframework.data.domain.Range;
import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse;
import org.springframework.data.redis.connection.ReactiveZSetCommands.ZAddCommand;
import org.springframework.data.redis.connection.zset.DefaultTuple;
import org.springframework.data.redis.connection.zset.Tuple;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.test.condition.EnabledOnCommand;
import org.springframework.data.redis.test.extension.parametrized.ParameterizedRedisTest;
@@ -55,6 +61,149 @@ public class LettuceReactiveZSetCommandsIntegrationTests extends LettuceReactive
assertThat(connection.zSetCommands().zAdd(KEY_1_BBUFFER, 3.5D, VALUE_1_BBUFFER).block()).isEqualTo(1L);
}
@ParameterizedRedisTest // GH-2731
void zAddShouldConsiderAbsentPresentUpsertFlags() {
Tuple tuple = Tuple.of(VALUE_1_BYTES, 3.5D);
zAdd(KEY_1_BBUFFER, tuple, Function.identity()).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(1) //
.verifyComplete();
// NX
zAdd(KEY_1_BBUFFER, tuple, ZAddCommand::nx).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
zAdd(KEY_2_BBUFFER, tuple, ZAddCommand::nx).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(1) //
.verifyComplete();
// XX
zAdd(KEY_1_BBUFFER, Tuple.of(VALUE_1_BYTES, 3.0D), ZAddCommand::xx).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
connection.zSetCommands().zScore(KEY_1_BBUFFER, VALUE_1_BBUFFER).map(Number::doubleValue) //
.as(StepVerifier::create) //
.expectNext(3.0) //
.verifyComplete();
zAdd(KEY_3_BBUFFER, tuple, ZAddCommand::xx).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
}
@ParameterizedRedisTest // GH-2731
void zAddShouldConsiderLessThan() {
Tuple tuple = Tuple.of(VALUE_1_BYTES, 3.5D);
zAdd(KEY_1_BBUFFER, tuple, Function.identity()).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(1) //
.verifyComplete();
zAdd(KEY_1_BBUFFER, Tuple.of(VALUE_1_BYTES, 6D), ZAddCommand::lt).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
connection.zSetCommands().zScore(KEY_1_BBUFFER, VALUE_1_BBUFFER).map(Number::doubleValue) //
.as(StepVerifier::create) //
.expectNext(3.5) //
.verifyComplete();
zAdd(KEY_1_BBUFFER, Tuple.of(VALUE_1_BYTES, 1D), ZAddCommand::lt).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
connection.zSetCommands().zScore(KEY_1_BBUFFER, VALUE_1_BBUFFER).map(Number::doubleValue) //
.as(StepVerifier::create) //
.expectNext(1.0) //
.verifyComplete();
}
@ParameterizedRedisTest // GH-2731
void zAddShouldConsiderGreaterThan() {
Tuple tuple = Tuple.of(VALUE_1_BYTES, 3.5D);
zAdd(KEY_1_BBUFFER, tuple, Function.identity()).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(1) //
.verifyComplete();
zAdd(KEY_1_BBUFFER, Tuple.of(VALUE_1_BYTES, 1D), ZAddCommand::gt).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
connection.zSetCommands().zScore(KEY_1_BBUFFER, VALUE_1_BBUFFER).map(Number::doubleValue) //
.as(StepVerifier::create) //
.expectNext(3.5) //
.verifyComplete();
zAdd(KEY_1_BBUFFER, Tuple.of(VALUE_1_BYTES, 6D), ZAddCommand::gt).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
connection.zSetCommands().zScore(KEY_1_BBUFFER, VALUE_1_BBUFFER).map(Number::doubleValue) //
.as(StepVerifier::create) //
.expectNext(6.0) //
.verifyComplete();
}
@ParameterizedRedisTest // GH-2731
void zAddShouldConsiderIncrFlag() {
Tuple tuple = Tuple.of(VALUE_1_BYTES, 3.5D);
zAdd(KEY_1_BBUFFER, tuple, Function.identity()).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(1) //
.verifyComplete();
zAdd(KEY_1_BBUFFER, tuple, ZAddCommand::incr).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(7) //
.verifyComplete();
}
@ParameterizedRedisTest // GH-2731
void zAddShouldConsiderChFlag() {
Tuple tuple = Tuple.of(VALUE_1_BYTES, 3.5D);
zAdd(KEY_1_BBUFFER, tuple, Function.identity()).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(1) //
.verifyComplete();
zAdd(KEY_1_BBUFFER, tuple, ZAddCommand::ch).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(0) //
.verifyComplete();
zAdd(KEY_1_BBUFFER, Tuple.of(VALUE_1_BYTES, 3.0D), ZAddCommand::ch).map(Number::intValue) //
.as(StepVerifier::create) //
.expectNext(1) //
.verifyComplete();
}
private Flux<Number> zAdd(ByteBuffer key, Tuple tuple, Function<ZAddCommand, ZAddCommand> commandCustomizer) {
return connection.zSetCommands().zAdd(Mono.just(commandCustomizer.apply(ZAddCommand.tuple(tuple).to(key))))
.map(NumericResponse::getOutput);
}
@ParameterizedRedisTest // DATAREDIS-525
void zRemShouldRemoveValuesFromSet() {