All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.redisson.spring.data.connection.RedissonReactiveKeyCommands Maven / Gradle / Ivy

There is a newer version: 3.39.0
Show newest version
/**
 * Copyright (c) 2013-2024 Nikita Koksharov
 *
 * 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.redisson.spring.data.connection;

import org.reactivestreams.Publisher;
import org.redisson.client.codec.ByteArrayCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.client.protocol.convertor.BooleanReplayConvertor;
import org.redisson.client.protocol.convertor.Convertor;
import org.redisson.reactive.CommandReactiveExecutor;
import org.redisson.reactive.RedissonKeysReactive;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.connection.ReactiveKeyCommands;
import org.springframework.data.redis.connection.ReactiveRedisConnection.*;
import org.springframework.data.redis.connection.ValueEncoding;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.util.Assert;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 
 * @author Nikita Koksharov
 *
 */
public class RedissonReactiveKeyCommands extends RedissonBaseReactive implements ReactiveKeyCommands {

    public RedissonReactiveKeyCommands(CommandReactiveExecutor executorService) {
        super(executorService);
    }

    @Override
    public Flux> exists(Publisher keys) {
        return execute(keys, key -> {

            Assert.notNull(key.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(key.getKey());
            Mono m = read(keyBuf, StringCodec.INSTANCE, RedisCommands.EXISTS, keyBuf);
            return m.map(v -> new BooleanResponse<>(key, v));
        });
    }
    
    private static final RedisStrictCommand TYPE = new RedisStrictCommand("TYPE", new Convertor() {
        @Override
        public DataType convert(Object obj) {
            return DataType.fromCode(obj.toString());
        }
    });

    @Override
    public Flux> type(Publisher keys) {
        return execute(keys, key -> {

            Assert.notNull(key.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(key.getKey());
            Mono m = read(keyBuf, StringCodec.INSTANCE, TYPE, keyBuf);
            return m.map(v -> new CommandResponse<>(key, v));
        });
    }
    
    @Override
    public Flux, Long>> touch(Publisher> keys) {
        return execute(keys, coll -> {

            Assert.notNull(coll, "Collection must not be null!");
            
            Object[] params = coll.stream().map(buf -> toByteArray(buf)).toArray(Object[]::new);

            Mono m = write(null, StringCodec.INSTANCE, RedisCommands.TOUCH_LONG, params);
            return m.map(v -> new NumericResponse<>(coll, v));
        });
    }

    @Override
    public Flux> keys(Publisher patterns) {
        return execute(patterns, pattern -> {

            Assert.notNull(pattern, "Pattern must not be null!");

            Mono> m = read(null, StringCodec.INSTANCE, RedisCommands.KEYS, toByteArray(pattern));
            return m.map(v -> {
                List values = v.stream().map(t -> ByteBuffer.wrap(t.getBytes())).collect(Collectors.toList());
                return new MultiValueResponse<>(pattern, values);   
            });
        });
    }

    @Override
    public Flux scan(ScanOptions options) {
        RedissonKeysReactive reactive = new RedissonKeysReactive(executorService);
        return reactive.getKeysByPattern(options.getPattern(), options.getCount().intValue()).map(t -> ByteBuffer.wrap(t.getBytes()));
    }

    @Override
    public Mono randomKey() {
        return executorService.reactive(() -> {
            return executorService.readRandomAsync(ByteArrayCodec.INSTANCE, RedisCommands.RANDOM_KEY);
        });
    }

    static final RedisStrictCommand RENAME = new RedisStrictCommand("RENAME");
    
    @Override
    public Flux> rename(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");
            Assert.notNull(command.getNewKey(), "New name must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            byte[] newKeyBuf = toByteArray(command.getNewKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RENAME, keyBuf, newKeyBuf);
            return m.map(v -> new BooleanResponse<>(command, true));
        });
    }

    @Override
    public Flux> renameNX(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");
            Assert.notNull(command.getNewKey(), "New name must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            byte[] newKeyBuf = toByteArray(command.getNewKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.RENAMENX, keyBuf, newKeyBuf);
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }

    @Override
    public Flux> del(Publisher keys) {
        Flux s = Flux.from(keys);
        return s.concatMap(command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.DEL, keyBuf);
            return m.map(v -> new NumericResponse<>(command, v));
        });
    }

    @Override
    public Flux, Long>> mDel(Publisher> keys) {
        return execute(keys, coll -> {

            Assert.notNull(coll, "List must not be null!");
            
            Object[] params = coll.stream().map(buf -> toByteArray(buf)).toArray(Object[]::new);

            Mono m = write(null, StringCodec.INSTANCE, RedisCommands.DEL, params);
            return m.map(v -> new NumericResponse<>(coll, v));
        });
    }

