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

org.redisson.RedissonJsonBucket Maven / Gradle / Ivy

Go to download

Easy Redis Java client and Real-Time Data Platform. Valkey compatible. Sync/Async/RxJava3/Reactive API. Client side caching. Over 50 Redis based Java objects and services: JCache API, Apache Tomcat, Hibernate, Spring, Set, Multimap, SortedSet, Map, List, Queue, Deque, Semaphore, Lock, AtomicLong, Map Reduce, Bloom filter, Scheduler, RPC

The 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;

import org.redisson.api.JsonType;
import org.redisson.api.RFuture;
import org.redisson.api.RJsonBucket;
import org.redisson.client.codec.LongCodec;
import org.redisson.client.codec.StringCodec;
import org.redisson.client.protocol.RedisCommand;
import org.redisson.client.protocol.RedisCommands;
import org.redisson.client.protocol.RedisStrictCommand;
import org.redisson.client.protocol.convertor.JsonTypeConvertor;
import org.redisson.client.protocol.convertor.LongNumberConvertor;
import org.redisson.client.protocol.convertor.NumberConvertor;
import org.redisson.client.protocol.decoder.ListFirstObjectDecoder;
import org.redisson.client.protocol.decoder.ListMultiDecoder2;
import org.redisson.client.protocol.decoder.ObjectListReplayDecoder;
import org.redisson.client.protocol.decoder.StringListListReplayDecoder;
import org.redisson.codec.JsonCodec;
import org.redisson.codec.JsonCodecWrapper;
import org.redisson.command.CommandAsyncExecutor;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Json data holder
 *
 * @author Nikita Koksharov
 *
 */
public class RedissonJsonBucket extends RedissonExpirable implements RJsonBucket {

    public RedissonJsonBucket(JsonCodec codec, CommandAsyncExecutor connectionManager, String name) {
        super(new JsonCodecWrapper(codec), connectionManager, name);
    }


    @Override
    public long size() {
        return get(sizeAsync());
    }

    @Override
    public RFuture sizeAsync() {
        throw new UnsupportedOperationException();
    }

    @Override
    public List stringSizeMulti(String path) {
        return get(stringSizeMultiAsync(path));
    }

