/* * Copyright 2016-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.data.redis.connection; import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Optional; import org.reactivestreams.Publisher; import org.springframework.data.domain.Range; import org.springframework.data.redis.connection.ReactiveRedisConnection.BooleanResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.ByteBufferResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.Command; import org.springframework.data.redis.connection.ReactiveRedisConnection.CommandResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.KeyCommand; import org.springframework.data.redis.connection.ReactiveRedisConnection.MultiValueResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.NumericResponse; import org.springframework.data.redis.connection.ReactiveRedisConnection.RangeCommand; import org.springframework.data.redis.connection.RedisStringCommands.BitOperation; import org.springframework.data.redis.connection.RedisStringCommands.SetOption; import org.springframework.data.redis.core.types.Expiration; import org.springframework.util.Assert; /** * Redis String commands executed using reactive infrastructure. * * @author Christoph Strobl * @author Mark Paluch * @since 2.0 */ public interface ReactiveStringCommands { /** * {@code SET} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/set">Redis Documentation: SET</a> */ class SetCommand extends KeyCommand { private ByteBuffer value; private Expiration expiration; private SetOption option; private SetCommand(ByteBuffer key, ByteBuffer value, Expiration expiration, SetOption option) { super(key); this.value = value; this.expiration = expiration; this.option = option; } /** * Creates a new {@link SetCommand} given a {@literal key}. * * @param key must not be {@literal null}. * @return a new {@link SetCommand} for a {@literal key}. */ public static SetCommand set(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new SetCommand(key, null, null, null); } /** * Applies the {@literal value}. Constructs a new command instance with all previously configured properties. * * @param value must not be {@literal null}. * @return a new {@link SetCommand} with {@literal value} applied. */ public SetCommand value(ByteBuffer value) { Assert.notNull(value, "Value must not be null!"); return new SetCommand(getKey(), value, expiration, option); } /** * Applies {@link Expiration}. Constructs a new command instance with all previously configured properties. * * @param expiration must not be {@literal null}. * @return a new {@link SetCommand} with {@link Expiration} applied. */ public SetCommand expiring(Expiration expiration) { Assert.notNull(expiration, "Expiration must not be null!"); return new SetCommand(getKey(), value, expiration, option); } /** * Applies {@link SetOption}. Constructs a new command instance with all previously configured properties. * * @param option must not be {@literal null}. * @return a new {@link SetCommand} with {@link SetOption} applied. */ public SetCommand withSetOption(SetOption option) { Assert.notNull(option, "SetOption must not be null!"); return new SetCommand(getKey(), value, expiration, option); } /** * @return */ public ByteBuffer getValue() { return value; } /** * @return */ public Optional<Expiration> getExpiration() { return Optional.ofNullable(expiration); } /** * @return */ public Optional<SetOption> getOption() { return Optional.ofNullable(option); } } /** * Set {@literal value} for {@literal key}. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/set">Redis Documentation: SET</a> */ default Mono<Boolean> set(ByteBuffer key, ByteBuffer value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); return set(Mono.just(SetCommand.set(key).value(value))).next().map(BooleanResponse::getOutput); } /** * Set {@literal value} for {@literal key} with {@literal expiration} and {@literal options}. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @param expiration must not be {@literal null}. * @param option must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/set">Redis Documentation: SET</a> */ default Mono<Boolean> set(ByteBuffer key, ByteBuffer value, Expiration expiration, SetOption option) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); return set(Mono.just(SetCommand.set(key).value(value).withSetOption(option).expiring(expiration))).next() .map(BooleanResponse::getOutput); } /** * Set each and every item separately by invoking {@link SetCommand}. * * @param commands must not be {@literal null}. * @return {@link Flux} of {@link BooleanResponse} holding the {@link SetCommand} along with the command result. * @see <a href="http://redis.io/commands/set">Redis Documentation: SET</a> */ Flux<BooleanResponse<SetCommand>> set(Publisher<SetCommand> commands); /** * Get single element stored at {@literal key}. * * @param key must not be {@literal null}. * @return empty {@link ByteBuffer} in case {@literal key} does not exist. * @see <a href="http://redis.io/commands/get">Redis Documentation: GET</a> */ default Mono<ByteBuffer> get(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return get(Mono.just(new KeyCommand(key))).next().map(CommandResponse::getOutput); } /** * Get elements one by one. * * @param keys must not be {@literal null}. * @return {@link Flux} of {@link ByteBufferResponse} holding the {@literal key} to get along with the value * retrieved. * @see <a href="http://redis.io/commands/get">Redis Documentation: GET</a> */ Flux<ByteBufferResponse<KeyCommand>> get(Publisher<KeyCommand> keys); /** * Set {@literal value} for {@literal key} and return the existing value. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/getset">Redis Documentation: GETSET</a> */ default Mono<ByteBuffer> getSet(ByteBuffer key, ByteBuffer value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); return getSet(Mono.just(SetCommand.set(key).value(value))).next().map(ByteBufferResponse::getOutput); } /** * Set {@literal value} for {@literal key} and return the existing value one by one. * * @param commands must not be {@literal null}. * @return {@link Flux} of {@link ByteBufferResponse} holding the {@link SetCommand} along with the previously * existing value. * @see <a href="http://redis.io/commands/getset">Redis Documentation: GETSET</a> */ Flux<ByteBufferResponse<SetCommand>> getSet(Publisher<SetCommand> commands); /** * Get multiple values in one batch. * * @param keys must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/mget">Redis Documentation: MGET</a> */ default Mono<List<ByteBuffer>> mGet(List<ByteBuffer> keys) { Assert.notNull(keys, "Keys must not be null!"); return mGet(Mono.just(keys)).next().map(MultiValueResponse::getOutput); } /** * Get multiple values at for {@literal keysets} in batches. * * @param keysets must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/mget">Redis Documentation: MGET</a> */ Flux<MultiValueResponse<List<ByteBuffer>, ByteBuffer>> mGet(Publisher<List<ByteBuffer>> keysets); /** * Set {@literal value} for {@literal key}, only if {@literal key} does not exist. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/setnx">Redis Documentation: SETNX</a> */ default Mono<Boolean> setNX(ByteBuffer key, ByteBuffer value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); return setNX(Mono.just(SetCommand.set(key).value(value))).next().map(BooleanResponse::getOutput); } /** * Set {@literal key value} pairs, only if {@literal key} does not exist. * * @param values must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/setnx">Redis Documentation: SETNX</a> */ Flux<BooleanResponse<SetCommand>> setNX(Publisher<SetCommand> values); /** * Set {@literal key value} pair and {@link Expiration}. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @param expireTimeout must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/setex">Redis Documentation: SETEX</a> */ default Mono<Boolean> setEX(ByteBuffer key, ByteBuffer value, Expiration expireTimeout) { Assert.notNull(key, "Keys must not be null!"); Assert.notNull(value, "Keys must not be null!"); Assert.notNull(expireTimeout, "ExpireTimeout must not be null!"); return setEX(Mono.just(SetCommand.set(key).value(value).expiring(expireTimeout))).next() .map(BooleanResponse::getOutput); } /** * Set {@literal key value} pairs and {@link Expiration}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/setex">Redis Documentation: SETEX</a> */ Flux<BooleanResponse<SetCommand>> setEX(Publisher<SetCommand> commands); /** * Set {@literal key value} pair and {@link Expiration}. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @param expireTimeout must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/psetex">Redis Documentation: PSETEX</a> */ default Mono<Boolean> pSetEX(ByteBuffer key, ByteBuffer value, Expiration expireTimeout) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); Assert.notNull(key, "ExpireTimeout must not be null!"); return pSetEX(Mono.just(SetCommand.set(key).value(value).expiring(expireTimeout))).next() .map(BooleanResponse::getOutput); } /** * Set {@literal key value} pairs and {@link Expiration}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/psetex">Redis Documentation: PSETEX</a> */ Flux<BooleanResponse<SetCommand>> pSetEX(Publisher<SetCommand> commands); /** * {@code MSET} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/mset">Redis Documentation: MSET</a> */ class MSetCommand implements Command { private Map<ByteBuffer, ByteBuffer> keyValuePairs; private MSetCommand(Map<ByteBuffer, ByteBuffer> keyValuePairs) { this.keyValuePairs = keyValuePairs; } /* (non-Javadoc) * @see org.springframework.data.redis.connection.ReactiveRedisConnection.Command#getKey() */ @Override public ByteBuffer getKey() { return null; } /** * Creates a new {@link MSetCommand} given a {@link Map} of key-value tuples. * * @param keyValuePairs must not be {@literal null}. * @return a new {@link MSetCommand} for a {@link Map} of key-value tuples. */ public static MSetCommand mset(Map<ByteBuffer, ByteBuffer> keyValuePairs) { Assert.notNull(keyValuePairs, "Key-value pairs must not be null!"); return new MSetCommand(keyValuePairs); } /** * @return */ public Map<ByteBuffer, ByteBuffer> getKeyValuePairs() { return keyValuePairs; } } /** * Set multiple keys to multiple values using key-value pairs provided in {@literal tuple}. * * @param keyValuePairs must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/mset">Redis Documentation: MSET</a> */ default Mono<Boolean> mSet(Map<ByteBuffer, ByteBuffer> keyValuePairs) { Assert.notNull(keyValuePairs, "Key-value pairs must not be null!"); return mSet(Mono.just(MSetCommand.mset(keyValuePairs))).next().map(BooleanResponse::getOutput); } /** * Set multiple keys to multiple values using key-value pairs provided in {@literal commands}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/mset">Redis Documentation: MSET</a> */ Flux<BooleanResponse<MSetCommand>> mSet(Publisher<MSetCommand> commands); /** * Set multiple keys to multiple values using key-value pairs provided in {@literal keyValuePairs} only if the * provided key does not exist. * * @param keyValuePairs must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/msetnx">Redis Documentation: MSETNX</a> */ default Mono<Boolean> mSetNX(Map<ByteBuffer, ByteBuffer> keyValuePairs) { Assert.notNull(keyValuePairs, "Key-value pairs must not be null!"); return mSetNX(Mono.just(MSetCommand.mset(keyValuePairs))).next().map(BooleanResponse::getOutput); } /** * Set multiple keys to multiple values using key-value pairs provided in {@literal tuples} only if the provided key * does not exist. * * @param source must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/msetnx">Redis Documentation: MSETNX</a> */ Flux<BooleanResponse<MSetCommand>> mSetNX(Publisher<MSetCommand> source); /** * {@code APPEND} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/append">Redis Documentation: APPEND</a> */ class AppendCommand extends KeyCommand { private ByteBuffer value; private AppendCommand(ByteBuffer key, ByteBuffer value) { super(key); this.value = value; } /** * Creates a new {@link AppendCommand} given a {@literal key}. * * @param key must not be {@literal null}. * @return a new {@link AppendCommand} for a {@literal key}. */ public static AppendCommand key(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new AppendCommand(key, null); } /** * Applies the {@literal value} to append. Constructs a new command instance with all previously configured * properties. * * @param value must not be {@literal null}. * @return a new {@link AppendCommand} with {@literal value} applied. */ public AppendCommand append(ByteBuffer value) { Assert.notNull(value, "Value must not be null!"); return new AppendCommand(getKey(), value); } /** * @return */ public ByteBuffer getValue() { return value; } } /** * Append a {@literal value} to {@literal key}. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/append">Redis Documentation: APPEND</a> */ default Mono<Long> append(ByteBuffer key, ByteBuffer value) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); return append(Mono.just(AppendCommand.key(key).append(value))).next().map(NumericResponse::getOutput); } /** * Append a {@link AppendCommand#getValue()} to the {@link AppendCommand#getKey()}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/append">Redis Documentation: APPEND</a> */ Flux<NumericResponse<AppendCommand, Long>> append(Publisher<AppendCommand> commands); /** * Get a substring of value of {@literal key} between {@literal begin} and {@literal end}. * * @param key must not be {@literal null}. * @param begin * @param end * @return * @see <a href="http://redis.io/commands/getrange">Redis Documentation: GETRANGE</a> */ default Mono<ByteBuffer> getRange(ByteBuffer key, long begin, long end) { Assert.notNull(key, "Key must not be null!"); return getRange(Mono.just(RangeCommand.key(key).fromIndex(begin).toIndex(end))) // .next() // .map(ByteBufferResponse::getOutput); } /** * Get a substring of value of {@literal key} between {@literal begin} and {@literal end}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/getrange">Redis Documentation: GETRANGE</a> */ Flux<ByteBufferResponse<RangeCommand>> getRange(Publisher<RangeCommand> commands); /** * {@code SETRANGE} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/setrange">Redis Documentation: SETRANGE</a> */ class SetRangeCommand extends KeyCommand { private ByteBuffer value; private Long offset; private SetRangeCommand(ByteBuffer key, ByteBuffer value, Long offset) { super(key); this.value = value; this.offset = offset; } /** * Creates a new {@link SetRangeCommand} given a {@literal key}. * * @param key must not be {@literal null}. * @return a new {@link SetRangeCommand} for a {@literal key}. */ public static SetRangeCommand overwrite(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new SetRangeCommand(key, null, null); } /** * Applies the {@literal value}. Constructs a new command instance with all previously configured properties. * * @param value must not be {@literal null}. * @return a new {@link SetCommand} with {@literal value} applied. */ public SetRangeCommand withValue(ByteBuffer value) { Assert.notNull(value, "Value must not be null!"); return new SetRangeCommand(getKey(), value, offset); } /** * Applies the {@literal index}. Constructs a new command instance with all previously configured properties. * * @param index * @return a new {@link SetRangeCommand} with {@literal key} applied. */ public SetRangeCommand atPosition(long index) { return new SetRangeCommand(getKey(), value, index); } /** * @return */ public ByteBuffer getValue() { return value; } /** * @return */ public Long getOffset() { return offset; } } /** * Overwrite parts of {@literal key} starting at the specified {@literal offset} with given {@literal value}. * * @param key must not be {@literal null}. * @param value must not be {@literal null}. * @param offset * @return * @see <a href="http://redis.io/commands/setrange">Redis Documentation: SETRANGE</a> */ default Mono<Long> setRange(ByteBuffer key, ByteBuffer value, long offset) { Assert.notNull(key, "Key must not be null!"); Assert.notNull(value, "Value must not be null!"); return setRange(Mono.just(SetRangeCommand.overwrite(key).withValue(value).atPosition(offset))).next() .map(NumericResponse::getOutput); } /** * Overwrite parts of {@link SetRangeCommand#key} starting at the specified {@literal offset} with given * {@link SetRangeCommand#value}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/setrange">Redis Documentation: SETRANGE</a> */ Flux<NumericResponse<SetRangeCommand, Long>> setRange(Publisher<SetRangeCommand> commands); /** * {@code GETBIT} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/getbit">Redis Documentation: GETBIT</a> */ class GetBitCommand extends KeyCommand { private Long offset; private GetBitCommand(ByteBuffer key, Long offset) { super(key); this.offset = offset; } /** * Creates a new {@link GetBitCommand} given a {@literal key}. * * @param key must not be {@literal null}. * @return a new {@link GetBitCommand} for a {@literal key}. */ public static GetBitCommand bit(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new GetBitCommand(key, null); } /** * Applies the offset {@literal index}. Constructs a new command instance with all previously configured properties. * * @param offset * @return a new {@link GetBitCommand} with {@literal offset} applied. */ public GetBitCommand atOffset(long offset) { return new GetBitCommand(getKey(), offset); } /** * @return */ public Long getOffset() { return offset; } } /** * Get the bit value at {@literal offset} of value at {@literal key}. * * @param key must not be {@literal null}. * @param offset * @return * @see <a href="http://redis.io/commands/getbit">Redis Documentation: GETBIT</a> */ default Mono<Boolean> getBit(ByteBuffer key, long offset) { Assert.notNull(key, "Key must not be null!"); return getBit(Mono.just(GetBitCommand.bit(key).atOffset(offset))).next().map(BooleanResponse::getOutput); } /** * Get the bit value at {@literal offset} of value at {@literal key}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/getbit">Redis Documentation: GETBIT</a> */ Flux<BooleanResponse<GetBitCommand>> getBit(Publisher<GetBitCommand> commands); /** * {@code SETBIT} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/setbit">Redis Documentation: SETBIT</a> */ class SetBitCommand extends KeyCommand { private Long offset; private boolean value; private SetBitCommand(ByteBuffer key, Long offset, boolean value) { super(key); this.offset = offset; this.value = value; } /** * Creates a new {@link SetBitCommand} given a {@literal key}. * * @param key must not be {@literal null}. * @return a new {@link SetBitCommand} for a {@literal key}. */ public static SetBitCommand bit(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new SetBitCommand(key, null, false); } /** * Applies the offset {@literal index}. Constructs a new command instance with all previously configured properties. * * @param index * @return a new {@link SetBitCommand} with {@literal offset} applied. */ public SetBitCommand atOffset(long index) { return new SetBitCommand(getKey(), index, value); } /** * Applies the {@literal bit}. Constructs a new command instance with all previously configured properties. * * @param bit * @return a new {@link SetBitCommand} with {@literal offset} applied. */ public SetBitCommand to(boolean bit) { return new SetBitCommand(getKey(), offset, bit); } /** * @return */ public Long getOffset() { return offset; } /** * @return */ public boolean getValue() { return value; } } /** * Sets the bit at {@literal offset} in value stored at {@literal key} and return the original value. * * @param key must not be {@literal null}. * @param offset * @param value * @return */ default Mono<Boolean> setBit(ByteBuffer key, long offset, boolean value) { Assert.notNull(key, "Key must not be null!"); return setBit(Mono.just(SetBitCommand.bit(key).atOffset(offset).to(value))).next().map(BooleanResponse::getOutput); } /** * Sets the bit at {@literal offset} in value stored at {@literal key} and return the original value. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/setbit">Redis Documentation: SETBIT</a> */ Flux<BooleanResponse<SetBitCommand>> setBit(Publisher<SetBitCommand> commands); /** * {@code BITCOUNT} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/bitcount">Redis Documentation: BITCOUNT</a> */ class BitCountCommand extends KeyCommand { private Range<Long> range; private BitCountCommand(ByteBuffer key, Range<Long> range) { super(key); this.range = range; } /** * Creates a new {@link BitCountCommand} given a {@literal key}. * * @param key must not be {@literal null}. * @return a new {@link BitCountCommand} for a {@literal key}. */ public static BitCountCommand bitCount(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return new BitCountCommand(key, null); } /** * Applies the {@link Range}. Constructs a new command instance with all previously configured properties. * * @param range must not be {@literal null}. * @return a new {@link BitCountCommand} with {@link Range} applied. */ public BitCountCommand within(Range<Long> range) { Assert.notNull(range, "Range must not be null!"); return new BitCountCommand(getKey(), range); } /** * @return */ public Range<Long> getRange() { return range; } } /** * Count the number of set bits (population counting) in value stored at {@literal key}. * * @param key must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/bitcount">Redis Documentation: BITCOUNT</a> */ default Mono<Long> bitCount(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return bitCount(Mono.just(BitCountCommand.bitCount(key))).next().map(NumericResponse::getOutput); } /** * Count the number of set bits (population counting) of value stored at {@literal key} between {@literal begin} and * {@literal end}. * * @param key must not be {@literal null}. * @param begin * @param end * @return * @see <a href="http://redis.io/commands/bitcount">Redis Documentation: BITCOUNT</a> */ default Mono<Long> bitCount(ByteBuffer key, long begin, long end) { Assert.notNull(key, "Key must not be null!"); return bitCount(Mono.just(BitCountCommand.bitCount(key).within(new Range<>(begin, end)))).next() .map(NumericResponse::getOutput); } /** * Count the number of set bits (population counting) of value stored at {@literal key} between {@literal begin} and * {@literal end}. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/bitcount">Redis Documentation: BITCOUNT</a> */ Flux<NumericResponse<BitCountCommand, Long>> bitCount(Publisher<BitCountCommand> commands); /** * {@code BITOP} command parameters. * * @author Christoph Strobl * @see <a href="http://redis.io/commands/bitop">Redis Documentation: BITOP</a> */ class BitOpCommand { private List<ByteBuffer> keys; private BitOperation bitOp; private ByteBuffer destinationKey; private BitOpCommand(List<ByteBuffer> keys, BitOperation bitOp, ByteBuffer destinationKey) { this.keys = keys; this.bitOp = bitOp; this.destinationKey = destinationKey; } /** * Creates a new {@link BitOpCommand} given a {@link BitOperation}. * * @param bitOp must not be {@literal null}. * @return a new {@link BitCountCommand} for a {@link BitOperation}. */ public static BitOpCommand perform(BitOperation bitOp) { Assert.notNull(bitOp, "BitOperation must not be null!"); return new BitOpCommand(null, bitOp, null); } /** * Applies the operation to {@literal keys}. Constructs a new command instance with all previously configured * properties. * * @param keys must not be {@literal null}. * @return a new {@link BitOpCommand} with {@link Range} applied. */ public BitOpCommand onKeys(Collection<ByteBuffer> keys) { Assert.notNull(keys, "Keys must not be null!"); return new BitOpCommand(new ArrayList<>(keys), bitOp, destinationKey); } /** * Applies the {@literal key} to store the result at. Constructs a new command instance with all previously * configured properties. * * @param destinationKey must not be {@literal null}. * @return a new {@link BitOpCommand} with {@link Range} applied. */ public BitOpCommand andSaveAs(ByteBuffer destinationKey) { Assert.notNull(destinationKey, "Destination key must not be null!"); return new BitOpCommand(keys, bitOp, destinationKey); } /** * @return */ public BitOperation getBitOp() { return bitOp; } /** * @return */ public List<ByteBuffer> getKeys() { return keys; } /** * @return */ public ByteBuffer getDestinationKey() { return destinationKey; } } /** * Perform bitwise operations between strings. * * @param keys must not be {@literal null}. * @param bitOp must not be {@literal null}. * @param destination must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/bitop">Redis Documentation: BITOP</a> */ default Mono<Long> bitOp(Collection<ByteBuffer> keys, BitOperation bitOp, ByteBuffer destination) { Assert.notNull(keys, "Keys must not be null!"); Assert.notNull(bitOp, "BitOperation must not be null!"); Assert.notNull(destination, "Destination must not be null!"); return bitOp(Mono.just(BitOpCommand.perform(bitOp).onKeys(keys).andSaveAs(destination))) // .next() // .map(NumericResponse::getOutput); } /** * Perform bitwise operations between strings. * * @param commands must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/bitop">Redis Documentation: BITOP</a> */ Flux<NumericResponse<BitOpCommand, Long>> bitOp(Publisher<BitOpCommand> commands); /** * Get the length of the value stored at {@literal key}. * * @param key must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/strlen">Redis Documentation: STRLEN</a> */ default Mono<Long> strLen(ByteBuffer key) { Assert.notNull(key, "Key must not be null!"); return strLen(Mono.just(new KeyCommand(key))).next().map(NumericResponse::getOutput); } /** * Get the length of the value stored at {@literal key}. * * @param keys must not be {@literal null}. * @return * @see <a href="http://redis.io/commands/strlen">Redis Documentation: STRLEN</a> */ Flux<NumericResponse<KeyCommand, Long>> strLen(Publisher<KeyCommand> keys); }