    @Override
    public Flux> unlink(Publisher keys) {
        return execute(keys, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.UNLINK, keyBuf);
            return m.map(v -> new NumericResponse<>(command, v));
        });
   }

    @Override
    public Flux, Long>> mUnlink(Publisher> keys) {
        return execute(keys, coll -> {

            Assert.notNull(coll, "List must not be null!");
            
            Object[] params = coll.stream().map(buf -> toByteArray(buf)).toArray(Object[]::new);

            Mono m = write(null, StringCodec.INSTANCE, RedisCommands.UNLINK, params);
            return m.map(v -> new NumericResponse<>(coll, v));
        });
    }

    private static final RedisStrictCommand EXPIRE = new RedisStrictCommand("EXPIRE", new BooleanReplayConvertor());
    
    @Override
    public Flux> expire(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, EXPIRE, keyBuf, command.getTimeout().getSeconds());
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }

    @Override
    public Flux> pExpire(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");
            Assert.notNull(command.getTimeout(), "Timeout must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.PEXPIRE, keyBuf, command.getTimeout().toMillis());
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }

    private static final RedisStrictCommand EXPIREAT = new RedisStrictCommand("EXPIREAT", new BooleanReplayConvertor());
    
    @Override
    public Flux> expireAt(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, EXPIREAT, keyBuf, command.getExpireAt().getEpochSecond());
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }

    @Override
    public Flux> pExpireAt(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.PEXPIREAT, keyBuf, command.getExpireAt().toEpochMilli());
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }

    @Override
    public Flux> persist(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.PERSIST, keyBuf);
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }
    
    private static final RedisStrictCommand TTL = new RedisStrictCommand("TTL");

    @Override
    public Flux> ttl(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = read(keyBuf, StringCodec.INSTANCE, TTL, keyBuf);
            return m.map(v -> new NumericResponse<>(command, v));
        });
    }

    @Override
    public Flux> pTtl(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = read(keyBuf, StringCodec.INSTANCE, RedisCommands.PTTL, keyBuf);
            return m.map(v -> new NumericResponse<>(command, v));
        });
    }

    @Override
    public Flux> move(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");
            Assert.notNull(command.getDatabase(), "Database must not be null!");

            byte[] keyBuf = toByteArray(command.getKey());
            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.MOVE, keyBuf, command.getDatabase());
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }
    
    private static final RedisStrictCommand OBJECT_ENCODING = new RedisStrictCommand("OBJECT", "ENCODING", new Convertor() {
        @Override
        public ValueEncoding convert(Object obj) {
            return ValueEncoding.of((String) obj);
        }
    });

    @Override
    public Mono encodingOf(ByteBuffer key) {
        Assert.notNull(key, "Key must not be null!");

        byte[] keyBuf = toByteArray(key);
        return read(keyBuf, StringCodec.INSTANCE, OBJECT_ENCODING, keyBuf);
    }

    private static final RedisStrictCommand OBJECT_IDLETIME = new RedisStrictCommand("OBJECT", "IDLETIME");
    
    @Override
    public Mono idletime(ByteBuffer key) {
        Assert.notNull(key, "Key must not be null!");

        byte[] keyBuf = toByteArray(key);
        Mono m = read(keyBuf, StringCodec.INSTANCE, OBJECT_IDLETIME, keyBuf);
        return m.map(Duration::ofSeconds);
    }
    
    private static final RedisStrictCommand OBJECT_REFCOUNT = new RedisStrictCommand("OBJECT", "REFCOUNT");

    @Override
    public Mono refcount(ByteBuffer key) {
        Assert.notNull(key, "Key must not be null!");

        byte[] keyBuf = toByteArray(key);
        return read(keyBuf, StringCodec.INSTANCE, OBJECT_REFCOUNT, keyBuf);
    }

    @Override
    public Flux> copy(Publisher commands) {
        return execute(commands, command -> {

            Assert.notNull(command.getKey(), "Key must not be null!");
            Assert.notNull(command.getTarget(), "Target must not be null!");

            List params = new ArrayList<>();
            byte[] keyBuf = toByteArray(command.getKey());
            params.add(keyBuf);
            byte[] targetBuf = toByteArray(command.getTarget());
            params.add(targetBuf);
            if (command.getDatabase() != null) {
                params.add("DB");
                params.add(command.getDatabase());
            }

            Mono m = write(keyBuf, StringCodec.INSTANCE, RedisCommands.COPY, params.toArray());
            return m.map(v -> new BooleanResponse<>(command, v));
        });
    }
}