    @Override
    public RFuture> stringSizeMultiAsync(String path) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_STRLEN_LIST, getRawName(), path);
    }

    @Override
    public Long stringSize(String path) {
        return get(stringSizeAsync(path));
    }

    @Override
    public RFuture stringSizeAsync(String path) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_STRLEN, getRawName(), path);
    }

    @Override
    public V get() {
        return get(getAsync());
    }

    @Override
    public RFuture getAsync() {
        if (getServiceManager().isResp3()) {
            return commandExecutor.readAsync(getRawName(), codec, RedisCommands.JSON_GET, getRawName(), ".");
        }
        return commandExecutor.readAsync(getRawName(), codec, RedisCommands.JSON_GET, getRawName());
    }

    @Override
    public  T get(JsonCodec codec, String... paths) {
        return get(getAsync(codec, paths));
    }

    @Override
    public  RFuture getAsync(JsonCodec codec, String... paths) {
        if (getServiceManager().isResp3()) {
            if (paths.length == 0) {
                paths = new String[]{"."};
            }
        }

        List args = new ArrayList<>();
        args.add(getRawName());
        args.addAll(Arrays.asList(paths));
        return commandExecutor.readAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.JSON_GET, args.toArray());
    }

    @Override
    public V getAndDelete() {
        return get(getAndDeleteAsync());
    }

    @Override
    public RFuture getAndDeleteAsync() {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                "local currValue = redis.call('json.get', KEYS[1]); "
                        + "redis.call('del', KEYS[1]); "
                        + "return currValue; ",
                Collections.singletonList(getRawName()));
    }

    @Override
    public boolean setIfAbsent(V value) {
        return get(setIfAbsentAsync(value));
    }

    @Override
    public boolean setIfAbsent(V value, Duration duration) {
        return get(setIfAbsentAsync(value, duration));
    }

    @Override
    public RFuture setIfAbsentAsync(V value) {
        return setIfAbsentAsync("$", value);
    }

    @Override
    public RFuture setIfAbsentAsync(V value, Duration duration) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_BOOLEAN,
          "local currValue = redis.call('json.set', KEYS[1], '$', ARGV[1], 'NX'); " +
                "if currValue ~= false then " +
                    "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                    "return 1;" +
                "end;" +
                "return 0; ",
        Collections.singletonList(getRawName()), encode(value), duration.toMillis());
    }

    @Override
    public boolean trySet(V value) {
        return get(trySetAsync(value));
    }

    @Override
    public RFuture trySetAsync(V value) {
        return trySetAsync("$", value);
    }

    @Override
    public boolean setIfAbsent(String path, Object value) {
        return get(setIfAbsentAsync(path, value));
    }

    @Override
    public RFuture setIfAbsentAsync(String path, Object value) {
        if (value == null) {
            return commandExecutor.readAsync(getRawName(), codec, RedisCommands.NOT_EXISTS, getRawName());
        }

        return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.JSON_SET_BOOLEAN, getRawName(), path, encode(value), "NX");
    }

    @Override
    public boolean trySet(String path, Object value) {
        return get(trySetAsync(path, value));
    }

    @Override
    public RFuture trySetAsync(String path, Object value) {
        if (value == null) {
            return commandExecutor.readAsync(getRawName(), codec, RedisCommands.NOT_EXISTS, getRawName());
        }

        return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.JSON_SET_BOOLEAN, getRawName(), path, encode(value), "NX");
    }

    @Override
    public boolean trySet(V value, long timeToLive, TimeUnit timeUnit) {
        return get(trySetAsync(value, timeToLive, timeUnit));
    }

    @Override
    public RFuture trySetAsync(V value, long timeToLive, TimeUnit timeUnit) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_BOOLEAN,
                  "local currValue = redis.call('json.set', KEYS[1], '$', ARGV[1], 'NX'); " +
                        "if currValue ~= false then " +
                            "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                            "return 1;" +
                        "end;" +
                        "return 0; ",
                Collections.singletonList(getRawName()), encode(value), timeUnit.toMillis(timeToLive));
    }

    @Override
    public boolean setIfExists(V value) {
        return get(setIfExistsAsync(value));
    }

    @Override
    public RFuture setIfExistsAsync(V value) {
        return setIfExistsAsync("$", value);
    }

    @Override
    public boolean setIfExists(String path, Object value) {
        return get(setIfExistsAsync(path, value));
    }

    @Override
    public RFuture setIfExistsAsync(String path, Object value) {
        return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.JSON_SET_BOOLEAN, getRawName(), path, encode(value), "XX");
    }

    @Override
    public boolean setIfExists(V value, long timeToLive, TimeUnit timeUnit) {
        return get(setIfExistsAsync(value, timeToLive, timeUnit));
    }

    @Override
    public RFuture setIfExistsAsync(V value, long timeToLive, TimeUnit timeUnit) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_BOOLEAN,
                "local currValue = redis.call('json.set', KEYS[1], '$', ARGV[1], 'XX'); " +
                      "if currValue ~= false then " +
                         "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                         "return 1;" +
                      "end;" +
                      "return 0; ",
                Collections.singletonList(getRawName()), encode(value), timeUnit.toMillis(timeToLive));
    }

    @Override
    public boolean setIfExists(V value, Duration duration) {
        return get(setIfExistsAsync(value, duration));
    }

    @Override
    public RFuture setIfExistsAsync(V value, Duration duration) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_BOOLEAN,
                "local currValue = redis.call('json.set', KEYS[1], '$', ARGV[1], 'XX'); " +
                      "if currValue ~= false then " +
                         "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                         "return 1;" +
                      "end;" +
                      "return 0; ",
                Collections.singletonList(getRawName()), encode(value), duration.toMillis());
    }

    @Override
    public boolean compareAndSet(V expect, V update) {
        return get(compareAndSetAsync(expect, update));
    }

    @Override
    public RFuture compareAndSetAsync(V expect, V update) {
        if (expect == null && update == null) {
            return trySetAsync(null);
        }

        if (expect == null) {
            return trySetAsync(update);
        }

        return compareAndSetUpdateAsync("$", expect, update);
    }

    @Override
    public boolean compareAndSet(String path, Object expect, Object update) {
        return get(compareAndSetAsync(path, expect, update));
    }

    @Override
    public RFuture compareAndSetAsync(String path, Object expect, Object update) {
        if (path == null) {
            throw new NullPointerException("path can't be null");
        }

        if (expect == null && update == null) {
            return trySetAsync(path, null);
        }

        if (expect == null) {
            return trySetAsync(path, update);
        }

        if (path.startsWith("$")) {
            expect = Arrays.asList(expect);
        }

        return compareAndSetUpdateAsync(path, expect, update);
    }

    protected RFuture compareAndSetUpdateAsync(String path, Object expect, Object update) {
        if (update == null) {
            return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_BOOLEAN,
                    "if redis.call('json.get', KEYS[1], ARGV[1]) == ARGV[2] then "
                            + "redis.call('json.del', KEYS[1], ARGV[1]); "
                            + "return 1 "
                        + "else "
                            + "return 0 end;",
                    Collections.singletonList(getRawName()), path, encode(expect));
        }

        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_BOOLEAN,
                "if redis.call('json.get', KEYS[1], ARGV[1]) == ARGV[2] then "
                        + "redis.call('json.set', KEYS[1], ARGV[1], ARGV[3]); "
                        + "return 1 "
                    + "else "
                        + "return 0 end",
                Collections.singletonList(getRawName()), path, encode(expect), encode(update));
    }

    @Override
    public V getAndSet(V newValue) {
        return get(getAndSetAsync(newValue));
    }

    @Override
    public RFuture getAndSetAsync(V newValue) {
        if (newValue == null) {
            return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                    "local v = redis.call('json.get', KEYS[1]); " +
                          "redis.call('json.del', KEYS[1]); " +
                          "return v",
                    Collections.singletonList(getRawName()));
        }

        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                "local currValue = redis.call('json.get', KEYS[1]); " +
                      "redis.call('json.set', KEYS[1], '$', ARGV[1]); " +
                      "return currValue; ",
                Collections.singletonList(getRawName()), encode(newValue));
    }

    @Override
    public  T getAndSet(JsonCodec codec, String path, Object newValue) {
        return get(getAndSetAsync(codec, path, newValue));
    }

    @Override
    public  RFuture getAndSetAsync(JsonCodec codec, String path, Object newValue) {
        if (newValue == null) {
            return commandExecutor.evalWriteAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.EVAL_OBJECT,
                    "local v = redis.call('json.get', KEYS[1], ARGV[1]); " +
                            "redis.call('json.del', KEYS[1]); " +
                            "return v",
                    Collections.singletonList(getRawName()), path);
        }

        return commandExecutor.evalWriteAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.EVAL_OBJECT,
                "local currValue = redis.call('json.get', KEYS[1], ARGV[1]); " +
                        "redis.call('json.set', KEYS[1], ARGV[1], ARGV[2]); " +
                        "return currValue; ",
                Collections.singletonList(getRawName()), path, encode(newValue));
    }

    @Override
    public V getAndSet(V value, long timeToLive, TimeUnit timeUnit) {
        return get(getAndSetAsync(value, timeToLive, timeUnit));
    }

    @Override
    public RFuture getAndSetAsync(V value, long timeToLive, TimeUnit timeUnit) {
        if (value == null) {
            return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                    "local v = redis.call('json.get', KEYS[1]); " +
                            "redis.call('json.del', KEYS[1]); " +
                            "return v",
                    Collections.singletonList(getRawName()));
        }

        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                "local currValue = redis.call('json.get', KEYS[1]); " +
                        "redis.call('json.set', KEYS[1], '$', ARGV[1]); " +
                        "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                        "return currValue; ",
                Collections.singletonList(getRawName()), encode(value), timeUnit.toMillis(timeToLive));
    }

    @Override
    public V getAndSet(V value, Duration duration) {
        return get(getAndSetAsync(value, duration));
    }

    @Override
    public RFuture getAndSetAsync(V value, Duration duration) {
        if (value == null) {
            return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                    "local v = redis.call('json.get', KEYS[1]); " +
                            "redis.call('json.del', KEYS[1]); " +
                            "return v",
                    Collections.singletonList(getRawName()));
        }

        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                "local currValue = redis.call('json.get', KEYS[1]); " +
                        "redis.call('json.set', KEYS[1], '$', ARGV[1]); " +
                        "redis.call('pexpire', KEYS[1], ARGV[2]); " +
                        "return currValue; ",
                Collections.singletonList(getRawName()), encode(value), duration.toMillis());
    }

    @Override
    public V getAndExpire(Duration duration) {
        return get(getAndExpireAsync(duration));
    }

    @Override
    public RFuture getAndExpireAsync(Duration duration) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                   "local currValue = redis.call('json.get', KEYS[1]); " +
                        "redis.call('pexpire', KEYS[1], ARGV[1]); " +
                        "return currValue; ",
                Collections.singletonList(getRawName()), duration.toMillis());
    }

    @Override
    public V getAndExpire(Instant time) {
        return get(getAndExpireAsync(time));
    }

    @Override
    public RFuture getAndExpireAsync(Instant time) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                "local currValue = redis.call('json.get', KEYS[1]); " +
                        "redis.call('pexpireat', KEYS[1], ARGV[1]); " +
                        "return currValue; ",
                Collections.singletonList(getRawName()), time.toEpochMilli());
    }

    @Override
    public V getAndClearExpire() {
        return get(getAndClearExpireAsync());
    }

    @Override
    public RFuture getAndClearExpireAsync() {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_OBJECT,
                        "local currValue = redis.call('json.get', KEYS[1]); " +
                        "redis.call('persist', KEYS[1]); " +
                        "return currValue; ",
                Collections.singletonList(getRawName()));
    }

    @Override
    public void set(V value) {
        get(setAsync(value));
    }

    @Override
    public RFuture setAsync(V value) {
        return setAsync("$", value);
    }

    @Override
    public void set(String path, Object value) {
        get(setAsync(path, value));
    }

    @Override
    public RFuture setAsync(String path, Object value) {
        return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.JSON_SET, getRawName(), path, encode(value));
    }

    @Override
    public void set(V value, long timeToLive, TimeUnit timeUnit) {
        get(setAsync(value, timeToLive, timeUnit));
    }

    @Override
    public RFuture setAsync(V value, long timeToLive, TimeUnit timeUnit) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_VOID,
                        "redis.call('json.set', KEYS[1], '$', ARGV[1]); " +
                              "redis.call('pexpire', KEYS[1], ARGV[2]); ",
                Collections.singletonList(getRawName()), encode(value), timeUnit.toMillis(timeToLive));
    }

    @Override
    public void set(V value, Duration duration) {
        get(setAsync(value, duration));
    }

    @Override
    public RFuture setAsync(V value, Duration duration) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_VOID,
                        "redis.call('json.set', KEYS[1], '$', ARGV[1]); " +
                              "redis.call('pexpire', KEYS[1], ARGV[2]); ",
                Collections.singletonList(getRawName()), encode(value), duration.toMillis());
    }

    @Override
    public void setAndKeepTTL(V value) {
        get(setAndKeepTTLAsync(value));
    }

    @Override
    public RFuture setAndKeepTTLAsync(V value) {
        return commandExecutor.evalWriteAsync(getRawName(), codec, RedisCommands.EVAL_VOID,
                "local ttl = redis.call('pttl', KEYS[1]);" +
                      "redis.call('json.set', KEYS[1], '$', ARGV[1]); " +
                      "if ttl > 0 then" +
                        "redis.call('pexpire', KEYS[1], ttl); " +
                      "end;",
                Collections.singletonList(getRawName()), encode(value));
    }

    @Override
    public RFuture deleteAsync() {
        return commandExecutor.writeAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.JSON_DEL_BOOLEAN, getRawName());
    }

    @Override
    public long stringAppend(String path, Object value) {
        return get(stringAppendAsync(path, value));
    }

    @Override
    public RFuture stringAppendAsync(String path, Object value) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_STRAPPEND, getRawName(), path, encode(value));
    }

    @Override
    public List stringAppendMulti(String path, Object value) {
        return get(stringAppendMultiAsync(path, value));
    }

    @Override
    public RFuture> stringAppendMultiAsync(String path, Object value) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_STRAPPEND_LIST, getRawName(), path, encode(value));
    }

    @Override
    public long arrayAppend(String path, Object... values) {
        return get(arrayAppendAsync(path, values));
    }

    @Override
    public RFuture arrayAppendAsync(String path, Object... values) {
        List args = new ArrayList<>(values.length + 2);
        args.add(getRawName());
        args.add(path);
        encode(args, Arrays.asList(values));
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRAPPEND, args.toArray());
    }

    @Override
    public List arrayAppendMulti(String path, Object... values) {
        return get(arrayAppendMultiAsync(path, values));
    }

    @Override
    public RFuture> arrayAppendMultiAsync(String path, Object... values) {
        List args = new ArrayList<>(values.length + 2);
        args.add(getRawName());
        args.add(path);
        encode(args, Arrays.asList(values));
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRAPPEND_LIST, args.toArray());
    }

    @Override
    public long arrayIndex(String path, Object value) {
        return get(arrayIndexAsync(path, value));
    }

    @Override
    public RFuture arrayIndexAsync(String path, Object value) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRINDEX, getRawName(), path, encode(value));
    }

    @Override
    public List arrayIndexMulti(String path, Object value) {
        return get(arrayIndexMultiAsync(path, value));
    }

    @Override
    public RFuture> arrayIndexMultiAsync(String path, Object value) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRINDEX_LIST, getRawName(), path, encode(value));
    }

    @Override
    public long arrayIndex(String path, Object value, long start, long end) {
        return get(arrayIndexAsync(path, value, start, end));
    }

    @Override
    public RFuture arrayIndexAsync(String path, Object value, long start, long end) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRINDEX, getRawName(), path, encode(value), start, end);
    }

    @Override
    public List arrayIndexMulti(String path, Object value, long start, long end) {
        return get(arrayIndexMultiAsync(path, value, start, end));
    }

    @Override
    public RFuture> arrayIndexMultiAsync(String path, Object value, long start, long end) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRINDEX_LIST, getRawName(), path, encode(value), start, end);
    }

    @Override
    public long arrayInsert(String path, long index, Object... values) {
        return get(arrayInsertAsync(path, index, values));
    }

    @Override
    public RFuture arrayInsertAsync(String path, long index, Object... values) {
        List args = new ArrayList<>(values.length + 3);
        args.add(getRawName());
        args.add(path);
        args.add(index);
        encode(args, Arrays.asList(values));
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRINSERT, args.toArray());
    }

    @Override
    public List arrayInsertMulti(String path, long index, Object... values) {
        return get(arrayInsertMultiAsync(path, index, values));
    }

    @Override
    public RFuture> arrayInsertMultiAsync(String path, long index, Object... values) {
        List args = new ArrayList<>(values.length + 3);
        args.add(getRawName());
        args.add(path);
        args.add(index);
        encode(args, Arrays.asList(values));
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRINSERT_LIST, args.toArray());
    }

    @Override
    public long arraySize(String path) {
        return get(arraySizeAsync(path));
    }

    @Override
    public RFuture arraySizeAsync(String path) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRLEN, getRawName(), path);
    }

    @Override
    public List arraySizeMulti(String path) {
        return get(arraySizeMultiAsync(path));
    }

    @Override
    public RFuture> arraySizeMultiAsync(String path) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRLEN_LIST, getRawName(), path);
    }

    @Override
    public  T arrayPollLast(JsonCodec codec, String path) {
        return get(arrayPollLastAsync(codec, path));
    }

    @Override
    public  RFuture arrayPollLastAsync(JsonCodec codec, String path) {
        return commandExecutor.writeAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.JSON_ARRPOP, getRawName(), path);
    }

    @Override
    public  List arrayPollLastMulti(JsonCodec codec, String path) {
        return get(arrayPollLastMultiAsync(codec, path));
    }

    @Override
    public  RFuture> arrayPollLastMultiAsync(JsonCodec codec, String path) {
        return commandExecutor.writeAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.JSON_ARRPOP_LIST, getRawName(), path);
    }

    @Override
    public  T arrayPollFirst(JsonCodec codec, String path) {
        return get(arrayPollFirstAsync(codec, path));
    }

    @Override
    public  RFuture arrayPollFirstAsync(JsonCodec codec, String path) {
        return commandExecutor.writeAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.JSON_ARRPOP, getRawName(), path, 0);
    }

    @Override
    public  List arrayPollFirstMulti(JsonCodec codec, String path) {
        return get(arrayPollFirstMultiAsync(codec, path));
    }

    @Override
    public  RFuture> arrayPollFirstMultiAsync(JsonCodec codec, String path) {
        return commandExecutor.writeAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.JSON_ARRPOP_LIST, getRawName(), path, 0);
    }

    @Override
    public  T arrayPop(JsonCodec codec, String path, long index) {
        return get(arrayPopAsync(codec, path, index));
    }

    @Override
    public  RFuture arrayPopAsync(JsonCodec codec, String path, long index) {
        return commandExecutor.writeAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.JSON_ARRPOP, getRawName(), path, index);
    }

    @Override
    public  List arrayPopMulti(JsonCodec codec, String path, long index) {
        return get(arrayPopMultiAsync(codec, path, index));
    }

    @Override
    public  RFuture> arrayPopMultiAsync(JsonCodec codec, String path, long index) {
        return commandExecutor.writeAsync(getRawName(), new JsonCodecWrapper(codec), RedisCommands.JSON_ARRPOP_LIST, getRawName(), path, index);
    }

    @Override
    public long arrayTrim(String path, long start, long end) {
        return get(arrayTrimAsync(path, start, end));
    }

    @Override
    public RFuture arrayTrimAsync(String path, long start, long end) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRTRIM, getRawName(), path, start, end);
    }

    @Override
    public List arrayTrimMulti(String path, long start, long end) {
        return get(arrayTrimMultiAsync(path, start, end));
    }

    @Override
    public RFuture> arrayTrimMultiAsync(String path, long start, long end) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_ARRTRIM_LIST, getRawName(), path, start, end);
    }

    @Override
    public long clear() {
        return get(clearAsync());
    }

    @Override
    public RFuture clearAsync() {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_CLEAR, getRawName());
    }

    @Override
    public long clear(String path) {
        return get(clearAsync(path));
    }

    @Override
    public RFuture clearAsync(String path) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_CLEAR, getRawName(), path);
    }

    @Override
    public  T incrementAndGet(String path, T delta) {
        return get(incrementAndGetAsync(path, delta));
    }

    @Override
    public  RFuture incrementAndGetAsync(String path, T delta) {
        RedisCommand command;
        if (getServiceManager().isResp3()) {
            command = new RedisCommand<>("JSON.NUMINCRBY", new ListFirstObjectDecoder(), new LongNumberConvertor(delta.getClass()));
        } else {
            command = new RedisCommand<>("JSON.NUMINCRBY", new NumberConvertor(delta.getClass()));
        }
        return commandExecutor.writeAsync(getRawName(), StringCodec.INSTANCE, command,
                                            getRawName(), path, new BigDecimal(delta.toString()).toPlainString());
    }

    @Override
    public  List incrementAndGetMulti(String path, T delta) {
        return get(incrementAndGetMultiAsync(path, delta));
    }

    @Override
    public  RFuture> incrementAndGetMultiAsync(String path, T delta) {
        return commandExecutor.writeAsync(getRawName(), StringCodec.INSTANCE, new RedisCommand("JSON.NUMINCRBY",
                                                                        new ObjectListReplayDecoder(), new NumberConvertor(delta.getClass())),
                                            getRawName(), path, new BigDecimal(delta.toString()).toPlainString());
    }

    @Override
    public long countKeys() {
        return get(countKeysAsync());
    }

    @Override
    public RFuture countKeysAsync() {
        RedisStrictCommand command = RedisCommands.JSON_OBJLEN;
        if (getServiceManager().isResp3()) {
            command = new RedisStrictCommand("JSON.OBJLEN", new ListFirstObjectDecoder());
        }

        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, command, getRawName());
    }

    @Override
    public long countKeys(String path) {
        return get(countKeysAsync(path));
    }

    @Override
    public RFuture countKeysAsync(String path) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_OBJLEN, getRawName(), path);
    }

    @Override
    public List countKeysMulti(String path) {
        return get(countKeysMultiAsync(path));
    }

    @Override
    public RFuture> countKeysMultiAsync(String path) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_OBJLEN_LIST, getRawName(), path);
    }

    @Override
    public List getKeys() {
        return get(getKeysAsync());
    }

    @Override
    public RFuture> getKeysAsync() {
        RedisCommand command = RedisCommands.JSON_OBJKEYS;
        if (getServiceManager().isResp3()) {
            command = new RedisCommand("JSON.OBJKEYS",
                    new ListMultiDecoder2(new ListFirstObjectDecoder(), new StringListListReplayDecoder()));
        }
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, command, getRawName());
    }

    @Override
    public List getKeys(String path) {
        return get(getKeysAsync(path));
    }

    @Override
    public RFuture> getKeysAsync(String path) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_OBJKEYS, getRawName(), path);
    }

    @Override
    public List> getKeysMulti(String path) {
        return get(getKeysMultiAsync(path));
    }

    @Override
    public RFuture>> getKeysMultiAsync(String path) {
        return commandExecutor.readAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_OBJKEYS_LIST, getRawName(), path);
    }

    @Override
    public boolean toggle(String path) {
        return get(toggleAsync(path));
    }

    @Override
    public RFuture toggleAsync(String path) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_TOGGLE, getRawName(), path);
    }

    @Override
    public List toggleMulti(String path) {
        return get(toggleMultiAsync(path));
    }

    @Override
    public RFuture> toggleMultiAsync(String path) {
        return commandExecutor.writeAsync(getRawName(), LongCodec.INSTANCE, RedisCommands.JSON_TOGGLE_LIST, getRawName(), path);
    }

    @Override
    public JsonType getType() {
        return get(getTypeAsync());
    }

    @Override
    public RFuture getTypeAsync() {
        RedisCommand command = RedisCommands.JSON_TYPE;
        if (getServiceManager().isResp3()) {
            command = new RedisCommand("JSON.TYPE", new ListFirstObjectDecoder(), new JsonTypeConvertor());
        }

        return commandExecutor.readAsync(getRawName(), StringCodec.INSTANCE, command, getRawName());
    }

    @Override
    public JsonType getType(String path) {
        return get(getTypeAsync(path));
    }

    @Override
    public RFuture getTypeAsync(String path) {
        RedisCommand command = RedisCommands.JSON_TYPE;
        if (getServiceManager().isResp3()) {
            command = new RedisCommand("JSON.TYPE", new ListFirstObjectDecoder(), new JsonTypeConvertor());
        }

        return commandExecutor.readAsync(getRawName(), StringCodec.INSTANCE, command, getRawName(), path);
    }

    @Override
    public long delete(String path) {
        return get(deleteAsync(path));
    }

    @Override
    public RFuture deleteAsync(String path) {
        return commandExecutor.writeAsync(getRawName(), StringCodec.INSTANCE, RedisCommands.JSON_DEL_LONG, getRawName(), path);
    }

    @Override
    public void merge(String path, Object value) {
        get(mergeAsync(path, value));
    }

    @Override
    public RFuture mergeAsync(String path, Object value) {
        return commandExecutor.writeAsync(getRawName(), codec, RedisCommands.JSON_MERGE, getRawName(), path, encode(value));
    }

    @Override
    public V findCommon(String name) {
        return get(findCommonAsync(name));
    }

    @Override
    public RFuture findCommonAsync(String name) {
        throw new UnsupportedOperationException();
    }

    @Override
    public long findCommonLength(String name) {
        return get(findCommonLengthAsync(name));
    }

    @Override
    public RFuture findCommonLengthAsync(String name) {
        throw new UnsupportedOperationException();
    }
}