@Override public LettuceReactiveRedisConnection getReactiveConnection() { return getShareNativeConnection() ? new LettuceReactiveRedisConnection(getSharedReactiveConnection(), reactiveConnectionProvider) : new LettuceReactiveRedisConnection(reactiveConnectionProvider); }
@Override public Flux<BooleanResponse<SetCommand>> pSetEX(Publisher<SetCommand> commands) { return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null!"); Assert.notNull(command.getValue(), "Value must not be null!"); Assert.isTrue(command.getExpiration().isPresent(), "Expiration time must not be null!"); return cmd .psetex(command.getKey(), command.getExpiration().get().getExpirationTimeInMilliseconds(), command.getValue()) .map(LettuceConverters::stringToBoolean).map((value) -> new BooleanResponse<>(command, value)); })); }
@Override public Flux<PopResponse> bPop(Publisher<BPopCommand> commands) { return connection.executeDedicated(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKeys(), "Keys must not be null!"); Assert.notNull(command.getDirection(), "Direction must not be null!"); long timeout = command.getTimeout().get(ChronoUnit.SECONDS); Mono<PopResult> mappedMono = (ObjectUtils.nullSafeEquals(Direction.RIGHT, command.getDirection()) ? cmd.brpop(timeout, command.getKeys().stream().toArray(ByteBuffer[]::new)) : cmd.blpop(timeout, command.getKeys().stream().toArray(ByteBuffer[]::new))) .map(kv -> Arrays.asList(kv.getKey(), kv.getValue())).map(PopResult::new); return mappedMono.map(value -> new PopResponse(command, value)); })); }
/** * @param callback * @return * @since 2.0.1 */ public <T> Flux<T> executeDedicated(LettuceReactiveCallback<T> callback) { return getDedicatedCommands().flatMapMany(callback::doWithCommands).onErrorMap(translateException()); }
/** * @param callback * @return */ public <T> Flux<T> execute(LettuceReactiveCallback<T> callback) { return getCommands().flatMapMany(callback::doWithCommands).onErrorMap(translateException()); }
private <T> Mono<T> doWithPubSub(Function<RedisPubSubReactiveCommands<ByteBuffer, ByteBuffer>, Mono<T>> function) { return connection.getPubSubConnection().flatMap(pubSubConnection -> function.apply(pubSubConnection.reactive())) .onErrorMap(connection.translateException()); } }
@Override public Flux<CommandResponse<SRandMembersCommand, Flux<ByteBuffer>>> sRandMember( Publisher<SRandMembersCommand> commands) { return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null!"); boolean singleElement = !command.getCount().isPresent() || command.getCount().get().equals(1L); Publisher<ByteBuffer> result = singleElement ? cmd.srandmember(command.getKey()) : cmd.srandmember(command.getKey(), command.getCount().get()); return Mono.just(new CommandResponse<>(command, Flux.from(result))); })); }
@Override public Flux<CommandResponse<KeyCommand, DataType>> type(Publisher<KeyCommand> commands) { return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null!"); return cmd.type(command.getKey()).map(LettuceConverters::toDataType) .map(respValue -> new CommandResponse<>(command, respValue)); })); }
@Override public Flux<BooleanResponse<SetCommand>> set(Publisher<SetCommand> commands) { return connection.execute(cmd -> Flux.from(commands).concatMap((command) -> { Assert.notNull(command.getKey(), "Key must not be null!"); Assert.notNull(command.getValue(), "Value must not be null!"); SetArgs args = null; if (command.getExpiration().isPresent() || command.getOption().isPresent()) { args = LettuceConverters.toSetArgs(command.getExpiration().isPresent() ? command.getExpiration().get() : null, command.getOption().isPresent() ? command.getOption().get() : null); } Mono<String> mono = args != null ? cmd.set(command.getKey(), command.getValue(), args) : cmd.set(command.getKey(), command.getValue()); return mono.map(LettuceConverters::stringToBoolean).map(value -> new BooleanResponse<>(command, value)) .switchIfEmpty(Mono.just(new BooleanResponse<>(command, Boolean.FALSE))); })); }
@Override public Flux<ReactiveRedisConnection.BooleanResponse<MSetCommand>> mSetNX(Publisher<MSetCommand> commands) { return getConnection().execute(cmd -> Flux.from(commands).concatMap(command -> { if (ClusterSlotHashUtil.isSameSlotForAllKeys(command.getKeyValuePairs().keySet())) { return super.mSetNX(Mono.just(command)); } return Mono .error(new InvalidDataAccessApiUsageException("All keys must map to the same slot for MSETNX command.")); })); } }
@Override public Flux<NumericResponse<SDiffStoreCommand, Long>> sDiffStore(Publisher<SDiffStoreCommand> commands) { return getConnection().execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKeys(), "Source keys must not be null!"); Assert.notNull(command.getKey(), "Destination key must not be null!"); List<ByteBuffer> keys = new ArrayList<>(command.getKeys()); keys.add(command.getKey()); if (ClusterSlotHashUtil.isSameSlotForAllKeys(keys)) { return super.sDiffStore(Mono.just(command)); } return sDiff(Mono.just(SDiffCommand.keys(command.getKeys()))).next().flatMap(values -> { Mono<Long> result = cmd.sadd(command.getKey(), values.getOutput().toStream().toArray(ByteBuffer[]::new)); return result.map(value -> new NumericResponse<>(command, value)); }); })); }
@Override public Flux<CommandResponse<KeyCommand, Flux<ByteBuffer>>> hVals(Publisher<KeyCommand> commands) { return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null!"); Flux<ByteBuffer> result = cmd.hvals(command.getKey()); return Mono.just(new CommandResponse<>(command, result)); })); }
@Override public Flux<Long> publish(Publisher<ChannelMessage<ByteBuffer, ByteBuffer>> messageStream) { Assert.notNull(messageStream, "ChannelMessage stream must not be null!"); return connection.getCommands().flatMapMany(commands -> Flux.from(messageStream) .flatMap(message -> commands.publish(message.getChannel(), message.getMessage()))); }
@Override public Flux<CommandResponse<SDiffCommand, Flux<ByteBuffer>>> sDiff(Publisher<SDiffCommand> commands) { return getConnection().execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKeys(), "Keys must not be null!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(command.getKeys())) { return super.sDiff(Mono.just(command)); } Mono<List<ByteBuffer>> sourceSet = cmd.smembers(command.getKeys().get(0)).distinct().collectList(); List<Mono<List<ByteBuffer>>> intersectingSets = new ArrayList<>(); for (int i = 1; i < command.getKeys().size(); i++) { intersectingSets.add(cmd.smembers(command.getKeys().get(i)).distinct().collectList()); } Flux<List<ByteBuffer>> result = Flux.zip(sourceSet, Flux.merge(intersectingSets).collectList(), (source, intersectings) -> { for (List<ByteBuffer> intersecting : intersectings) { source.removeAll(intersecting); } return source; }); return Mono.just(new CommandResponse<>(command, result.concatMap(v -> Flux.fromStream(v.stream())))); })); }
@Override public Flux<CommandResponse<KeyCommand, Flux<Map.Entry<ByteBuffer, ByteBuffer>>>> hGetAll( Publisher<KeyCommand> commands) { return connection.execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKey(), "Key must not be null!"); Mono<Map<ByteBuffer, ByteBuffer>> result = cmd.hgetall(command.getKey()); return Mono.just(new CommandResponse<>(command, result.flatMapMany(v -> Flux.fromStream(v.entrySet().stream())))); })); }
@Override public Flux<CommandResponse<SUnionCommand, Flux<ByteBuffer>>> sUnion(Publisher<SUnionCommand> commands) { return getConnection().execute(cmd -> Flux.from(commands).concatMap(command -> { Assert.notNull(command.getKeys(), "Keys must not be null!"); if (ClusterSlotHashUtil.isSameSlotForAllKeys(command.getKeys())) { return super.sUnion(Mono.just(command)); } Flux<ByteBuffer> result = Flux.merge(command.getKeys().stream().map(cmd::smembers).collect(Collectors.toList())) .distinct(); return Mono.just(new CommandResponse<>(command, result)); })); }
@Override public Flux<CommandResponse<ReadCommand, Flux<ByteBufferRecord>>> read(Publisher<ReadCommand> commands) { return Flux.from(commands).map(command -> { Assert.notNull(command.getStreamOffsets(), "StreamOffsets must not be null!"); Assert.notNull(command.getReadOptions(), "ReadOptions must not be null!"); StreamReadOptions readOptions = command.getReadOptions(); if (readOptions.getBlock() != null && readOptions.getBlock() > 0) { return new CommandResponse<>(command, connection.executeDedicated(cmd -> doRead(command, readOptions, cmd))); } return new CommandResponse<>(command, connection.execute(cmd -> doRead(command, readOptions, cmd))); }); }
@SuppressWarnings("unchecked") private <T> Flux<T> convertIfNecessary(Flux<T> eval, ReturnType returnType) { if (returnType == ReturnType.MULTI) { return eval.concatMap(t -> { return t instanceof Exception ? Flux.error(connection.translateException().apply((Exception) t)) : Flux.just(t); }); } return eval; }
@Override public Mono<ReactiveSubscription> createSubscription() { return connection.getPubSubConnection() .map(pubSubConnection -> new LettuceReactiveSubscription(pubSubConnection.reactive(), connection.translateException())); }
protected Mono<? extends RedisClusterReactiveCommands<ByteBuffer, ByteBuffer>> getCommands() { if (sharedConnection != null) { return sharedConnection.map(LettuceReactiveRedisConnection::getRedisClusterReactiveCommands); } return getDedicatedCommands(); }