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

redis.clients.jedis.CommandObjects Maven / Gradle / Ivy

The newest version!
package redis.clients.jedis;

import static redis.clients.jedis.Protocol.Command.*;
import static redis.clients.jedis.Protocol.Keyword.*;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.json.JSONArray;
import org.json.JSONObject;

import redis.clients.jedis.Protocol.Command;
import redis.clients.jedis.Protocol.Keyword;
import redis.clients.jedis.args.*;
import redis.clients.jedis.bloom.*;
import redis.clients.jedis.bloom.RedisBloomProtocol.*;
import redis.clients.jedis.commands.ProtocolCommand;
import redis.clients.jedis.gears.*;
import redis.clients.jedis.gears.RedisGearsProtocol.*;
import redis.clients.jedis.gears.resps.GearsLibraryInfo;
import redis.clients.jedis.graph.GraphProtocol.*;
import redis.clients.jedis.json.*;
import redis.clients.jedis.json.JsonProtocol.JsonCommand;
import redis.clients.jedis.json.DefaultGsonObjectMapper;
import redis.clients.jedis.json.JsonObjectMapper;
import redis.clients.jedis.params.*;
import redis.clients.jedis.resps.*;
import redis.clients.jedis.search.*;
import redis.clients.jedis.search.SearchProtocol.*;
import redis.clients.jedis.search.SearchResult.SearchResultBuilder;
import redis.clients.jedis.search.aggr.AggregationBuilder;
import redis.clients.jedis.search.aggr.AggregationResult;
import redis.clients.jedis.search.schemafields.SchemaField;
import redis.clients.jedis.timeseries.*;
import redis.clients.jedis.timeseries.TimeSeriesProtocol.*;
import redis.clients.jedis.util.KeyValue;

public class CommandObjects {

  private RedisProtocol protocol;

  // TODO: restrict?
  public final void setProtocol(RedisProtocol proto) {
    this.protocol = proto;
  }

  // TODO: remove?
  protected RedisProtocol getProtocol() {
    return protocol;
  }

  private volatile JsonObjectMapper jsonObjectMapper;
  private final AtomicInteger searchDialect = new AtomicInteger(0);

  private JedisBroadcastAndRoundRobinConfig broadcastAndRoundRobinConfig = null;

  void setBroadcastAndRoundRobinConfig(JedisBroadcastAndRoundRobinConfig config) {
    this.broadcastAndRoundRobinConfig = config;
  }

  protected CommandArguments commandArguments(ProtocolCommand command) {
    return new CommandArguments(command);
  }

  private final CommandObject PING_COMMAND_OBJECT = new CommandObject<>(commandArguments(PING), BuilderFactory.STRING);

  public final CommandObject ping() {
    return PING_COMMAND_OBJECT;
  }

  private final CommandObject FLUSHALL_COMMAND_OBJECT = new CommandObject<>(commandArguments(FLUSHALL), BuilderFactory.STRING);

  public final CommandObject flushAll() {
    return FLUSHALL_COMMAND_OBJECT;
  }

  private final CommandObject FLUSHDB_COMMAND_OBJECT = new CommandObject<>(commandArguments(FLUSHDB), BuilderFactory.STRING);

  public final CommandObject flushDB() {
    return FLUSHDB_COMMAND_OBJECT;
  }

  public final CommandObject configSet(String parameter, String value) {
    return new CommandObject<>(commandArguments(Command.CONFIG).add(Keyword.SET).add(parameter).add(value), BuilderFactory.STRING);
  }

  // Key commands
  public final CommandObject exists(String key) {
    return new CommandObject<>(commandArguments(Command.EXISTS).key(key), BuilderFactory.BOOLEAN);
  }

  public final CommandObject exists(String... keys) {
    return new CommandObject<>(commandArguments(Command.EXISTS).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject exists(byte[] key) {
    return new CommandObject<>(commandArguments(Command.EXISTS).key(key), BuilderFactory.BOOLEAN);
  }

  public final CommandObject exists(byte[]... keys) {
    return new CommandObject<>(commandArguments(Command.EXISTS).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject persist(String key) {
    return new CommandObject<>(commandArguments(Command.PERSIST).key(key), BuilderFactory.LONG);
  }

  public final CommandObject persist(byte[] key) {
    return new CommandObject<>(commandArguments(Command.PERSIST).key(key), BuilderFactory.LONG);
  }

  public final CommandObject type(String key) {
    return new CommandObject<>(commandArguments(Command.TYPE).key(key), BuilderFactory.STRING);
  }

  public final CommandObject type(byte[] key) {
    return new CommandObject<>(commandArguments(Command.TYPE).key(key), BuilderFactory.STRING);
  }

  public final CommandObject dump(String key) {
    return new CommandObject<>(commandArguments(Command.DUMP).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject dump(byte[] key) {
    return new CommandObject<>(commandArguments(Command.DUMP).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject restore(String key, long ttl, byte[] serializedValue) {
    return new CommandObject<>(commandArguments(RESTORE).key(key).add(ttl)
        .add(serializedValue), BuilderFactory.STRING);
  }

  public final CommandObject restore(String key, long ttl, byte[] serializedValue, RestoreParams params) {
    return new CommandObject<>(commandArguments(RESTORE).key(key).add(ttl)
        .add(serializedValue).addParams(params), BuilderFactory.STRING);
  }

  public final CommandObject restore(byte[] key, long ttl, byte[] serializedValue) {
    return new CommandObject<>(commandArguments(RESTORE).key(key).add(ttl)
        .add(serializedValue), BuilderFactory.STRING);
  }

  public final CommandObject restore(byte[] key, long ttl, byte[] serializedValue, RestoreParams params) {
    return new CommandObject<>(commandArguments(RESTORE).key(key).add(ttl)
        .add(serializedValue).addParams(params), BuilderFactory.STRING);
  }

  public final CommandObject expire(String key, long seconds) {
    return new CommandObject<>(commandArguments(EXPIRE).key(key).add(seconds), BuilderFactory.LONG);
  }

  public final CommandObject expire(byte[] key, long seconds) {
    return new CommandObject<>(commandArguments(EXPIRE).key(key).add(seconds), BuilderFactory.LONG);
  }

  public final CommandObject expire(String key, long seconds, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(EXPIRE).key(key).add(seconds).add(expiryOption),
        BuilderFactory.LONG);
  }

  public final CommandObject expire(byte[] key, long seconds, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(EXPIRE).key(key).add(seconds).add(expiryOption),
        BuilderFactory.LONG);
  }

  public final CommandObject pexpire(String key, long milliseconds) {
    return new CommandObject<>(commandArguments(PEXPIRE).key(key).add(milliseconds), BuilderFactory.LONG);
  }

  public final CommandObject pexpire(byte[] key, long milliseconds) {
    return new CommandObject<>(commandArguments(PEXPIRE).key(key).add(milliseconds), BuilderFactory.LONG);
  }

  public final CommandObject pexpire(String key, long milliseconds, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(PEXPIRE).key(key).add(milliseconds).add(expiryOption),
        BuilderFactory.LONG);
  }

  public final CommandObject pexpire(byte[] key, long milliseconds, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(PEXPIRE).key(key).add(milliseconds).add(expiryOption),
        BuilderFactory.LONG);
  }

  public final CommandObject expireTime(String key) {
    return new CommandObject<>(commandArguments(EXPIRETIME).key(key), BuilderFactory.LONG);
  }

  public final CommandObject expireTime(byte[] key) {
    return new CommandObject<>(commandArguments(EXPIRETIME).key(key), BuilderFactory.LONG);
  }

  public final CommandObject pexpireTime(String key) {
    return new CommandObject<>(commandArguments(PEXPIRETIME).key(key), BuilderFactory.LONG);
  }

  public final CommandObject pexpireTime(byte[] key) {
    return new CommandObject<>(commandArguments(PEXPIRETIME).key(key), BuilderFactory.LONG);
  }

  public final CommandObject expireAt(String key, long unixTime) {
    return new CommandObject<>(commandArguments(EXPIREAT).key(key).add(unixTime), BuilderFactory.LONG);
  }

  public final CommandObject expireAt(byte[] key, long unixTime) {
    return new CommandObject<>(commandArguments(EXPIREAT).key(key).add(unixTime), BuilderFactory.LONG);
  }

  public final CommandObject expireAt(String key, long unixTime, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(EXPIREAT).key(key).add(unixTime).add(expiryOption), BuilderFactory.LONG);
  }

  public final CommandObject expireAt(byte[] key, long unixTime, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(EXPIREAT).key(key).add(unixTime).add(expiryOption), BuilderFactory.LONG);
  }

  public final CommandObject pexpireAt(String key, long millisecondsTimestamp) {
    return new CommandObject<>(commandArguments(PEXPIREAT).key(key).add(millisecondsTimestamp), BuilderFactory.LONG);
  }

  public final CommandObject pexpireAt(byte[] key, long millisecondsTimestamp) {
    return new CommandObject<>(commandArguments(PEXPIREAT).key(key).add(millisecondsTimestamp), BuilderFactory.LONG);
  }

  public final CommandObject pexpireAt(String key, long millisecondsTimestamp, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(PEXPIREAT).key(key).add(millisecondsTimestamp).add(expiryOption),
        BuilderFactory.LONG);
  }

  public final CommandObject pexpireAt(byte[] key, long millisecondsTimestamp, ExpiryOption expiryOption) {
    return new CommandObject<>(commandArguments(PEXPIREAT).key(key).add(millisecondsTimestamp).add(expiryOption),
        BuilderFactory.LONG);
  }

  public final CommandObject ttl(String key) {
    return new CommandObject<>(commandArguments(TTL).key(key), BuilderFactory.LONG);
  }

  public final CommandObject ttl(byte[] key) {
    return new CommandObject<>(commandArguments(TTL).key(key), BuilderFactory.LONG);
  }

  public final CommandObject pttl(String key) {
    return new CommandObject<>(commandArguments(PTTL).key(key), BuilderFactory.LONG);
  }

  public final CommandObject pttl(byte[] key) {
    return new CommandObject<>(commandArguments(PTTL).key(key), BuilderFactory.LONG);
  }

  public final CommandObject touch(String key) {
    return new CommandObject<>(commandArguments(TOUCH).key(key), BuilderFactory.LONG);
  }

  public final CommandObject touch(String... keys) {
    return new CommandObject<>(commandArguments(TOUCH).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject touch(byte[] key) {
    return new CommandObject<>(commandArguments(TOUCH).key(key), BuilderFactory.LONG);
  }

  public final CommandObject touch(byte[]... keys) {
    return new CommandObject<>(commandArguments(TOUCH).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject> sort(String key) {
    return new CommandObject<>(commandArguments(SORT).key(key), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> sort(String key, SortingParams sortingParams) {
    return new CommandObject<>(commandArguments(SORT).key(key).addParams(sortingParams), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> sort(byte[] key) {
    return new CommandObject<>(commandArguments(SORT).key(key), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> sort(byte[] key, SortingParams sortingParams) {
    return new CommandObject<>(commandArguments(SORT).key(key).addParams(sortingParams), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject sort(String key, String dstkey) {
    return new CommandObject<>(commandArguments(SORT).key(key)
        .add(STORE).key(dstkey), BuilderFactory.LONG);
  }

  public final CommandObject sort(String key, SortingParams sortingParams, String dstkey) {
    return new CommandObject<>(commandArguments(SORT).key(key).addParams(sortingParams)
        .add(STORE).key(dstkey), BuilderFactory.LONG);
  }

  public final CommandObject sort(byte[] key, byte[] dstkey) {
    return new CommandObject<>(commandArguments(SORT).key(key)
        .add(STORE).key(dstkey), BuilderFactory.LONG);
  }

  public final CommandObject sort(byte[] key, SortingParams sortingParams, byte[] dstkey) {
    return new CommandObject<>(commandArguments(SORT).key(key).addParams(sortingParams)
        .add(STORE).key(dstkey), BuilderFactory.LONG);
  }

  public final CommandObject> sortReadonly(byte[] key, SortingParams sortingParams) {
    return new CommandObject<>(commandArguments(SORT_RO).key(key).addParams(sortingParams),
        BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> sortReadonly(String key, SortingParams sortingParams) {
    return new CommandObject<>(commandArguments(SORT_RO).key(key).addParams(sortingParams),
        BuilderFactory.STRING_LIST);
  }

  public final CommandObject del(String key) {
    return new CommandObject<>(commandArguments(DEL).key(key), BuilderFactory.LONG);
  }

  public final CommandObject del(String... keys) {
    return new CommandObject<>(commandArguments(DEL).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject del(byte[] key) {
    return new CommandObject<>(commandArguments(DEL).key(key), BuilderFactory.LONG);
  }

  public final CommandObject del(byte[]... keys) {
    return new CommandObject<>(commandArguments(DEL).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject unlink(String key) {
    return new CommandObject<>(commandArguments(UNLINK).key(key), BuilderFactory.LONG);
  }

  public final CommandObject unlink(String... keys) {
    return new CommandObject<>(commandArguments(UNLINK).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject unlink(byte[] key) {
    return new CommandObject<>(commandArguments(UNLINK).key(key), BuilderFactory.LONG);
  }

  public final CommandObject unlink(byte[]... keys) {
    return new CommandObject<>(commandArguments(UNLINK).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject copy(String srcKey, String dstKey, boolean replace) {
    CommandArguments args = commandArguments(Command.COPY).key(srcKey).key(dstKey);
    if (replace) {
      args.add(REPLACE);
    }
    return new CommandObject<>(args, BuilderFactory.BOOLEAN);
  }

  public final CommandObject copy(byte[] srcKey, byte[] dstKey, boolean replace) {
    CommandArguments args = commandArguments(Command.COPY).key(srcKey).key(dstKey);
    if (replace) {
      args.add(REPLACE);
    }
    return new CommandObject<>(args, BuilderFactory.BOOLEAN);
  }

  public final CommandObject rename(String oldkey, String newkey) {
    return new CommandObject<>(commandArguments(RENAME).key(oldkey).key(newkey), BuilderFactory.STRING);
  }

  public final CommandObject renamenx(String oldkey, String newkey) {
    return new CommandObject<>(commandArguments(RENAMENX).key(oldkey).key(newkey), BuilderFactory.LONG);
  }

  public final CommandObject rename(byte[] oldkey, byte[] newkey) {
    return new CommandObject<>(commandArguments(RENAME).key(oldkey).key(newkey), BuilderFactory.STRING);
  }

  public final CommandObject renamenx(byte[] oldkey, byte[] newkey) {
    return new CommandObject<>(commandArguments(RENAMENX).key(oldkey).key(newkey), BuilderFactory.LONG);
  }

  public CommandObject dbSize() {
    return new CommandObject<>(commandArguments(DBSIZE), BuilderFactory.LONG);
  }

  public CommandObject> keys(String pattern) {
    CommandArguments args = commandArguments(Command.KEYS).key(pattern);
    return new CommandObject<>(args, BuilderFactory.STRING_SET);
  }

  public CommandObject> keys(byte[] pattern) {
    CommandArguments args = commandArguments(Command.KEYS).key(pattern);
    return new CommandObject<>(args, BuilderFactory.BINARY_SET);
  }

  public CommandObject> scan(String cursor) {
    return new CommandObject<>(commandArguments(SCAN).add(cursor), BuilderFactory.SCAN_RESPONSE);
  }

  public CommandObject> scan(String cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(SCAN).add(cursor).addParams(params), BuilderFactory.SCAN_RESPONSE);
  }

  public CommandObject> scan(String cursor, ScanParams params, String type) {
    return new CommandObject<>(commandArguments(SCAN).add(cursor).addParams(params).add(Keyword.TYPE).add(type), BuilderFactory.SCAN_RESPONSE);
  }

  public CommandObject> scan(byte[] cursor) {
    return new CommandObject<>(commandArguments(SCAN).add(cursor), BuilderFactory.SCAN_BINARY_RESPONSE);
  }

  public CommandObject> scan(byte[] cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(SCAN).add(cursor).addParams(params), BuilderFactory.SCAN_BINARY_RESPONSE);
  }

  public CommandObject> scan(byte[] cursor, ScanParams params, byte[] type) {
    return new CommandObject<>(commandArguments(SCAN).add(cursor).addParams(params).add(Keyword.TYPE).add(type), BuilderFactory.SCAN_BINARY_RESPONSE);
  }

  public final CommandObject randomKey() {
    return new CommandObject<>(commandArguments(RANDOMKEY), BuilderFactory.STRING);
  }

  public final CommandObject randomBinaryKey() {
    return new CommandObject<>(commandArguments(RANDOMKEY), BuilderFactory.BINARY);
  }
  // Key commands

  // String commands
  public final CommandObject set(String key, String value) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value), BuilderFactory.STRING);
  }

  public final CommandObject set(String key, String value, SetParams params) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value).addParams(params), BuilderFactory.STRING);
  }

  public final CommandObject set(byte[] key, byte[] value) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value), BuilderFactory.STRING);
  }

  public final CommandObject set(byte[] key, byte[] value, SetParams params) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value).addParams(params), BuilderFactory.STRING);
  }

  public final CommandObject get(String key) {
    return new CommandObject<>(commandArguments(Command.GET).key(key), BuilderFactory.STRING);
  }

  public final CommandObject setGet(String key, String value) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value).add(Keyword.GET), BuilderFactory.STRING);
  }

  public final CommandObject setGet(String key, String value, SetParams params) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value).addParams(params)
        .add(Keyword.GET), BuilderFactory.STRING);
  }

  public final CommandObject getDel(String key) {
    return new CommandObject<>(commandArguments(Command.GETDEL).key(key), BuilderFactory.STRING);
  }

  public final CommandObject getEx(String key, GetExParams params) {
    return new CommandObject<>(commandArguments(Command.GETEX).key(key).addParams(params), BuilderFactory.STRING);
  }

  public final CommandObject get(byte[] key) {
    return new CommandObject<>(commandArguments(Command.GET).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject setGet(byte[] key, byte[] value) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value).add(Keyword.GET), BuilderFactory.BINARY);
  }

  public final CommandObject setGet(byte[] key, byte[] value, SetParams params) {
    return new CommandObject<>(commandArguments(Command.SET).key(key).add(value).addParams(params)
        .add(Keyword.GET), BuilderFactory.BINARY);
  }

  public final CommandObject getDel(byte[] key) {
    return new CommandObject<>(commandArguments(Command.GETDEL).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject getEx(byte[] key, GetExParams params) {
    return new CommandObject<>(commandArguments(Command.GETEX).key(key).addParams(params), BuilderFactory.BINARY);
  }

  public final CommandObject getSet(String key, String value) {
    return new CommandObject<>(commandArguments(Command.GETSET).key(key).add(value), BuilderFactory.STRING);
  }

  public final CommandObject getSet(byte[] key, byte[] value) {
    return new CommandObject<>(commandArguments(Command.GETSET).key(key).add(value), BuilderFactory.BINARY);
  }

  public final CommandObject setnx(String key, String value) {
    return new CommandObject<>(commandArguments(SETNX).key(key).add(value), BuilderFactory.LONG);
  }

  public final CommandObject setex(String key, long seconds, String value) {
    return new CommandObject<>(commandArguments(SETEX).key(key).add(seconds).add(value), BuilderFactory.STRING);
  }

  public final CommandObject psetex(String key, long milliseconds, String value) {
    return new CommandObject<>(commandArguments(PSETEX).key(key).add(milliseconds).add(value), BuilderFactory.STRING);
  }

  public final CommandObject setnx(byte[] key, byte[] value) {
    return new CommandObject<>(commandArguments(SETNX).key(key).add(value), BuilderFactory.LONG);
  }

  public final CommandObject setex(byte[] key, long seconds, byte[] value) {
    return new CommandObject<>(commandArguments(SETEX).key(key).add(seconds).add(value), BuilderFactory.STRING);
  }

  public final CommandObject psetex(byte[] key, long milliseconds, byte[] value) {
    return new CommandObject<>(commandArguments(PSETEX).key(key).add(milliseconds).add(value), BuilderFactory.STRING);
  }

  public final CommandObject setbit(String key, long offset, boolean value) {
    return new CommandObject<>(commandArguments(SETBIT).key(key).add(offset).add(value), BuilderFactory.BOOLEAN);
  }

  public final CommandObject setbit(byte[] key, long offset, boolean value) {
    return new CommandObject<>(commandArguments(SETBIT).key(key).add(offset).add(value), BuilderFactory.BOOLEAN);
  }

  public final CommandObject getbit(String key, long offset) {
    return new CommandObject<>(commandArguments(GETBIT).key(key).add(offset), BuilderFactory.BOOLEAN);
  }

  public final CommandObject getbit(byte[] key, long offset) {
    return new CommandObject<>(commandArguments(GETBIT).key(key).add(offset), BuilderFactory.BOOLEAN);
  }

  public final CommandObject setrange(String key, long offset, String value) {
    return new CommandObject<>(commandArguments(SETRANGE).key(key).add(offset).add(value), BuilderFactory.LONG);
  }

  public final CommandObject setrange(byte[] key, long offset, byte[] value) {
    return new CommandObject<>(commandArguments(SETRANGE).key(key).add(offset).add(value), BuilderFactory.LONG);
  }

  public final CommandObject getrange(String key, long startOffset, long endOffset) {
    return new CommandObject<>(commandArguments(GETRANGE).key(key).add(startOffset).add(endOffset), BuilderFactory.STRING);
  }

  public final CommandObject getrange(byte[] key, long startOffset, long endOffset) {
    return new CommandObject<>(commandArguments(GETRANGE).key(key).add(startOffset).add(endOffset), BuilderFactory.BINARY);
  }

  public final CommandObject> mget(String... keys) {
    return new CommandObject<>(commandArguments(MGET).keys((Object[]) keys), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> mget(byte[]... keys) {
    return new CommandObject<>(commandArguments(MGET).keys((Object[]) keys), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject mset(String... keysvalues) {
    return new CommandObject<>(addFlatKeyValueArgs(commandArguments(MSET), keysvalues), BuilderFactory.STRING);
  }

  public final CommandObject msetnx(String... keysvalues) {
    return new CommandObject<>(addFlatKeyValueArgs(commandArguments(MSETNX), keysvalues), BuilderFactory.LONG);
  }

  public final CommandObject mset(byte[]... keysvalues) {
    return new CommandObject<>(addFlatKeyValueArgs(commandArguments(MSET), keysvalues), BuilderFactory.STRING);
  }

  public final CommandObject msetnx(byte[]... keysvalues) {
    return new CommandObject<>(addFlatKeyValueArgs(commandArguments(MSETNX), keysvalues), BuilderFactory.LONG);
  }

  public final CommandObject incr(String key) {
    return new CommandObject<>(commandArguments(Command.INCR).key(key), BuilderFactory.LONG);
  }

  public final CommandObject incrBy(String key, long increment) {
    return new CommandObject<>(commandArguments(INCRBY).key(key).add(increment), BuilderFactory.LONG);
  }

  public final CommandObject incrByFloat(String key, double increment) {
    return new CommandObject<>(commandArguments(INCRBYFLOAT).key(key).add(increment), BuilderFactory.DOUBLE);
  }

  public final CommandObject incr(byte[] key) {
    return new CommandObject<>(commandArguments(Command.INCR).key(key), BuilderFactory.LONG);
  }

  public final CommandObject incrBy(byte[] key, long increment) {
    return new CommandObject<>(commandArguments(INCRBY).key(key).add(increment), BuilderFactory.LONG);
  }

  public final CommandObject incrByFloat(byte[] key, double increment) {
    return new CommandObject<>(commandArguments(INCRBYFLOAT).key(key).add(increment), BuilderFactory.DOUBLE);
  }

  public final CommandObject decr(String key) {
    return new CommandObject<>(commandArguments(DECR).key(key), BuilderFactory.LONG);
  }

  public final CommandObject decrBy(String key, long decrement) {
    return new CommandObject<>(commandArguments(DECRBY).key(key).add(decrement), BuilderFactory.LONG);
  }

  public final CommandObject decr(byte[] key) {
    return new CommandObject<>(commandArguments(DECR).key(key), BuilderFactory.LONG);
  }

  public final CommandObject decrBy(byte[] key, long decrement) {
    return new CommandObject<>(commandArguments(DECRBY).key(key).add(decrement), BuilderFactory.LONG);
  }

  public final CommandObject append(String key, String value) {
    return new CommandObject<>(commandArguments(APPEND).key(key).add(value), BuilderFactory.LONG);
  }

  public final CommandObject append(byte[] key, byte[] value) {
    return new CommandObject<>(commandArguments(APPEND).key(key).add(value), BuilderFactory.LONG);
  }

  public final CommandObject substr(String key, int start, int end) {
    return new CommandObject<>(commandArguments(SUBSTR).key(key).add(start).add(end), BuilderFactory.STRING);
  }

  public final CommandObject substr(byte[] key, int start, int end) {
    return new CommandObject<>(commandArguments(SUBSTR).key(key).add(start).add(end), BuilderFactory.BINARY);
  }

  public final CommandObject strlen(String key) {
    return new CommandObject<>(commandArguments(STRLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject strlen(byte[] key) {
    return new CommandObject<>(commandArguments(STRLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject bitcount(String key) {
    return new CommandObject<>(commandArguments(BITCOUNT).key(key), BuilderFactory.LONG);
  }

  public final CommandObject bitcount(String key, long start, long end) {
    return new CommandObject<>(commandArguments(BITCOUNT).key(key).add(start).add(end), BuilderFactory.LONG);
  }

  public final CommandObject bitcount(String key, long start, long end, BitCountOption option) {
    return new CommandObject<>(commandArguments(BITCOUNT).key(key).add(start).add(end).add(option), BuilderFactory.LONG);
  }

  public final CommandObject bitcount(byte[] key) {
    return new CommandObject<>(commandArguments(BITCOUNT).key(key), BuilderFactory.LONG);
  }

  public final CommandObject bitcount(byte[] key, long start, long end) {
    return new CommandObject<>(commandArguments(BITCOUNT).key(key).add(start).add(end), BuilderFactory.LONG);
  }

  public final CommandObject bitcount(byte[] key, long start, long end, BitCountOption option) {
    return new CommandObject<>(commandArguments(BITCOUNT).key(key).add(start).add(end).add(option), BuilderFactory.LONG);
  }

  public final CommandObject bitpos(String key, boolean value) {
    return new CommandObject<>(commandArguments(BITPOS).key(key).add(value ? 1 : 0), BuilderFactory.LONG);
  }

  public final CommandObject bitpos(String key, boolean value, BitPosParams params) {
    return new CommandObject<>(commandArguments(BITPOS).key(key).add(value ? 1 : 0).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject bitpos(byte[] key, boolean value) {
    return new CommandObject<>(commandArguments(BITPOS).key(key).add(value ? 1 : 0), BuilderFactory.LONG);
  }

  public final CommandObject bitpos(byte[] key, boolean value, BitPosParams params) {
    return new CommandObject<>(commandArguments(BITPOS).key(key).add(value ? 1 : 0).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject> bitfield(String key, String... arguments) {
    return new CommandObject<>(commandArguments(BITFIELD).key(key).addObjects((Object[]) arguments), BuilderFactory.LONG_LIST);
  }

  public final CommandObject> bitfieldReadonly(String key, String... arguments) {
    return new CommandObject<>(commandArguments(BITFIELD_RO).key(key).addObjects((Object[]) arguments), BuilderFactory.LONG_LIST);
  }

  public final CommandObject> bitfield(byte[] key, byte[]... arguments) {
    return new CommandObject<>(commandArguments(BITFIELD).key(key).addObjects((Object[]) arguments), BuilderFactory.LONG_LIST);
  }

  public final CommandObject> bitfieldReadonly(byte[] key, byte[]... arguments) {
    return new CommandObject<>(commandArguments(BITFIELD_RO).key(key).addObjects((Object[]) arguments), BuilderFactory.LONG_LIST);
  }

  public final CommandObject bitop(BitOP op, String destKey, String... srcKeys) {
    return new CommandObject<>(commandArguments(BITOP).add(op).key(destKey).keys((Object[]) srcKeys), BuilderFactory.LONG);
  }

  public final CommandObject bitop(BitOP op, byte[] destKey, byte[]... srcKeys) {
    return new CommandObject<>(commandArguments(BITOP).add(op).key(destKey).keys((Object[]) srcKeys), BuilderFactory.LONG);
  }

  public final CommandObject lcs(String keyA, String keyB, LCSParams params) {
    return new CommandObject<>(commandArguments(Command.LCS).key(keyA).key(keyB)
        .addParams(params), BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER);
  }

  public final CommandObject lcs(byte[] keyA, byte[] keyB, LCSParams params) {
    return new CommandObject<>(commandArguments(Command.LCS).key(keyA).key(keyB)
        .addParams(params), BuilderFactory.STR_ALGO_LCS_RESULT_BUILDER);
  }
  // String commands

  // List commands
  public final CommandObject rpush(String key, String... strings) {
    return new CommandObject<>(commandArguments(RPUSH).key(key).addObjects((Object[]) strings), BuilderFactory.LONG);
  }

  public final CommandObject rpush(byte[] key, byte[]... strings) {
    return new CommandObject<>(commandArguments(RPUSH).key(key).addObjects((Object[]) strings), BuilderFactory.LONG);
  }

  public final CommandObject lpush(String key, String... strings) {
    return new CommandObject<>(commandArguments(LPUSH).key(key).addObjects((Object[]) strings), BuilderFactory.LONG);
  }

  public final CommandObject lpush(byte[] key, byte[]... strings) {
    return new CommandObject<>(commandArguments(LPUSH).key(key).addObjects((Object[]) strings), BuilderFactory.LONG);
  }

  public final CommandObject llen(String key) {
    return new CommandObject<>(commandArguments(LLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject llen(byte[] key) {
    return new CommandObject<>(commandArguments(LLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject> lrange(String key, long start, long stop) {
    return new CommandObject<>(commandArguments(LRANGE).key(key).add(start).add(stop), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> lrange(byte[] key, long start, long stop) {
    return new CommandObject<>(commandArguments(LRANGE).key(key).add(start).add(stop), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject ltrim(String key, long start, long stop) {
    return new CommandObject<>(commandArguments(LTRIM).key(key).add(start).add(stop), BuilderFactory.STRING);
  }

  public final CommandObject ltrim(byte[] key, long start, long stop) {
    return new CommandObject<>(commandArguments(LTRIM).key(key).add(start).add(stop), BuilderFactory.STRING);
  }

  public final CommandObject lindex(String key, long index) {
    return new CommandObject<>(commandArguments(LINDEX).key(key).add(index), BuilderFactory.STRING);
  }

  public final CommandObject lindex(byte[] key, long index) {
    return new CommandObject<>(commandArguments(LINDEX).key(key).add(index), BuilderFactory.BINARY);
  }

  public final CommandObject lset(String key, long index, String value) {
    return new CommandObject<>(commandArguments(LSET).key(key).add(index).add(value), BuilderFactory.STRING);
  }

  public final CommandObject lset(byte[] key, long index, byte[] value) {
    return new CommandObject<>(commandArguments(LSET).key(key).add(index).add(value), BuilderFactory.STRING);
  }

  public final CommandObject lrem(String key, long count, String value) {
    return new CommandObject<>(commandArguments(LREM).key(key).add(count).add(value), BuilderFactory.LONG);
  }

  public final CommandObject lrem(byte[] key, long count, byte[] value) {
    return new CommandObject<>(commandArguments(LREM).key(key).add(count).add(value), BuilderFactory.LONG);
  }

  public final CommandObject lpop(String key) {
    return new CommandObject<>(commandArguments(LPOP).key(key), BuilderFactory.STRING);
  }

  public final CommandObject> lpop(String key, int count) {
    return new CommandObject<>(commandArguments(LPOP).key(key).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject lpop(byte[] key) {
    return new CommandObject<>(commandArguments(LPOP).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject> lpop(byte[] key, int count) {
    return new CommandObject<>(commandArguments(LPOP).key(key).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject rpop(String key) {
    return new CommandObject<>(commandArguments(RPOP).key(key), BuilderFactory.STRING);
  }

  public final CommandObject> rpop(String key, int count) {
    return new CommandObject<>(commandArguments(RPOP).key(key).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject rpop(byte[] key) {
    return new CommandObject<>(commandArguments(RPOP).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject> rpop(byte[] key, int count) {
    return new CommandObject<>(commandArguments(RPOP).key(key).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject lpos(String key, String element) {
    return new CommandObject<>(commandArguments(LPOS).key(key).add(element), BuilderFactory.LONG);
  }

  public final CommandObject lpos(String key, String element, LPosParams params) {
    return new CommandObject<>(commandArguments(LPOS).key(key).add(element).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject> lpos(String key, String element, LPosParams params, long count) {
    return new CommandObject<>(commandArguments(LPOS).key(key).add(element)
        .addParams(params).add(COUNT).add(count), BuilderFactory.LONG_LIST);
  }

  public final CommandObject lpos(byte[] key, byte[] element) {
    return new CommandObject<>(commandArguments(LPOS).key(key).add(element), BuilderFactory.LONG);
  }

  public final CommandObject lpos(byte[] key, byte[] element, LPosParams params) {
    return new CommandObject<>(commandArguments(LPOS).key(key).add(element).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject> lpos(byte[] key, byte[] element, LPosParams params, long count) {
    return new CommandObject<>(commandArguments(LPOS).key(key).add(element)
        .addParams(params).add(COUNT).add(count), BuilderFactory.LONG_LIST);
  }

  public final CommandObject linsert(String key, ListPosition where, String pivot, String value) {
    return new CommandObject<>(commandArguments(LINSERT).key(key).add(where)
        .add(pivot).add(value), BuilderFactory.LONG);
  }

  public final CommandObject linsert(byte[] key, ListPosition where, byte[] pivot, byte[] value) {
    return new CommandObject<>(commandArguments(LINSERT).key(key).add(where)
        .add(pivot).add(value), BuilderFactory.LONG);
  }

  public final CommandObject lpushx(String key, String... strings) {
    return new CommandObject<>(commandArguments(LPUSHX).key(key).addObjects((Object[]) strings), BuilderFactory.LONG);
  }

  public final CommandObject rpushx(String key, String... strings) {
    return new CommandObject<>(commandArguments(RPUSHX).key(key).addObjects((Object[]) strings), BuilderFactory.LONG);
  }

  public final CommandObject lpushx(byte[] key, byte[]... args) {
    return new CommandObject<>(commandArguments(LPUSHX).key(key).addObjects((Object[]) args), BuilderFactory.LONG);
  }

  public final CommandObject rpushx(byte[] key, byte[]... args) {
    return new CommandObject<>(commandArguments(RPUSHX).key(key).addObjects((Object[]) args), BuilderFactory.LONG);
  }

  public final CommandObject> blpop(int timeout, String key) {
    return new CommandObject<>(commandArguments(BLPOP).blocking().key(key).add(timeout), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> blpop(int timeout, String... keys) {
    return new CommandObject<>(commandArguments(BLPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> blpop(double timeout, String key) {
    return new CommandObject<>(commandArguments(BLPOP).blocking().key(key).add(timeout), BuilderFactory.KEYED_ELEMENT);
  }

  public final CommandObject> blpop(double timeout, String... keys) {
    return new CommandObject<>(commandArguments(BLPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.KEYED_ELEMENT);
  }

  public final CommandObject> blpop(int timeout, byte[]... keys) {
    return new CommandObject<>(commandArguments(BLPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> blpop(double timeout, byte[]... keys) {
    return new CommandObject<>(commandArguments(BLPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.BINARY_KEYED_ELEMENT);
  }

  public final CommandObject> brpop(int timeout, String key) {
    return new CommandObject<>(commandArguments(BRPOP).blocking().key(key).add(timeout), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> brpop(int timeout, String... keys) {
    return new CommandObject<>(commandArguments(BRPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> brpop(double timeout, String key) {
    return new CommandObject<>(commandArguments(BRPOP).blocking().key(key).add(timeout), BuilderFactory.KEYED_ELEMENT);
  }

  public final CommandObject> brpop(double timeout, String... keys) {
    return new CommandObject<>(commandArguments(BRPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.KEYED_ELEMENT);
  }

  public final CommandObject> brpop(int timeout, byte[]... keys) {
    return new CommandObject<>(commandArguments(BRPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> brpop(double timeout, byte[]... keys) {
    return new CommandObject<>(commandArguments(BRPOP).blocking().keys((Object[]) keys).add(timeout), BuilderFactory.BINARY_KEYED_ELEMENT);
  }

  public final CommandObject rpoplpush(String srckey, String dstkey) {
    return new CommandObject<>(commandArguments(RPOPLPUSH).key(srckey).key(dstkey), BuilderFactory.STRING);
  }

  public final CommandObject brpoplpush(String source, String destination, int timeout) {
    return new CommandObject<>(commandArguments(BRPOPLPUSH).blocking().key(source)
        .key(destination).add(timeout), BuilderFactory.STRING);
  }

  public final CommandObject rpoplpush(byte[] srckey, byte[] dstkey) {
    return new CommandObject<>(commandArguments(RPOPLPUSH).key(srckey).key(dstkey), BuilderFactory.BINARY);
  }

  public final CommandObject brpoplpush(byte[] source, byte[] destination, int timeout) {
    return new CommandObject<>(commandArguments(BRPOPLPUSH).blocking().key(source)
        .key(destination).add(timeout), BuilderFactory.BINARY);
  }

  public final CommandObject lmove(String srcKey, String dstKey, ListDirection from, ListDirection to) {
    return new CommandObject<>(commandArguments(LMOVE).key(srcKey).key(dstKey)
        .add(from).add(to), BuilderFactory.STRING);
  }

  public final CommandObject blmove(String srcKey, String dstKey, ListDirection from, ListDirection to, double timeout) {
    return new CommandObject<>(commandArguments(BLMOVE).blocking().key(srcKey)
        .key(dstKey).add(from).add(to).add(timeout), BuilderFactory.STRING);
  }

  public final CommandObject lmove(byte[] srcKey, byte[] dstKey, ListDirection from, ListDirection to) {
    return new CommandObject<>(commandArguments(LMOVE).key(srcKey).key(dstKey)
        .add(from).add(to), BuilderFactory.BINARY);
  }

  public final CommandObject blmove(byte[] srcKey, byte[] dstKey, ListDirection from, ListDirection to, double timeout) {
    return new CommandObject<>(commandArguments(BLMOVE).blocking().key(srcKey)
        .key(dstKey).add(from).add(to).add(timeout), BuilderFactory.BINARY);
  }

  public final CommandObject>> lmpop(ListDirection direction, String... keys) {
    return new CommandObject<>(commandArguments(LMPOP).add(keys.length).keys((Object[]) keys)
        .add(direction), BuilderFactory.KEYED_STRING_LIST);
  }

  public final CommandObject>> lmpop(ListDirection direction, int count, String... keys) {
    return new CommandObject<>(commandArguments(LMPOP).add(keys.length).keys((Object[]) keys)
        .add(direction).add(COUNT).add(count), BuilderFactory.KEYED_STRING_LIST);
  }

  public final CommandObject>> blmpop(double timeout, ListDirection direction, String... keys) {
    return new CommandObject<>(commandArguments(BLMPOP).blocking().add(timeout)
        .add(keys.length).keys((Object[]) keys).add(direction), BuilderFactory.KEYED_STRING_LIST);
  }

  public final CommandObject>> blmpop(double timeout, ListDirection direction, int count, String... keys) {
    return new CommandObject<>(commandArguments(BLMPOP).blocking().add(timeout)
        .add(keys.length).keys((Object[]) keys).add(direction).add(COUNT).add(count),
        BuilderFactory.KEYED_STRING_LIST);
  }

  public final CommandObject>> lmpop(ListDirection direction, byte[]... keys) {
    return new CommandObject<>(commandArguments(LMPOP).add(keys.length).keys((Object[]) keys)
        .add(direction), BuilderFactory.KEYED_BINARY_LIST);
  }

  public final CommandObject>> lmpop(ListDirection direction, int count, byte[]... keys) {
    return new CommandObject<>(commandArguments(LMPOP).add(keys.length).keys((Object[]) keys)
        .add(direction).add(COUNT).add(count), BuilderFactory.KEYED_BINARY_LIST);
  }

  public final CommandObject>> blmpop(double timeout, ListDirection direction, byte[]... keys) {
    return new CommandObject<>(commandArguments(BLMPOP).blocking().add(timeout)
        .add(keys.length).keys((Object[]) keys).add(direction), BuilderFactory.KEYED_BINARY_LIST);
  }

  public final CommandObject>> blmpop(double timeout, ListDirection direction, int count, byte[]... keys) {
    return new CommandObject<>(commandArguments(BLMPOP).blocking().add(timeout)
        .add(keys.length).keys((Object[]) keys).add(direction).add(COUNT).add(count),
        BuilderFactory.KEYED_BINARY_LIST);
  }
  // List commands

  // Hash commands
  public final CommandObject hset(String key, String field, String value) {
    return new CommandObject<>(commandArguments(HSET).key(key).add(field).add(value), BuilderFactory.LONG);
  }

  public final CommandObject hset(String key, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(HSET).key(key), hash), BuilderFactory.LONG);
  }

  public final CommandObject hget(String key, String field) {
    return new CommandObject<>(commandArguments(HGET).key(key).add(field), BuilderFactory.STRING);
  }

  public final CommandObject hsetnx(String key, String field, String value) {
    return new CommandObject<>(commandArguments(HSETNX).key(key).add(field).add(value), BuilderFactory.LONG);
  }

  public final CommandObject hmset(String key, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(HMSET).key(key), hash), BuilderFactory.STRING);
  }

  public final CommandObject> hmget(String key, String... fields) {
    return new CommandObject<>(commandArguments(HMGET).key(key).addObjects((Object[]) fields), BuilderFactory.STRING_LIST);
  }

  public final CommandObject hset(byte[] key, byte[] field, byte[] value) {
    return new CommandObject<>(commandArguments(HSET).key(key).add(field).add(value), BuilderFactory.LONG);
  }

  public final CommandObject hset(byte[] key, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(HSET).key(key), hash), BuilderFactory.LONG);
  }

  public final CommandObject hget(byte[] key, byte[] field) {
    return new CommandObject<>(commandArguments(HGET).key(key).add(field), BuilderFactory.BINARY);
  }

  public final CommandObject hsetnx(byte[] key, byte[] field, byte[] value) {
    return new CommandObject<>(commandArguments(HSETNX).key(key).add(field).add(value), BuilderFactory.LONG);
  }

  public final CommandObject hmset(byte[] key, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(HMSET).key(key), hash), BuilderFactory.STRING);
  }

  public final CommandObject> hmget(byte[] key, byte[]... fields) {
    return new CommandObject<>(commandArguments(HMGET).key(key).addObjects((Object[]) fields), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject hincrBy(String key, String field, long value) {
    return new CommandObject<>(commandArguments(HINCRBY).key(key).add(field).add(value), BuilderFactory.LONG);
  }

  public final CommandObject hincrByFloat(String key, String field, double value) {
    return new CommandObject<>(commandArguments(HINCRBYFLOAT).key(key).add(field).add(value), BuilderFactory.DOUBLE);
  }

  public final CommandObject hexists(String key, String field) {
    return new CommandObject<>(commandArguments(HEXISTS).key(key).add(field), BuilderFactory.BOOLEAN);
  }

  public final CommandObject hdel(String key, String... field) {
    return new CommandObject<>(commandArguments(HDEL).key(key).addObjects((Object[]) field), BuilderFactory.LONG);
  }

  public final CommandObject hlen(String key) {
    return new CommandObject<>(commandArguments(HLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject hincrBy(byte[] key, byte[] field, long value) {
    return new CommandObject<>(commandArguments(HINCRBY).key(key).add(field).add(value), BuilderFactory.LONG);
  }

  public final CommandObject hincrByFloat(byte[] key, byte[] field, double value) {
    return new CommandObject<>(commandArguments(HINCRBYFLOAT).key(key).add(field).add(value), BuilderFactory.DOUBLE);
  }

  public final CommandObject hexists(byte[] key, byte[] field) {
    return new CommandObject<>(commandArguments(HEXISTS).key(key).add(field), BuilderFactory.BOOLEAN);
  }

  public final CommandObject hdel(byte[] key, byte[]... field) {
    return new CommandObject<>(commandArguments(HDEL).key(key).addObjects((Object[]) field), BuilderFactory.LONG);
  }

  public final CommandObject hlen(byte[] key) {
    return new CommandObject<>(commandArguments(HLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject> hkeys(String key) {
    return new CommandObject<>(commandArguments(HKEYS).key(key), BuilderFactory.STRING_SET);
  }

  public final CommandObject> hvals(String key) {
    return new CommandObject<>(commandArguments(HVALS).key(key), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> hkeys(byte[] key) {
    return new CommandObject<>(commandArguments(HKEYS).key(key), BuilderFactory.BINARY_SET);
  }

  public final CommandObject> hvals(byte[] key) {
    return new CommandObject<>(commandArguments(HVALS).key(key), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> hgetAll(String key) {
    return new CommandObject<>(commandArguments(HGETALL).key(key), BuilderFactory.STRING_MAP);
  }

  public final CommandObject hrandfield(String key) {
    return new CommandObject<>(commandArguments(HRANDFIELD).key(key), BuilderFactory.STRING);
  }

  public final CommandObject> hrandfield(String key, long count) {
    return new CommandObject<>(commandArguments(HRANDFIELD).key(key).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject>> hrandfieldWithValues(String key, long count) {
    return new CommandObject<>(commandArguments(HRANDFIELD).key(key).add(count).add(WITHVALUES),
        protocol != RedisProtocol.RESP3 ? BuilderFactory.STRING_PAIR_LIST : BuilderFactory.STRING_PAIR_LIST_FROM_PAIRS);
  }

  public final CommandObject> hgetAll(byte[] key) {
    return new CommandObject<>(commandArguments(HGETALL).key(key), BuilderFactory.BINARY_MAP);
  }

  public final CommandObject hrandfield(byte[] key) {
    return new CommandObject<>(commandArguments(HRANDFIELD).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject> hrandfield(byte[] key, long count) {
    return new CommandObject<>(commandArguments(HRANDFIELD).key(key).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject>> hrandfieldWithValues(byte[] key, long count) {
    return new CommandObject<>(commandArguments(HRANDFIELD).key(key).add(count).add(WITHVALUES),
        protocol != RedisProtocol.RESP3 ? BuilderFactory.BINARY_PAIR_LIST : BuilderFactory.BINARY_PAIR_LIST_FROM_PAIRS);
  }

  public final CommandObject>> hscan(String key, String cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(HSCAN).key(key).add(cursor).addParams(params), BuilderFactory.HSCAN_RESPONSE);
  }

  public final CommandObject hstrlen(String key, String field) {
    return new CommandObject<>(commandArguments(HSTRLEN).key(key).add(field), BuilderFactory.LONG);
  }

  public final CommandObject>> hscan(byte[] key, byte[] cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(HSCAN).key(key).add(cursor).addParams(params), BuilderFactory.HSCAN_BINARY_RESPONSE);
  }

  public final CommandObject hstrlen(byte[] key, byte[] field) {
    return new CommandObject<>(commandArguments(HSTRLEN).key(key).add(field), BuilderFactory.LONG);
  }
  // Hash commands

  // Set commands
  public final CommandObject sadd(String key, String... members) {
    return new CommandObject<>(commandArguments(SADD).key(key).addObjects((Object[]) members), BuilderFactory.LONG);
  }

  public final CommandObject sadd(byte[] key, byte[]... members) {
    return new CommandObject<>(commandArguments(SADD).key(key).addObjects((Object[]) members), BuilderFactory.LONG);
  }

  public final CommandObject> smembers(String key) {
    return new CommandObject<>(commandArguments(SMEMBERS).key(key), BuilderFactory.STRING_SET);
  }

  public final CommandObject> smembers(byte[] key) {
    return new CommandObject<>(commandArguments(SMEMBERS).key(key), BuilderFactory.BINARY_SET);
  }

  public final CommandObject srem(String key, String... members) {
    return new CommandObject<>(commandArguments(SREM).key(key).addObjects((Object[]) members), BuilderFactory.LONG);
  }

  public final CommandObject srem(byte[] key, byte[]... members) {
    return new CommandObject<>(commandArguments(SREM).key(key).addObjects((Object[]) members), BuilderFactory.LONG);
  }

  public final CommandObject spop(String key) {
    return new CommandObject<>(commandArguments(SPOP).key(key), BuilderFactory.STRING);
  }

  public final CommandObject spop(byte[] key) {
    return new CommandObject<>(commandArguments(SPOP).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject> spop(String key, long count) {
    return new CommandObject<>(commandArguments(SPOP).key(key).add(count), BuilderFactory.STRING_SET);
  }

  public final CommandObject> spop(byte[] key, long count) {
    return new CommandObject<>(commandArguments(SPOP).key(key).add(count), BuilderFactory.BINARY_SET);
  }

  public final CommandObject scard(String key) {
    return new CommandObject<>(commandArguments(SCARD).key(key), BuilderFactory.LONG);
  }

  public final CommandObject scard(byte[] key) {
    return new CommandObject<>(commandArguments(SCARD).key(key), BuilderFactory.LONG);
  }

  public final CommandObject sismember(String key, String member) {
    return new CommandObject<>(commandArguments(SISMEMBER).key(key).add(member), BuilderFactory.BOOLEAN);
  }

  public final CommandObject sismember(byte[] key, byte[] member) {
    return new CommandObject<>(commandArguments(SISMEMBER).key(key).add(member), BuilderFactory.BOOLEAN);
  }

  public final CommandObject> smismember(String key, String... members) {
    return new CommandObject<>(commandArguments(SMISMEMBER).key(key).addObjects((Object[]) members), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject> smismember(byte[] key, byte[]... members) {
    return new CommandObject<>(commandArguments(SMISMEMBER).key(key).addObjects((Object[]) members), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject srandmember(String key) {
    return new CommandObject<>(commandArguments(SRANDMEMBER).key(key), BuilderFactory.STRING);
  }

  public final CommandObject srandmember(byte[] key) {
    return new CommandObject<>(commandArguments(SRANDMEMBER).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject> srandmember(String key, int count) {
    return new CommandObject<>(commandArguments(SRANDMEMBER).key(key).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> srandmember(byte[] key, int count) {
    return new CommandObject<>(commandArguments(SRANDMEMBER).key(key).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> sscan(String key, String cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(SSCAN).key(key).add(cursor).addParams(params), BuilderFactory.SSCAN_RESPONSE);
  }

  public final CommandObject> sscan(byte[] key, byte[] cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(SSCAN).key(key).add(cursor).addParams(params), BuilderFactory.SSCAN_BINARY_RESPONSE);
  }

  public final CommandObject> sdiff(String... keys) {
    return new CommandObject<>(commandArguments(SDIFF).keys((Object[]) keys), BuilderFactory.STRING_SET);
  }

  public final CommandObject sdiffstore(String dstkey, String... keys) {
    return new CommandObject<>(commandArguments(SDIFFSTORE).key(dstkey).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject> sdiff(byte[]... keys) {
    return new CommandObject<>(commandArguments(SDIFF).keys((Object[]) keys), BuilderFactory.BINARY_SET);
  }

  public final CommandObject sdiffstore(byte[] dstkey, byte[]... keys) {
    return new CommandObject<>(commandArguments(SDIFFSTORE).key(dstkey).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject> sinter(String... keys) {
    return new CommandObject<>(commandArguments(SINTER).keys((Object[]) keys), BuilderFactory.STRING_SET);
  }

  public final CommandObject sinterstore(String dstkey, String... keys) {
    return new CommandObject<>(commandArguments(SINTERSTORE).key(dstkey).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject sintercard(String... keys) {
    return new CommandObject<>(commandArguments(SINTERCARD).add(keys.length).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject sintercard(int limit, String... keys) {
    return new CommandObject<>(commandArguments(SINTERCARD).add(keys.length).keys((Object[]) keys).add(LIMIT).add(limit),BuilderFactory.LONG);
  }

  public final CommandObject> sinter(byte[]... keys) {
    return new CommandObject<>(commandArguments(SINTER).keys((Object[]) keys), BuilderFactory.BINARY_SET);
  }

  public final CommandObject sinterstore(byte[] dstkey, byte[]... keys) {
    return new CommandObject<>(commandArguments(SINTERSTORE).key(dstkey).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject sintercard(byte[]... keys) {
    return new CommandObject<>(commandArguments(SINTERCARD).add(keys.length).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject sintercard(int limit, byte[]... keys) {
    return new CommandObject<>(commandArguments(SINTERCARD).add(keys.length).keys((Object[]) keys).add(LIMIT).add(limit),BuilderFactory.LONG);
  }

  public final CommandObject> sunion(String... keys) {
    return new CommandObject<>(commandArguments(SUNION).keys((Object[]) keys), BuilderFactory.STRING_SET);
  }

  public final CommandObject sunionstore(String dstkey, String... keys) {
    return new CommandObject<>(commandArguments(SUNIONSTORE).key(dstkey).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject> sunion(byte[]... keys) {
    return new CommandObject<>(commandArguments(SUNION).keys((Object[]) keys), BuilderFactory.BINARY_SET);
  }

  public final CommandObject sunionstore(byte[] dstkey, byte[]... keys) {
    return new CommandObject<>(commandArguments(SUNIONSTORE).key(dstkey).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject smove(String srckey, String dstkey, String member) {
    return new CommandObject<>(commandArguments(SMOVE).key(srckey).key(dstkey).add(member), BuilderFactory.LONG);
  }

  public final CommandObject smove(byte[] srckey, byte[] dstkey, byte[] member) {
    return new CommandObject<>(commandArguments(SMOVE).key(srckey).key(dstkey).add(member), BuilderFactory.LONG);
  }
  // Set commands

  // Sorted Set commands
  public final CommandObject zadd(String key, double score, String member) {
    return new CommandObject<>(commandArguments(ZADD).key(key).add(score).add(member), BuilderFactory.LONG);
  }

  public final CommandObject zadd(String key, double score, String member, ZAddParams params) {
    return new CommandObject<>(commandArguments(ZADD).key(key).addParams(params)
        .add(score).add(member), BuilderFactory.LONG);
  }

  public final CommandObject zadd(String key, Map scoreMembers) {
    return new CommandObject<>(addSortedSetFlatMapArgs(commandArguments(ZADD).key(key), scoreMembers), BuilderFactory.LONG);
  }

  public final CommandObject zadd(String key, Map scoreMembers, ZAddParams params) {
    return new CommandObject<>(addSortedSetFlatMapArgs(commandArguments(ZADD).key(key).addParams(params), scoreMembers), BuilderFactory.LONG);
  }

  public final CommandObject zaddIncr(String key, double score, String member, ZAddParams params) {
    return new CommandObject<>(commandArguments(ZADD).key(key).add(Keyword.INCR)
        .addParams(params).add(score).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject zadd(byte[] key, double score, byte[] member) {
    return new CommandObject<>(commandArguments(ZADD).key(key).add(score).add(member), BuilderFactory.LONG);
  }

  public final CommandObject zadd(byte[] key, double score, byte[] member, ZAddParams params) {
    return new CommandObject<>(commandArguments(ZADD).key(key).addParams(params)
        .add(score).add(member), BuilderFactory.LONG);
  }

  public final CommandObject zadd(byte[] key, Map scoreMembers) {
    return new CommandObject<>(addSortedSetFlatMapArgs(commandArguments(ZADD).key(key), scoreMembers), BuilderFactory.LONG);
  }

  public final CommandObject zadd(byte[] key, Map scoreMembers, ZAddParams params) {
    return new CommandObject<>(addSortedSetFlatMapArgs(commandArguments(ZADD).key(key).addParams(params), scoreMembers), BuilderFactory.LONG);
  }

  public final CommandObject zaddIncr(byte[] key, double score, byte[] member, ZAddParams params) {
    return new CommandObject<>(commandArguments(ZADD).key(key).add(Keyword.INCR)
        .addParams(params).add(score).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject zincrby(String key, double increment, String member) {
    return new CommandObject<>(commandArguments(ZINCRBY).key(key).add(increment).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject zincrby(String key, double increment, String member, ZIncrByParams params) {
    return new CommandObject<>(commandArguments(ZADD).key(key).addParams(params).add(increment).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject zincrby(byte[] key, double increment, byte[] member) {
    return new CommandObject<>(commandArguments(ZINCRBY).key(key).add(increment).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject zincrby(byte[] key, double increment, byte[] member, ZIncrByParams params) {
    return new CommandObject<>(commandArguments(ZADD).key(key).addParams(params).add(increment).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject zrem(String key, String... members) {
    return new CommandObject<>(commandArguments(ZREM).key(key).addObjects((Object[]) members), BuilderFactory.LONG);
  }

  public final CommandObject zrem(byte[] key, byte[]... members) {
    return new CommandObject<>(commandArguments(ZREM).key(key).addObjects((Object[]) members), BuilderFactory.LONG);
  }

  public final CommandObject zrank(String key, String member) {
    return new CommandObject<>(commandArguments(ZRANK).key(key).add(member), BuilderFactory.LONG);
  }

  public final CommandObject zrevrank(String key, String member) {
    return new CommandObject<>(commandArguments(ZREVRANK).key(key).add(member), BuilderFactory.LONG);
  }

  public final CommandObject> zrankWithScore(String key, String member) {
    return new CommandObject<>(commandArguments(ZRANK).key(key).add(member).add(WITHSCORE), BuilderFactory.ZRANK_WITHSCORE_PAIR);
  }

  public final CommandObject> zrevrankWithScore(String key, String member) {
    return new CommandObject<>(commandArguments(ZREVRANK).key(key).add(member).add(WITHSCORE), BuilderFactory.ZRANK_WITHSCORE_PAIR);
  }

  public final CommandObject zrank(byte[] key, byte[] member) {
    return new CommandObject<>(commandArguments(ZRANK).key(key).add(member), BuilderFactory.LONG);
  }

  public final CommandObject zrevrank(byte[] key, byte[] member) {
    return new CommandObject<>(commandArguments(ZREVRANK).key(key).add(member), BuilderFactory.LONG);
  }

  public final CommandObject> zrankWithScore(byte[] key, byte[] member) {
    return new CommandObject<>(commandArguments(ZRANK).key(key).add(member).add(WITHSCORE), BuilderFactory.ZRANK_WITHSCORE_PAIR);
  }

  public final CommandObject> zrevrankWithScore(byte[] key, byte[] member) {
    return new CommandObject<>(commandArguments(ZREVRANK).key(key).add(member).add(WITHSCORE), BuilderFactory.ZRANK_WITHSCORE_PAIR);
  }

  public final CommandObject zrandmember(String key) {
    return new CommandObject<>(commandArguments(ZRANDMEMBER).key(key), BuilderFactory.STRING);
  }

  public final CommandObject> zrandmember(String key, long count) {
    return new CommandObject<>(commandArguments(ZRANDMEMBER).key(key).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrandmemberWithScores(String key, long count) {
    return new CommandObject<>(commandArguments(ZRANDMEMBER).key(key).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zrandmember(byte[] key) {
    return new CommandObject<>(commandArguments(ZRANDMEMBER).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject> zrandmember(byte[] key, long count) {
    return new CommandObject<>(commandArguments(ZRANDMEMBER).key(key).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrandmemberWithScores(byte[] key, long count) {
    return new CommandObject<>(commandArguments(ZRANDMEMBER).key(key).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zcard(String key) {
    return new CommandObject<>(commandArguments(ZCARD).key(key), BuilderFactory.LONG);
  }

  public final CommandObject zscore(String key, String member) {
    return new CommandObject<>(commandArguments(ZSCORE).key(key).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject> zmscore(String key, String... members) {
    return new CommandObject<>(commandArguments(ZMSCORE).key(key).addObjects((Object[]) members), BuilderFactory.DOUBLE_LIST);
  }

  public final CommandObject zcard(byte[] key) {
    return new CommandObject<>(commandArguments(ZCARD).key(key), BuilderFactory.LONG);
  }

  public final CommandObject zscore(byte[] key, byte[] member) {
    return new CommandObject<>(commandArguments(ZSCORE).key(key).add(member), BuilderFactory.DOUBLE);
  }

  public final CommandObject> zmscore(byte[] key, byte[]... members) {
    return new CommandObject<>(commandArguments(ZMSCORE).key(key).addObjects((Object[]) members), BuilderFactory.DOUBLE_LIST);
  }

  public final CommandObject zpopmax(String key) {
    return new CommandObject<>(commandArguments(ZPOPMAX).key(key), BuilderFactory.TUPLE);
  }

  public final CommandObject> zpopmax(String key, int count) {
    return new CommandObject<>(commandArguments(ZPOPMAX).key(key).add(count), getTupleListBuilder());
  }

  public final CommandObject zpopmin(String key) {
    return new CommandObject<>(commandArguments(ZPOPMIN).key(key), BuilderFactory.TUPLE);
  }

  public final CommandObject> zpopmin(String key, int count) {
    return new CommandObject<>(commandArguments(ZPOPMIN).key(key).add(count), getTupleListBuilder());
  }

  public final CommandObject zpopmax(byte[] key) {
    return new CommandObject<>(commandArguments(ZPOPMAX).key(key), BuilderFactory.TUPLE);
  }

  public final CommandObject> zpopmax(byte[] key, int count) {
    return new CommandObject<>(commandArguments(ZPOPMAX).key(key).add(count), getTupleListBuilder());
  }

  public final CommandObject zpopmin(byte[] key) {
    return new CommandObject<>(commandArguments(ZPOPMIN).key(key), BuilderFactory.TUPLE);
  }

  public final CommandObject> zpopmin(byte[] key, int count) {
    return new CommandObject<>(commandArguments(ZPOPMIN).key(key).add(count), getTupleListBuilder());
  }

  public final CommandObject> bzpopmax(double timeout, String... keys) {
    return new CommandObject<>(commandArguments(BZPOPMAX).blocking().keys((Object[]) keys).add(timeout),
        BuilderFactory.KEYED_TUPLE);
  }

  public final CommandObject> bzpopmin(double timeout, String... keys) {
    return new CommandObject<>(commandArguments(BZPOPMIN).blocking().keys((Object[]) keys).add(timeout),
        BuilderFactory.KEYED_TUPLE);
  }

  public final CommandObject> bzpopmax(double timeout, byte[]... keys) {
    return new CommandObject<>(commandArguments(BZPOPMAX).blocking().keys((Object[]) keys)
        .add(timeout), BuilderFactory.BINARY_KEYED_TUPLE);
  }

  public final CommandObject> bzpopmin(double timeout, byte[]... keys) {
    return new CommandObject<>(commandArguments(BZPOPMIN).blocking().keys((Object[]) keys)
        .add(timeout), BuilderFactory.BINARY_KEYED_TUPLE);
  }

  public final CommandObject zcount(String key, double min, double max) {
    return new CommandObject<>(commandArguments(ZCOUNT).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zcount(String key, String min, String max) {
    return new CommandObject<>(commandArguments(ZCOUNT).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zcount(byte[] key, double min, double max) {
    return new CommandObject<>(commandArguments(ZCOUNT).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zcount(byte[] key, byte[] min, byte[] max) {
    return new CommandObject<>(commandArguments(ZCOUNT).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject> zrange(String key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key).add(start).add(stop), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrevrange(String key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZREVRANGE).key(key).add(start).add(stop), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrangeWithScores(String key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key)
        .add(start).add(stop).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeWithScores(String key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZREVRANGE).key(key)
        .add(start).add(stop).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrange(String key, ZRangeParams zRangeParams) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key).addParams(zRangeParams), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrangeWithScores(String key, ZRangeParams zRangeParams) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key).addParams(zRangeParams).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zrangestore(String dest, String src, ZRangeParams zRangeParams) {
    return new CommandObject<>(commandArguments(ZRANGESTORE).key(dest).add(src).addParams(zRangeParams), BuilderFactory.LONG);
  }

  public final CommandObject> zrangeByScore(String key, double min, double max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrangeByScore(String key, String min, String max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrevrangeByScore(String key, double max, double min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrevrangeByScore(String key, String max, String min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrangeByScore(String key, double min, double max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrangeByScore(String key, String min, String max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrevrangeByScore(String key, double max, double min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrevrangeByScore(String key, String max, String min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrangeByScoreWithScores(String key, double min, double max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrangeByScoreWithScores(String key, String min, String max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(String key, double max, double min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(String key, String max, String min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrangeByScoreWithScores(String key, double min, double max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrangeByScoreWithScores(String key, String min, String max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(String key, double max, double min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(String key, String max, String min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrange(byte[] key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key).add(start).add(stop), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrevrange(byte[] key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZREVRANGE).key(key).add(start).add(stop), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrangeWithScores(byte[] key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key)
        .add(start).add(stop).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeWithScores(byte[] key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZREVRANGE).key(key)
        .add(start).add(stop).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrange(byte[] key, ZRangeParams zRangeParams) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key).addParams(zRangeParams), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrangeWithScores(byte[] key, ZRangeParams zRangeParams) {
    return new CommandObject<>(commandArguments(ZRANGE).key(key).addParams(zRangeParams).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zrangestore(byte[] dest, byte[] src, ZRangeParams zRangeParams) {
    return new CommandObject<>(commandArguments(ZRANGESTORE).key(dest).add(src).addParams(zRangeParams), BuilderFactory.LONG);
  }

  public final CommandObject> zrangeByScore(byte[] key, double min, double max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrangeByScore(byte[] key, byte[] min, byte[] max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrevrangeByScore(byte[] key, double max, double min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrevrangeByScore(byte[] key, byte[] max, byte[] min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrangeByScore(byte[] key, double min, double max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrangeByScore(byte[] key, byte[] min, byte[] max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrevrangeByScore(byte[] key, double max, double min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrevrangeByScore(byte[] key, byte[] max, byte[] min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrangeByScoreWithScores(byte[] key, double min, double max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrangeByScoreWithScores(byte[] key, byte[] min, byte[] max) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(byte[] key, double max, double min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(byte[] key, byte[] max, byte[] min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrangeByScoreWithScores(byte[] key, double min, double max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrangeByScoreWithScores(byte[] key, byte[] min, byte[] max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYSCORE).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(byte[] key, double max, double min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject> zrevrangeByScoreWithScores(byte[] key, byte[] max, byte[] min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYSCORE).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zremrangeByRank(String key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYRANK).key(key).add(start).add(stop), BuilderFactory.LONG);
  }

  public final CommandObject zremrangeByScore(String key, double min, double max) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zremrangeByScore(String key, String min, String max) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zremrangeByRank(byte[] key, long start, long stop) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYRANK).key(key).add(start).add(stop), BuilderFactory.LONG);
  }

  public final CommandObject zremrangeByScore(byte[] key, double min, double max) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zremrangeByScore(byte[] key, byte[] min, byte[] max) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYSCORE).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zlexcount(String key, String min, String max) {
    return new CommandObject<>(commandArguments(ZLEXCOUNT).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject> zrangeByLex(String key, String min, String max) {
    return new CommandObject<>(commandArguments(ZRANGEBYLEX).key(key).add(min).add(max), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrangeByLex(String key, String min, String max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYLEX).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrevrangeByLex(String key, String max, String min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYLEX).key(key).add(max).add(min), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zrevrangeByLex(String key, String max, String min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYLEX).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count), BuilderFactory.STRING_LIST);
  }

  public final CommandObject zremrangeByLex(String key, String min, String max) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYLEX).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject zlexcount(byte[] key, byte[] min, byte[] max) {
    return new CommandObject<>(commandArguments(ZLEXCOUNT).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject> zrangeByLex(byte[] key, byte[] min, byte[] max) {
    return new CommandObject<>(commandArguments(ZRANGEBYLEX).key(key).add(min).add(max), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrangeByLex(byte[] key, byte[] min, byte[] max, int offset, int count) {
    return new CommandObject<>(commandArguments(ZRANGEBYLEX).key(key).add(min).add(max)
        .add(LIMIT).add(offset).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrevrangeByLex(byte[] key, byte[] max, byte[] min) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYLEX).key(key).add(max).add(min), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zrevrangeByLex(byte[] key, byte[] max, byte[] min, int offset, int count) {
    return new CommandObject<>(commandArguments(ZREVRANGEBYLEX).key(key).add(max).add(min)
        .add(LIMIT).add(offset).add(count), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject zremrangeByLex(byte[] key, byte[] min, byte[] max) {
    return new CommandObject<>(commandArguments(ZREMRANGEBYLEX).key(key).add(min).add(max), BuilderFactory.LONG);
  }

  public final CommandObject> zscan(String key, String cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(ZSCAN).key(key).add(cursor).addParams(params), BuilderFactory.ZSCAN_RESPONSE);
  }

  public final CommandObject> zscan(byte[] key, byte[] cursor, ScanParams params) {
    return new CommandObject<>(commandArguments(ZSCAN).key(key).add(cursor).addParams(params), BuilderFactory.ZSCAN_RESPONSE);
  }

  public final CommandObject> zdiff(String... keys) {
    return new CommandObject<>(commandArguments(ZDIFF).add(keys.length).keys((Object[]) keys),
        BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zdiffWithScores(String... keys) {
    return new CommandObject<>(commandArguments(ZDIFF).add(keys.length).keys((Object[]) keys)
        .add(WITHSCORES), getTupleListBuilder());
  }

  /**
   * @deprecated Use {@link #zdiffstore(java.lang.String, java.lang.String...)}.
   */
  @Deprecated
  public final CommandObject zdiffStore(String dstkey, String... keys) {
    return zdiffstore(dstkey, keys);
  }

  public final CommandObject zdiffstore(String dstkey, String... keys) {
    return new CommandObject<>(commandArguments(ZDIFFSTORE).key(dstkey)
        .add(keys.length).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject> zdiff(byte[]... keys) {
    return new CommandObject<>(commandArguments(ZDIFF).add(keys.length).keys((Object[]) keys), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zdiffWithScores(byte[]... keys) {
    return new CommandObject<>(commandArguments(ZDIFF).add(keys.length).keys((Object[]) keys)
        .add(WITHSCORES), getTupleListBuilder());
  }

  /**
   * @deprecated Use {@link #zdiffstore(byte..., byte[]...)}.
   */
  @Deprecated
  public final CommandObject zdiffStore(byte[] dstkey, byte[]... keys) {
    return zdiffstore(dstkey, keys);
  }

  public final CommandObject zdiffstore(byte[] dstkey, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZDIFFSTORE).key(dstkey)
        .add(keys.length).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject> zinter(ZParams params, String... keys) {
    return new CommandObject<>(commandArguments(ZINTER).add(keys.length).keys((Object[]) keys)
        .addParams(params), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zinterWithScores(ZParams params, String... keys) {
    return new CommandObject<>(commandArguments(ZINTER).add(keys.length).keys((Object[]) keys)
        .addParams(params).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zinterstore(String dstkey, String... keys) {
    return new CommandObject<>(commandArguments(ZINTERSTORE).key(dstkey)
        .add(keys.length).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject zinterstore(String dstkey, ZParams params, String... keys) {
    return new CommandObject<>(commandArguments(ZINTERSTORE).key(dstkey)
        .add(keys.length).keys((Object[]) keys).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject zintercard(String... keys) {
    return new CommandObject<>(commandArguments(ZINTERCARD).add(keys.length)
        .keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject zintercard(long limit, String... keys) {
    return new CommandObject<>(commandArguments(ZINTERCARD).add(keys.length)
        .keys((Object[]) keys).add(LIMIT).add(limit), BuilderFactory.LONG);
  }

  public final CommandObject zinterstore(byte[] dstkey, byte[]... sets) {
    return new CommandObject<>(commandArguments(ZINTERSTORE).key(dstkey)
        .add(sets.length).keys((Object[]) sets), BuilderFactory.LONG);
  }

  public final CommandObject zinterstore(byte[] dstkey, ZParams params, byte[]... sets) {
    return new CommandObject<>(commandArguments(ZINTERSTORE).key(dstkey)
        .add(sets.length).keys((Object[]) sets).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject zintercard(byte[]... keys) {
    return new CommandObject<>(commandArguments(ZINTERCARD).add(keys.length)
        .keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject zintercard(long limit, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZINTERCARD).add(keys.length)
        .keys((Object[]) keys).add(LIMIT).add(limit), BuilderFactory.LONG);
  }

  public final CommandObject> zinter(ZParams params, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZINTER).add(keys.length).keys((Object[]) keys)
        .addParams(params), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zinterWithScores(ZParams params, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZINTER).add(keys.length).keys((Object[]) keys)
        .addParams(params).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zunionstore(String dstkey, String... sets) {
    return new CommandObject<>(commandArguments(ZUNIONSTORE).key(dstkey)
        .add(sets.length).keys((Object[]) sets), BuilderFactory.LONG);
  }

  public final CommandObject zunionstore(String dstkey, ZParams params, String... sets) {
    return new CommandObject<>(commandArguments(ZUNIONSTORE).key(dstkey)
        .add(sets.length).keys((Object[]) sets).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject> zunion(ZParams params, String... keys) {
    return new CommandObject<>(commandArguments(ZUNION).add(keys.length).keys((Object[]) keys)
        .addParams(params), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> zunionWithScores(ZParams params, String... keys) {
    return new CommandObject<>(commandArguments(ZUNION).add(keys.length).keys((Object[]) keys)
        .addParams(params).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject zunionstore(byte[] dstkey, byte[]... sets) {
    return new CommandObject<>(commandArguments(ZUNIONSTORE).key(dstkey)
        .add(sets.length).keys((Object[]) sets), BuilderFactory.LONG);
  }

  public final CommandObject zunionstore(byte[] dstkey, ZParams params, byte[]... sets) {
    return new CommandObject<>(commandArguments(ZUNIONSTORE).key(dstkey)
        .add(sets.length).keys((Object[]) sets).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject> zunion(ZParams params, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZUNION).add(keys.length).keys((Object[]) keys)
        .addParams(params), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> zunionWithScores(ZParams params, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZUNION).add(keys.length).keys((Object[]) keys)
        .addParams(params).add(WITHSCORES), getTupleListBuilder());
  }

  public final CommandObject>> zmpop(SortedSetOption option, String... keys) {
    return new CommandObject<>(commandArguments(ZMPOP).add(keys.length).keys((Object[]) keys)
        .add(option), BuilderFactory.KEYED_TUPLE_LIST);
  }

  public final CommandObject>> zmpop(SortedSetOption option, int count, String... keys) {
    return new CommandObject<>(commandArguments(ZMPOP).add(keys.length).keys((Object[]) keys)
        .add(option).add(COUNT).add(count), BuilderFactory.KEYED_TUPLE_LIST);
  }

  public final CommandObject>> bzmpop(double timeout, SortedSetOption option, String... keys) {
    return new CommandObject<>(commandArguments(BZMPOP).blocking().add(timeout).add(keys.length)
        .keys((Object[]) keys).add(option), BuilderFactory.KEYED_TUPLE_LIST);
  }

  public final CommandObject>> bzmpop(double timeout, SortedSetOption option, int count, String... keys) {
    return new CommandObject<>(commandArguments(BZMPOP).blocking().add(timeout).add(keys.length)
        .keys((Object[]) keys).add(option).add(COUNT).add(count), BuilderFactory.KEYED_TUPLE_LIST);
  }

  public final CommandObject>> zmpop(SortedSetOption option, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZMPOP).add(keys.length).keys((Object[]) keys)
        .add(option), BuilderFactory.BINARY_KEYED_TUPLE_LIST);
  }

  public final CommandObject>> zmpop(SortedSetOption option, int count, byte[]... keys) {
    return new CommandObject<>(commandArguments(ZMPOP).add(keys.length).keys((Object[]) keys)
        .add(option).add(COUNT).add(count), BuilderFactory.BINARY_KEYED_TUPLE_LIST);
  }

  public final CommandObject>> bzmpop(double timeout, SortedSetOption option, byte[]... keys) {
    return new CommandObject<>(commandArguments(BZMPOP).blocking().add(timeout).add(keys.length)
        .keys((Object[]) keys).add(option), BuilderFactory.BINARY_KEYED_TUPLE_LIST);
  }

  public final CommandObject>> bzmpop(double timeout, SortedSetOption option, int count, byte[]... keys) {
    return new CommandObject<>(commandArguments(BZMPOP).blocking().add(timeout).add(keys.length)
        .keys((Object[]) keys).add(option).add(COUNT).add(count), BuilderFactory.BINARY_KEYED_TUPLE_LIST);
  }

  private Builder> getTupleListBuilder() {
    return protocol == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_LIST_RESP3 : BuilderFactory.TUPLE_LIST;
  }

  private Builder> getTupleSetBuilder() {
    return protocol == RedisProtocol.RESP3 ? BuilderFactory.TUPLE_ZSET_RESP3 : BuilderFactory.TUPLE_ZSET;
  }
  // Sorted Set commands

  // Geo commands
  public final CommandObject geoadd(String key, double longitude, double latitude, String member) {
    return new CommandObject<>(commandArguments(GEOADD).key(key).add(longitude).add(latitude).add(member), BuilderFactory.LONG);
  }

  public final CommandObject geoadd(String key, Map memberCoordinateMap) {
    return new CommandObject<>(addGeoCoordinateFlatMapArgs(commandArguments(GEOADD).key(key), memberCoordinateMap), BuilderFactory.LONG);
  }

  public final CommandObject geoadd(String key, GeoAddParams params, Map memberCoordinateMap) {
    return new CommandObject<>(addGeoCoordinateFlatMapArgs(commandArguments(GEOADD).key(key).addParams(params), memberCoordinateMap), BuilderFactory.LONG);
  }

  public final CommandObject geodist(String key, String member1, String member2) {
    return new CommandObject<>(commandArguments(GEODIST).key(key).add(member1).add(member2), BuilderFactory.DOUBLE);
  }

  public final CommandObject geodist(String key, String member1, String member2, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEODIST).key(key).add(member1).add(member2).add(unit), BuilderFactory.DOUBLE);
  }

  public final CommandObject> geohash(String key, String... members) {
    return new CommandObject<>(commandArguments(GEOHASH).key(key).addObjects((Object[]) members), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> geopos(String key, String... members) {
    return new CommandObject<>(commandArguments(GEOPOS).key(key).addObjects((Object[]) members),
        BuilderFactory.GEO_COORDINATE_LIST);
  }

  public final CommandObject geoadd(byte[] key, double longitude, double latitude, byte[] member) {
    return new CommandObject<>(commandArguments(GEOADD).key(key).add(longitude).add(latitude).add(member), BuilderFactory.LONG);
  }

  public final CommandObject geoadd(byte[] key, Map memberCoordinateMap) {
    return new CommandObject<>(addGeoCoordinateFlatMapArgs(commandArguments(GEOADD).key(key), memberCoordinateMap), BuilderFactory.LONG);
  }

  public final CommandObject geoadd(byte[] key, GeoAddParams params, Map memberCoordinateMap) {
    return new CommandObject<>(addGeoCoordinateFlatMapArgs(commandArguments(GEOADD).key(key).addParams(params), memberCoordinateMap), BuilderFactory.LONG);
  }

  public final CommandObject geodist(byte[] key, byte[] member1, byte[] member2) {
    return new CommandObject<>(commandArguments(GEODIST).key(key).add(member1).add(member2), BuilderFactory.DOUBLE);
  }

  public final CommandObject geodist(byte[] key, byte[] member1, byte[] member2, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEODIST).key(key).add(member1).add(member2).add(unit), BuilderFactory.DOUBLE);
  }

  public final CommandObject> geohash(byte[] key, byte[]... members) {
    return new CommandObject<>(commandArguments(GEOHASH).key(key).addObjects((Object[]) members), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> geopos(byte[] key, byte[]... members) {
    return new CommandObject<>(commandArguments(GEOPOS).key(key).addObjects((Object[]) members),
        BuilderFactory.GEO_COORDINATE_LIST);
  }

  public final CommandObject> georadius(String key, double longitude, double latitude, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUS).key(key).add(longitude).add(latitude)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadius(String key,
      double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUS).key(key).add(longitude).add(latitude)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusReadonly(String key, double longitude, double latitude, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUS_RO).key(key).add(longitude).add(latitude)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusReadonly(String key,
      double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUS_RO).key(key).add(longitude).add(latitude)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject georadiusStore(String key, double longitude, double latitude,
      double radius, GeoUnit unit, GeoRadiusParam param, GeoRadiusStoreParam storeParam) {
    return new CommandObject<>(commandArguments(GEORADIUS).key(key).add(longitude).add(latitude)
        .add(radius).add(unit).addParams(param).addParams(storeParam), BuilderFactory.LONG);
  }

  public final CommandObject> georadiusByMember(String key, String member, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER).key(key).add(member)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusByMember(String key,
      String member, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER).key(key).add(member)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusByMemberReadonly(String key, String member, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER_RO).key(key).add(member)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusByMemberReadonly(String key,
      String member, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER_RO).key(key).add(member)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject georadiusByMemberStore(String key, String member,
      double radius, GeoUnit unit, GeoRadiusParam param, GeoRadiusStoreParam storeParam) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER).key(key).add(member)
        .add(radius).add(unit).addParams(param).addParams(storeParam), BuilderFactory.LONG);
  }

  public final CommandObject> georadius(byte[] key, double longitude, double latitude, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUS).key(key).add(longitude).add(latitude)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadius(byte[] key,
      double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUS).key(key).add(longitude).add(latitude)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusReadonly(byte[] key,
      double longitude, double latitude, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUS_RO).key(key).add(longitude).add(latitude)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusReadonly(byte[] key,
      double longitude, double latitude, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUS_RO).key(key).add(longitude).add(latitude)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject georadiusStore(byte[] key, double longitude, double latitude,
      double radius, GeoUnit unit, GeoRadiusParam param, GeoRadiusStoreParam storeParam) {
    return new CommandObject<>(commandArguments(GEORADIUS).key(key).add(longitude).add(latitude)
        .add(radius).add(unit).addParams(param).addParams(storeParam), BuilderFactory.LONG);
  }

  public final CommandObject> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER).key(key).add(member)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusByMember(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER).key(key).add(member)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusByMemberReadonly(byte[] key, byte[] member, double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER_RO).key(key).add(member)
        .add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> georadiusByMemberReadonly(byte[] key, byte[] member, double radius, GeoUnit unit, GeoRadiusParam param) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER_RO).key(key).add(member)
        .add(radius).add(unit).addParams(param), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject georadiusByMemberStore(byte[] key, byte[] member,
      double radius, GeoUnit unit, GeoRadiusParam param, GeoRadiusStoreParam storeParam) {
    return new CommandObject<>(commandArguments(GEORADIUSBYMEMBER).key(key).add(member)
        .add(radius).add(unit).addParams(param).addParams(storeParam), BuilderFactory.LONG);
  }

  public final CommandObject> geosearch(String key, String member,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key).add(FROMMEMBER).add(member)
        .add(BYRADIUS).add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(String key, GeoCoordinate coord,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key)
        .add(FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude())
        .add(BYRADIUS).add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(String key, String member,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key).add(FROMMEMBER).add(member)
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(String key, GeoCoordinate coord,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key)
        .add(FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude())
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(String key, GeoSearchParam params) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key).addParams(params),
        BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject geosearchStore(String dest, String src, String member,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).add(FROMMEMBER).add(member)
        .add(BYRADIUS).add(radius).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(String dest, String src, GeoCoordinate coord,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).add(FROMLONLAT).add(coord.getLongitude())
        .add(coord.getLatitude()).add(BYRADIUS).add(radius).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(String dest, String src, String member,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).add(FROMMEMBER).add(member)
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(String dest, String src, GeoCoordinate coord,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src)
        .add(FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude())
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(String dest, String src, GeoSearchParam params) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStoreStoreDist(String dest, String src, GeoSearchParam params) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).addParams(params).add(STOREDIST), BuilderFactory.LONG);
  }

  public final CommandObject> geosearch(byte[] key, byte[] member,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key).add(FROMMEMBER).add(member)
        .add(BYRADIUS).add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(byte[] key, GeoCoordinate coord,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key)
        .add(FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude())
        .add(BYRADIUS).add(radius).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(byte[] key, byte[] member,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key).add(FROMMEMBER).add(member)
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(byte[] key, GeoCoordinate coord,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key)
        .add(FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude())
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject> geosearch(byte[] key, GeoSearchParam params) {
    return new CommandObject<>(commandArguments(GEOSEARCH).key(key).addParams(params),
        BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT);
  }

  public final CommandObject geosearchStore(byte[] dest, byte[] src, byte[] member,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).add(FROMMEMBER).add(member)
        .add(BYRADIUS).add(radius).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(byte[] dest, byte[] src, GeoCoordinate coord,
      double radius, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src)
        .add(FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude())
        .add(BYRADIUS).add(radius).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(byte[] dest, byte[] src, byte[] member,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).add(FROMMEMBER).add(member)
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(byte[] dest, byte[] src, GeoCoordinate coord,
      double width, double height, GeoUnit unit) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src)
        .add(FROMLONLAT).add(coord.getLongitude()).add(coord.getLatitude())
        .add(BYBOX).add(width).add(height).add(unit), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStore(byte[] dest, byte[] src, GeoSearchParam params) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject geosearchStoreStoreDist(byte[] dest, byte[] src, GeoSearchParam params) {
    return new CommandObject<>(commandArguments(GEOSEARCHSTORE).key(dest).add(src).addParams(params).add(STOREDIST), BuilderFactory.LONG);
  }
  // Geo commands

  // Hyper Log Log commands
  public final CommandObject pfadd(String key, String... elements) {
    return new CommandObject<>(commandArguments(PFADD).key(key).addObjects((Object[]) elements), BuilderFactory.LONG);
  }

  public final CommandObject pfmerge(String destkey, String... sourcekeys) {
    return new CommandObject<>(commandArguments(PFMERGE).key(destkey).keys((Object[]) sourcekeys), BuilderFactory.STRING);
  }

  public final CommandObject pfadd(byte[] key, byte[]... elements) {
    return new CommandObject<>(commandArguments(PFADD).key(key).addObjects((Object[]) elements), BuilderFactory.LONG);
  }

  public final CommandObject pfmerge(byte[] destkey, byte[]... sourcekeys) {
    return new CommandObject<>(commandArguments(PFMERGE).key(destkey).keys((Object[]) sourcekeys), BuilderFactory.STRING);
  }

  public final CommandObject pfcount(String key) {
    return new CommandObject<>(commandArguments(PFCOUNT).key(key), BuilderFactory.LONG);
  }

  public final CommandObject pfcount(String... keys) {
    return new CommandObject<>(commandArguments(PFCOUNT).keys((Object[]) keys), BuilderFactory.LONG);
  }

  public final CommandObject pfcount(byte[] key) {
    return new CommandObject<>(commandArguments(PFCOUNT).key(key), BuilderFactory.LONG);
  }

  public final CommandObject pfcount(byte[]... keys) {
    return new CommandObject<>(commandArguments(PFCOUNT).keys((Object[]) keys), BuilderFactory.LONG);
  }
  // Hyper Log Log commands

  // Stream commands
  public final CommandObject xadd(String key, StreamEntryID id, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(XADD).key(key).add(id == null ? StreamEntryID.NEW_ENTRY : id), hash),
        BuilderFactory.STREAM_ENTRY_ID);
  }

  public final CommandObject xadd(String key, XAddParams params, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(XADD).key(key).addParams(params), hash),
        BuilderFactory.STREAM_ENTRY_ID);
  }

  public final CommandObject xlen(String key) {
    return new CommandObject<>(commandArguments(XLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject xadd(byte[] key, XAddParams params, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(XADD).key(key).addParams(params), hash),
        BuilderFactory.BINARY);
  }

  public final CommandObject xlen(byte[] key) {
    return new CommandObject<>(commandArguments(XLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject> xrange(String key, StreamEntryID start, StreamEntryID end) {
    return new CommandObject<>(commandArguments(XRANGE).key(key).add(start == null ? "-" : start).add(end == null ? "+" : end),
        BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrange(String key, StreamEntryID start, StreamEntryID end, int count) {
    return new CommandObject<>(commandArguments(XRANGE).key(key).add(start == null ? "-" : start).add(end == null ? "+" : end)
        .add(COUNT).add(count), BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrevrange(String key, StreamEntryID end, StreamEntryID start) {
    return new CommandObject<>(commandArguments(XREVRANGE).key(key).add(end == null ? "+" : end).add(start == null ? "-" : start),
        BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrevrange(String key, StreamEntryID end, StreamEntryID start, int count) {
    return new CommandObject<>(commandArguments(XREVRANGE).key(key).add(end == null ? "+" : end).add(start == null ? "-" : start)
        .add(COUNT).add(count), BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrange(String key, String start, String end) {
    return new CommandObject<>(commandArguments(XRANGE).key(key).add(start).add(end), BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrange(String key, String start, String end, int count) {
    return new CommandObject<>(commandArguments(XRANGE).key(key).add(start).add(end).add(COUNT).add(count), BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrevrange(String key, String end, String start) {
    return new CommandObject<>(commandArguments(XREVRANGE).key(key).add(end).add(start), BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrevrange(String key, String end, String start, int count) {
    return new CommandObject<>(commandArguments(XREVRANGE).key(key).add(end).add(start).add(COUNT).add(count), BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xrange(byte[] key, byte[] start, byte[] end) {
    return new CommandObject<>(commandArguments(XRANGE).key(key).add(start == null ? "-" : start).add(end == null ? "+" : end),
        BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> xrange(byte[] key, byte[] start, byte[] end, int count) {
    return new CommandObject<>(commandArguments(XRANGE).key(key).add(start == null ? "-" : start).add(end == null ? "+" : end)
        .add(COUNT).add(count), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> xrevrange(byte[] key, byte[] end, byte[] start) {
    return new CommandObject<>(commandArguments(XREVRANGE).key(key).add(end == null ? "+" : end).add(start == null ? "-" : start),
        BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> xrevrange(byte[] key, byte[] end, byte[] start, int count) {
    return new CommandObject<>(commandArguments(XREVRANGE).key(key).add(end == null ? "+" : end).add(start == null ? "-" : start)
        .add(COUNT).add(count), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject xack(String key, String group, StreamEntryID... ids) {
    return new CommandObject<>(commandArguments(XACK).key(key).add(group).addObjects((Object[]) ids), BuilderFactory.LONG);
  }

  public final CommandObject xack(byte[] key, byte[] group, byte[]... ids) {
    return new CommandObject<>(commandArguments(XACK).key(key).add(group).addObjects((Object[]) ids), BuilderFactory.LONG);
  }

  public final CommandObject xgroupCreate(String key, String groupName, StreamEntryID id, boolean makeStream) {
    CommandArguments args = commandArguments(XGROUP).add(CREATE).key(key)
        .add(groupName).add(id == null ? "0-0" : id);
    if (makeStream) args.add(MKSTREAM);
    return new CommandObject<>(args, BuilderFactory.STRING);
  }

  public final CommandObject xgroupSetID(String key, String groupName, StreamEntryID id) {
    return new CommandObject<>(commandArguments(XGROUP).add(SETID)
        .key(key).add(groupName).add(id), BuilderFactory.STRING);
  }

  public final CommandObject xgroupDestroy(String key, String groupName) {
    return new CommandObject<>(commandArguments(XGROUP).add(DESTROY)
        .key(key).add(groupName), BuilderFactory.LONG);
  }

  public final CommandObject xgroupCreateConsumer(String key, String groupName, String consumerName) {
    return new CommandObject<>(commandArguments(XGROUP).add(CREATECONSUMER)
        .key(key).add(groupName).add(consumerName), BuilderFactory.BOOLEAN);
  }

  public final CommandObject xgroupDelConsumer(String key, String groupName, String consumerName) {
    return new CommandObject<>(commandArguments(XGROUP).add(DELCONSUMER)
        .key(key).add(groupName).add(consumerName), BuilderFactory.LONG);
  }

  public final CommandObject xgroupCreate(byte[] key, byte[] groupName, byte[] id, boolean makeStream) {
    CommandArguments args = commandArguments(XGROUP).add(CREATE).key(key)
        .add(groupName).add(id);
    if (makeStream) args.add(MKSTREAM);
    return new CommandObject<>(args, BuilderFactory.STRING);
  }

  public final CommandObject xgroupSetID(byte[] key, byte[] groupName, byte[] id) {
    return new CommandObject<>(commandArguments(XGROUP).add(SETID)
        .key(key).add(groupName).add(id), BuilderFactory.STRING);
  }

  public final CommandObject xgroupDestroy(byte[] key, byte[] groupName) {
    return new CommandObject<>(commandArguments(XGROUP).add(DESTROY)
        .key(key).add(groupName), BuilderFactory.LONG);
  }

  public final CommandObject xgroupCreateConsumer(byte[] key, byte[] groupName, byte[] consumerName) {
    return new CommandObject<>(commandArguments(XGROUP).add(CREATECONSUMER)
        .key(key).add(groupName).add(consumerName), BuilderFactory.BOOLEAN);
  }

  public final CommandObject xgroupDelConsumer(byte[] key, byte[] groupName, byte[] consumerName) {
    return new CommandObject<>(commandArguments(XGROUP).add(DELCONSUMER)
        .key(key).add(groupName).add(consumerName), BuilderFactory.LONG);
  }
  public final CommandObject xdel(String key, StreamEntryID... ids) {
    return new CommandObject<>(commandArguments(XDEL).key(key).addObjects((Object[]) ids), BuilderFactory.LONG);
  }

  public final CommandObject xtrim(String key, long maxLen, boolean approximate) {
    CommandArguments args = commandArguments(XTRIM).key(key).add(MAXLEN);
    if (approximate) args.add(Protocol.BYTES_TILDE);
    args.add(maxLen);
    return new CommandObject<>(args, BuilderFactory.LONG);
  }

  public final CommandObject xtrim(String key, XTrimParams params) {
    return new CommandObject<>(commandArguments(XTRIM).key(key).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject xdel(byte[] key, byte[]... ids) {
    return new CommandObject<>(commandArguments(XDEL).key(key).addObjects((Object[]) ids), BuilderFactory.LONG);
  }

  public final CommandObject xtrim(byte[] key, long maxLen, boolean approximateLength) {
    CommandArguments args = commandArguments(XTRIM).key(key).add(MAXLEN);
    if (approximateLength) args.add(Protocol.BYTES_TILDE);
    args.add(maxLen);
    return new CommandObject<>(args, BuilderFactory.LONG);
  }

  public final CommandObject xtrim(byte[] key, XTrimParams params) {
    return new CommandObject<>(commandArguments(XTRIM).key(key).addParams(params), BuilderFactory.LONG);
  }

  public final CommandObject xpending(String key, String groupName) {
    return new CommandObject<>(commandArguments(XPENDING).key(key).add(groupName),
        BuilderFactory.STREAM_PENDING_SUMMARY);
  }

  public final CommandObject> xpending(String key, String groupName, XPendingParams params) {
    return new CommandObject<>(commandArguments(XPENDING).key(key).add(groupName)
        .addParams(params), BuilderFactory.STREAM_PENDING_ENTRY_LIST);
  }

  public final CommandObject xpending(byte[] key, byte[] groupName) {
    return new CommandObject<>(commandArguments(XPENDING).key(key).add(groupName),
        BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject> xpending(byte[] key, byte[] groupName, XPendingParams params) {
    return new CommandObject<>(commandArguments(XPENDING).key(key).add(groupName)
        .addParams(params), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> xclaim(String key, String group,
      String consumerName, long minIdleTime, XClaimParams params, StreamEntryID... ids) {
    return new CommandObject<>(commandArguments(XCLAIM).key(key).add(group)
        .add(consumerName).add(minIdleTime).addObjects((Object[]) ids).addParams(params),
        BuilderFactory.STREAM_ENTRY_LIST);
  }

  public final CommandObject> xclaimJustId(String key, String group,
      String consumerName, long minIdleTime, XClaimParams params, StreamEntryID... ids) {
    return new CommandObject<>(commandArguments(XCLAIM).key(key).add(group)
        .add(consumerName).add(minIdleTime).addObjects((Object[]) ids).addParams(params)
        .add(JUSTID), BuilderFactory.STREAM_ENTRY_ID_LIST);
  }

  public final CommandObject>> xautoclaim(String key,
      String group, String consumerName, long minIdleTime, StreamEntryID start,
      XAutoClaimParams params) {
    return new CommandObject<>(commandArguments(XAUTOCLAIM).key(key).add(group)
        .add(consumerName).add(minIdleTime).add(start).addParams(params),
        BuilderFactory.STREAM_AUTO_CLAIM_RESPONSE);
  }

  public final CommandObject>> xautoclaimJustId(
      String key, String group, String consumerName, long minIdleTime, StreamEntryID start,
      XAutoClaimParams params) {
    return new CommandObject<>(commandArguments(XAUTOCLAIM).key(key).add(group)
        .add(consumerName).add(minIdleTime).add(start).addParams(params)
        .add(JUSTID), BuilderFactory.STREAM_AUTO_CLAIM_JUSTID_RESPONSE);
  }

  public final CommandObject> xclaim(byte[] key, byte[] group,
      byte[] consumerName, long minIdleTime, XClaimParams params, byte[]... ids) {
    return new CommandObject<>(commandArguments(XCLAIM).key(key).add(group)
        .add(consumerName).add(minIdleTime).addObjects((Object[]) ids).addParams(params),
        BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> xclaimJustId(byte[] key, byte[] group,
      byte[] consumerName, long minIdleTime, XClaimParams params, byte[]... ids) {
    return new CommandObject<>(commandArguments(XCLAIM).key(key).add(group)
        .add(consumerName).add(minIdleTime).addObjects((Object[]) ids).addParams(params)
        .add(JUSTID), BuilderFactory.BINARY_LIST);
  }

  public final CommandObject> xautoclaim(byte[] key, byte[] groupName,
      byte[] consumerName, long minIdleTime, byte[] start, XAutoClaimParams params) {
    return new CommandObject<>(commandArguments(XAUTOCLAIM).key(key).add(groupName)
        .add(consumerName).add(minIdleTime).add(start).addParams(params),
        BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> xautoclaimJustId(byte[] key, byte[] groupName,
      byte[] consumerName, long minIdleTime, byte[] start, XAutoClaimParams params) {
    return new CommandObject<>(commandArguments(XAUTOCLAIM).key(key).add(groupName)
        .add(consumerName).add(minIdleTime).add(start).addParams(params)
        .add(JUSTID), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject xinfoStream(String key) {
    return new CommandObject<>(commandArguments(XINFO).add(STREAM).key(key), BuilderFactory.STREAM_INFO);
  }

  public final CommandObject xinfoStream(byte[] key) {
    return new CommandObject<>(commandArguments(XINFO).add(STREAM).key(key), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject xinfoStreamFull(String key) {
    return new CommandObject<>(commandArguments(XINFO).add(STREAM).key(key).add(FULL), BuilderFactory.STREAM_FULL_INFO);
  }

  public final CommandObject xinfoStreamFull(String key, int count) {
    return new CommandObject<>(commandArguments(XINFO).add(STREAM).key(key).add(FULL).add(COUNT).add(count), BuilderFactory.STREAM_FULL_INFO);
  }

  public final CommandObject xinfoStreamFull(byte[] key, int count) {
    return new CommandObject<>(commandArguments(XINFO).add(STREAM).key(key).add(FULL).add(COUNT).add(count), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject xinfoStreamFull(byte[] key) {
    return new CommandObject<>(commandArguments(XINFO).add(STREAM).key(key).add(FULL), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject> xinfoGroups(String key) {
    return new CommandObject<>(commandArguments(XINFO).add(GROUPS).key(key), BuilderFactory.STREAM_GROUP_INFO_LIST);
  }

  public final CommandObject> xinfoGroups(byte[] key) {
    return new CommandObject<>(commandArguments(XINFO).add(GROUPS).key(key), BuilderFactory.RAW_OBJECT_LIST);
  }

  /**
   * @deprecated Use {@link #xinfoConsumers2(java.lang.String, java.lang.String)}.
   */
  @Deprecated
  public final CommandObject> xinfoConsumers(String key, String group) {
    return new CommandObject<>(commandArguments(XINFO).add(CONSUMERS).key(key).add(group), BuilderFactory.STREAM_CONSUMERS_INFO_LIST);
  }

  public final CommandObject> xinfoConsumers2(String key, String group) {
    return new CommandObject<>(commandArguments(XINFO).add(CONSUMERS).key(key).add(group), BuilderFactory.STREAM_CONSUMER_INFO_LIST);
  }

  public final CommandObject> xinfoConsumers(byte[] key, byte[] group) {
    return new CommandObject<>(commandArguments(XINFO).add(CONSUMERS).key(key).add(group), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject>>> xread(
      XReadParams xReadParams, Map streams) {
    CommandArguments args = commandArguments(XREAD).addParams(xReadParams).add(STREAMS);
    Set> entrySet = streams.entrySet();
    entrySet.forEach(entry -> args.key(entry.getKey()));
    entrySet.forEach(entry -> args.add(entry.getValue()));
    return new CommandObject<>(args, BuilderFactory.STREAM_READ_RESPONSE);
  }

  public final CommandObject>>> xreadGroup(
      String groupName, String consumer, XReadGroupParams xReadGroupParams,
      Map streams) {
    CommandArguments args = commandArguments(XREADGROUP)
        .add(GROUP).add(groupName).add(consumer)
        .addParams(xReadGroupParams).add(STREAMS);
    Set> entrySet = streams.entrySet();
    entrySet.forEach(entry -> args.key(entry.getKey()));
    entrySet.forEach(entry -> args.add(entry.getValue()));
    return new CommandObject<>(args, BuilderFactory.STREAM_READ_RESPONSE);
  }

  public final CommandObject> xread(XReadParams xReadParams, Map.Entry... streams) {
    CommandArguments args = commandArguments(XREAD).addParams(xReadParams).add(STREAMS);
    for (Map.Entry entry : streams) {
      args.key(entry.getKey());
    }
    for (Map.Entry entry : streams) {
      args.add(entry.getValue());
    }
    return new CommandObject<>(args, BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> xreadGroup(byte[] groupName, byte[] consumer,
      XReadGroupParams xReadGroupParams, Map.Entry... streams) {
    CommandArguments args = commandArguments(XREADGROUP)
        .add(GROUP).add(groupName).add(consumer)
        .addParams(xReadGroupParams).add(STREAMS);
    for (Map.Entry entry : streams) {
      args.key(entry.getKey());
    }
    for (Map.Entry entry : streams) {
      args.add(entry.getValue());
    }
    return new CommandObject<>(args, BuilderFactory.RAW_OBJECT_LIST);
  }
  // Stream commands

  // Scripting commands
  public final CommandObject eval(String script) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(0), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject eval(String script, String sampleKey) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(0).processKey(sampleKey), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject eval(String script, int keyCount, String... params) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(keyCount)
        .addObjects((Object[]) params).processKeys(Arrays.copyOf(params, keyCount)),
        BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject eval(String script, List keys, List args) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject evalReadonly(String script, List keys, List args) {
    return new CommandObject<>(commandArguments(EVAL_RO).add(script).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject eval(byte[] script) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(0), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject eval(byte[] script, byte[] sampleKey) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(0).processKey(sampleKey), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject eval(byte[] script, int keyCount, byte[]... params) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(keyCount)
        .addObjects((Object[]) params).processKeys(Arrays.copyOf(params, keyCount)),
        BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject eval(byte[] script, List keys, List args) {
    return new CommandObject<>(commandArguments(EVAL).add(script).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject evalReadonly(byte[] script, List keys, List args) {
    return new CommandObject<>(commandArguments(EVAL_RO).add(script).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject evalsha(String sha1) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(0), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject evalsha(String sha1, String sampleKey) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(0).processKey(sampleKey), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject evalsha(String sha1, int keyCount, String... params) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(keyCount)
        .addObjects((Object[]) params).processKeys(Arrays.copyOf(params, keyCount)),
        BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject evalsha(String sha1, List keys, List args) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject evalshaReadonly(String sha1, List keys, List args) {
    return new CommandObject<>(commandArguments(EVALSHA_RO).add(sha1).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject evalsha(byte[] sha1) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(0), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject evalsha(byte[] sha1, byte[] sampleKey) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(0).processKey(sampleKey), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject evalsha(byte[] sha1, int keyCount, byte[]... params) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(keyCount)
        .addObjects((Object[]) params).processKeys(Arrays.copyOf(params, keyCount)),
        BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject evalsha(byte[] sha1, List keys, List args) {
    return new CommandObject<>(commandArguments(EVALSHA).add(sha1).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject evalshaReadonly(byte[] sha1, List keys, List args) {
    return new CommandObject<>(commandArguments(EVALSHA_RO).add(sha1).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject> scriptExists(List sha1s) {
    return new CommandObject<>(commandArguments(SCRIPT).add(Keyword.EXISTS).addObjects(sha1s), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject> scriptExists(String sampleKey, String... sha1s) {
    return new CommandObject<>(commandArguments(SCRIPT).add(Keyword.EXISTS).addObjects((Object[]) sha1s)
        .processKey(sampleKey), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject scriptLoad(String script) {
    return new CommandObject<>(commandArguments(SCRIPT).add(LOAD).add(script), BuilderFactory.STRING);
  }

  public final CommandObject scriptLoad(String script, String sampleKey) {
    return new CommandObject<>(commandArguments(SCRIPT).add(LOAD).add(script).processKey(sampleKey), BuilderFactory.STRING);
  }

  private final CommandObject SCRIPT_FLUSH_COMMAND_OBJECT = new CommandObject<>(commandArguments(SCRIPT).add(FLUSH), BuilderFactory.STRING);

  public final CommandObject scriptFlush() {
    return SCRIPT_FLUSH_COMMAND_OBJECT;
  }

  public final CommandObject scriptFlush(String sampleKey) {
    return new CommandObject<>(commandArguments(SCRIPT).add(FLUSH).processKey(sampleKey), BuilderFactory.STRING);
  }

  public final CommandObject scriptFlush(String sampleKey, FlushMode flushMode) {
    return new CommandObject<>(commandArguments(SCRIPT).add(FLUSH).add(flushMode).processKey(sampleKey), BuilderFactory.STRING);
  }

  private final CommandObject SCRIPT_KILL_COMMAND_OBJECT = new CommandObject<>(commandArguments(SCRIPT).add(KILL), BuilderFactory.STRING);

  public final CommandObject scriptKill() {
    return SCRIPT_KILL_COMMAND_OBJECT;
  }

  public final CommandObject scriptKill(String sampleKey) {
    return new CommandObject<>(commandArguments(SCRIPT).add(KILL).processKey(sampleKey), BuilderFactory.STRING);
  }

  public final CommandObject> scriptExists(byte[] sampleKey, byte[]... sha1s) {
    return new CommandObject<>(commandArguments(SCRIPT).add(Keyword.EXISTS).addObjects((Object[]) sha1s)
        .processKey(sampleKey), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject scriptLoad(byte[] script, byte[] sampleKey) {
    return new CommandObject<>(commandArguments(SCRIPT).add(LOAD).add(script).processKey(sampleKey), BuilderFactory.BINARY);
  }

  public final CommandObject scriptFlush(byte[] sampleKey) {
    return new CommandObject<>(commandArguments(SCRIPT).add(FLUSH).processKey(sampleKey), BuilderFactory.STRING);
  }

  public final CommandObject scriptFlush(byte[] sampleKey, FlushMode flushMode) {
    return new CommandObject<>(commandArguments(SCRIPT).add(FLUSH).add(flushMode).processKey(sampleKey), BuilderFactory.STRING);
  }

  public final CommandObject scriptKill(byte[] sampleKey) {
    return new CommandObject<>(commandArguments(SCRIPT).add(KILL).processKey(sampleKey), BuilderFactory.STRING);
  }

  private final CommandObject SLOWLOG_RESET_COMMAND_OBJECT
      = new CommandObject<>(commandArguments(SLOWLOG).add(Keyword.RESET), BuilderFactory.STRING);

  public final CommandObject slowlogReset() {
    return SLOWLOG_RESET_COMMAND_OBJECT;
  }

  public final CommandObject fcall(String name, List keys, List args) {
    return new CommandObject<>(commandArguments(FCALL).add(name).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject fcallReadonly(String name, List keys, List args) {
    return new CommandObject<>(commandArguments(FCALL_RO).add(name).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject functionDelete(String libraryName) {
    return new CommandObject<>(commandArguments(FUNCTION).add(DELETE).add(libraryName), BuilderFactory.STRING);
  }

  public final CommandObject> functionList() {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST), LibraryInfo.LIBRARY_INFO_LIST);
  }

  public final CommandObject> functionList(String libraryNamePattern) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST).add(LIBRARYNAME)
        .add(libraryNamePattern), LibraryInfo.LIBRARY_INFO_LIST);
  }

  public final CommandObject> functionListWithCode() {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST).add(WITHCODE), LibraryInfo.LIBRARY_INFO_LIST);
  }

  public final CommandObject> functionListWithCode(String libraryNamePattern) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST).add(LIBRARYNAME)
        .add(libraryNamePattern).add(WITHCODE), LibraryInfo.LIBRARY_INFO_LIST);
  }

  public final CommandObject functionLoad(String functionCode) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LOAD).add(functionCode), BuilderFactory.STRING);
  }

  public final CommandObject functionLoadReplace(String functionCode) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LOAD).add(REPLACE).add(functionCode), BuilderFactory.STRING);
  }

  public final CommandObject functionStats() {
    return new CommandObject<>(commandArguments(FUNCTION).add(STATS), FunctionStats.FUNCTION_STATS_BUILDER);
  }

  public final CommandObject functionStatsBinary() {
    return new CommandObject<>(commandArguments(FUNCTION).add(STATS), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject functionFlush() {
    return new CommandObject<>(commandArguments(FUNCTION).add(FLUSH), BuilderFactory.STRING);
  }

  public final CommandObject functionFlush(FlushMode mode) {
    return new CommandObject<>(commandArguments(FUNCTION).add(FLUSH).add(mode), BuilderFactory.STRING);
  }

  public final CommandObject functionKill() {
    return new CommandObject<>(commandArguments(FUNCTION).add(KILL), BuilderFactory.STRING);
  }

  public final CommandObject fcall(byte[] name, List keys, List args) {
    return new CommandObject<>(commandArguments(FCALL).add(name).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject fcallReadonly(byte[] name, List keys, List args) {
    return new CommandObject<>(commandArguments(FCALL_RO).add(name).add(keys.size())
        .keys(keys).addObjects(args), BuilderFactory.RAW_OBJECT);
  }

  public final CommandObject functionDelete(byte[] libraryName) {
    return new CommandObject<>(commandArguments(FUNCTION).add(DELETE).add(libraryName), BuilderFactory.STRING);
  }

  public final CommandObject functionDump() {
    return new CommandObject<>(commandArguments(FUNCTION).add(Keyword.DUMP), BuilderFactory.BINARY);
  }

  public final CommandObject> functionListBinary() {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> functionList(byte[] libraryNamePattern) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST).add(LIBRARYNAME)
        .add(libraryNamePattern), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> functionListWithCodeBinary() {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST).add(WITHCODE), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject> functionListWithCode(byte[] libraryNamePattern) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LIST).add(LIBRARYNAME).
        add(libraryNamePattern).add(WITHCODE), BuilderFactory.RAW_OBJECT_LIST);
  }

  public final CommandObject functionLoad(byte[] functionCode) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LOAD).add(functionCode), BuilderFactory.STRING);
  }

  public final CommandObject functionLoadReplace(byte[] functionCode) {
    return new CommandObject<>(commandArguments(FUNCTION).add(LOAD).add(REPLACE).add(functionCode), BuilderFactory.STRING);
  }

  public final CommandObject functionRestore(byte[] serializedValue) {
    return new CommandObject<>(commandArguments(FUNCTION).add(RESTORE).add(serializedValue),
        BuilderFactory.STRING);
  }

  public final CommandObject functionRestore(byte[] serializedValue, FunctionRestorePolicy policy) {
    return new CommandObject<>(commandArguments(FUNCTION).add(RESTORE).add(serializedValue)
        .add(policy.getRaw()), BuilderFactory.STRING);
  }
  // Scripting commands

  // Miscellaneous commands
  public final CommandObject copy(String srcKey, String dstKey, int dstDB, boolean replace) {
    CommandArguments args = commandArguments(Command.COPY).key(srcKey).key(dstKey).add(DB).add(dstDB);
    if (replace) args.add(REPLACE);
    return new CommandObject<>(args, BuilderFactory.BOOLEAN);
  }

  public final CommandObject copy(byte[] srcKey, byte[] dstKey, int dstDB, boolean replace) {
    CommandArguments args = commandArguments(Command.COPY).key(srcKey).key(dstKey).add(DB).add(dstDB);
    if (replace) args.add(REPLACE);
    return new CommandObject<>(args, BuilderFactory.BOOLEAN);
  }

  public final CommandObject migrate(String host, int port, String key, int timeout) {
    return migrate(host, port, key, 0, timeout);
  }

  public final CommandObject migrate(String host, int port, String key, int destinationDB, int timeout) {
    return new CommandObject<>(commandArguments(MIGRATE).add(host).add(port).key(key)
        .add(destinationDB).add(timeout), BuilderFactory.STRING);
  }

  public final CommandObject migrate(String host, int port, int timeout, MigrateParams params, String... keys) {
    return migrate(host, port, 0, timeout, params, keys);
  }

  public final CommandObject migrate(String host, int port, int destinationDB, int timeout,
      MigrateParams params, String... keys) {
    return new CommandObject<>(commandArguments(MIGRATE).add(host).add(port).add(new byte[0])
        .add(destinationDB).add(timeout).addParams(params).add(Keyword.KEYS).keys((Object[]) keys),
        BuilderFactory.STRING);
  }

  public final CommandObject migrate(String host, int port, byte[] key, int timeout) {
    return migrate(host, port, key, 0, timeout);
  }

  public final CommandObject migrate(String host, int port, byte[] key, int destinationDB, int timeout) {
    return new CommandObject<>(commandArguments(MIGRATE).add(host).add(port).key(key)
        .add(destinationDB).add(timeout), BuilderFactory.STRING);
  }

  public final CommandObject migrate(String host, int port, int timeout, MigrateParams params, byte[]... keys) {
    return migrate(host, port, 0, timeout, params, keys);
  }

  public final CommandObject migrate(String host, int port, int destinationDB, int timeout,
      MigrateParams params, byte[]... keys) {
    return new CommandObject<>(commandArguments(MIGRATE).add(host).add(port).add(new byte[0])
        .add(destinationDB).add(timeout).addParams(params).add(Keyword.KEYS).keys((Object[]) keys),
        BuilderFactory.STRING);
  }

  public final CommandObject memoryUsage(String key) {
    return new CommandObject<>(commandArguments(MEMORY).add(USAGE).key(key), BuilderFactory.LONG);
  }

  public final CommandObject memoryUsage(String key, int samples) {
    return new CommandObject<>(commandArguments(MEMORY).add(USAGE).key(key).add(SAMPLES).add(samples), BuilderFactory.LONG);
  }

  public final CommandObject memoryUsage(byte[] key) {
    return new CommandObject<>(commandArguments(MEMORY).add(USAGE).key(key), BuilderFactory.LONG);
  }

  public final CommandObject memoryUsage(byte[] key, int samples) {
    return new CommandObject<>(commandArguments(MEMORY).add(USAGE).key(key).add(SAMPLES).add(samples), BuilderFactory.LONG);
  }

  public final CommandObject objectRefcount(String key) {
    return new CommandObject<>(commandArguments(OBJECT).add(REFCOUNT).key(key), BuilderFactory.LONG);
  }

  public final CommandObject objectEncoding(String key) {
    return new CommandObject<>(commandArguments(OBJECT).add(ENCODING).key(key), BuilderFactory.STRING);
  }

  public final CommandObject objectIdletime(String key) {
    return new CommandObject<>(commandArguments(OBJECT).add(IDLETIME).key(key), BuilderFactory.LONG);
  }

  public final CommandObject objectFreq(String key) {
    return new CommandObject<>(commandArguments(OBJECT).add(FREQ).key(key), BuilderFactory.LONG);
  }

  public final CommandObject objectRefcount(byte[] key) {
    return new CommandObject<>(commandArguments(OBJECT).add(REFCOUNT).key(key), BuilderFactory.LONG);
  }

  public final CommandObject objectEncoding(byte[] key) {
    return new CommandObject<>(commandArguments(OBJECT).add(ENCODING).key(key), BuilderFactory.BINARY);
  }

  public final CommandObject objectIdletime(byte[] key) {
    return new CommandObject<>(commandArguments(OBJECT).add(IDLETIME).key(key), BuilderFactory.LONG);
  }

  public final CommandObject objectFreq(byte[] key) {
    return new CommandObject<>(commandArguments(OBJECT).add(FREQ).key(key), BuilderFactory.LONG);
  }

  public CommandObject waitReplicas(int replicas, long timeout) {
    return new CommandObject<>(commandArguments(WAIT).add(replicas).add(timeout), BuilderFactory.LONG);
  }

  public final CommandObject waitReplicas(String sampleKey, int replicas, long timeout) {
    return new CommandObject<>(commandArguments(WAIT).add(replicas).add(timeout).processKey(sampleKey), BuilderFactory.LONG);
  }

  public final CommandObject waitReplicas(byte[] sampleKey, int replicas, long timeout) {
    return new CommandObject<>(commandArguments(WAIT).add(replicas).add(timeout).processKey(sampleKey), BuilderFactory.LONG);
  }

  public CommandObject> waitAOF(long numLocal, long numReplicas, long timeout) {
    return new CommandObject<>(commandArguments(WAITAOF).add(numLocal).add(numReplicas).add(timeout), BuilderFactory.LONG_LONG_PAIR);
  }

  public CommandObject> waitAOF(byte[] sampleKey, long numLocal, long numReplicas, long timeout) {
    return new CommandObject<>(commandArguments(WAITAOF).add(numLocal).add(numReplicas).add(timeout).processKey(sampleKey), BuilderFactory.LONG_LONG_PAIR);
  }

  public CommandObject> waitAOF(String sampleKey, long numLocal, long numReplicas, long timeout) {
    return new CommandObject<>(commandArguments(WAITAOF).add(numLocal).add(numReplicas).add(timeout).processKey(sampleKey), BuilderFactory.LONG_LONG_PAIR);
  }

  public final CommandObject publish(String channel, String message) {
    return new CommandObject<>(commandArguments(PUBLISH).add(channel).add(message), BuilderFactory.LONG);
  }

  public final CommandObject publish(byte[] channel, byte[] message) {
    return new CommandObject<>(commandArguments(PUBLISH).add(channel).add(message), BuilderFactory.LONG);
  }

  public final CommandObject spublish(String channel, String message) {
    return new CommandObject<>(commandArguments(SPUBLISH).key(channel).add(message), BuilderFactory.LONG);
  }

  public final CommandObject spublish(byte[] channel, byte[] message) {
    return new CommandObject<>(commandArguments(SPUBLISH).key(channel).add(message), BuilderFactory.LONG);
  }
  // Miscellaneous commands

  // RediSearch commands
  public final CommandObject hsetObject(String key, String field, Object value) {
    return new CommandObject<>(commandArguments(HSET).key(key).add(field).add(value), BuilderFactory.LONG);
  }

  public final CommandObject hsetObject(String key, Map hash) {
    return new CommandObject<>(addFlatMapArgs(commandArguments(HSET).key(key), hash), BuilderFactory.LONG);
  }

  private boolean isRoundRobinSearchCommand() {
    if (broadcastAndRoundRobinConfig == null) {
      return true;
    } else if (broadcastAndRoundRobinConfig.getRediSearchModeInCluster() == JedisBroadcastAndRoundRobinConfig.RediSearchMode.LIGHT) {
      return false;
    }
    return true;
  }

  private CommandArguments checkAndRoundRobinSearchCommand(SearchCommand sc, String idx) {
    CommandArguments ca = commandArguments(sc);
    if (isRoundRobinSearchCommand()) {
      ca.add(idx);
    } else {
      ca.key(idx);
    }
    return ca;
  }

  private CommandArguments checkAndRoundRobinSearchCommand(SearchCommand sc, String idx1, String idx2) {
    CommandArguments ca = commandArguments(sc);
    if (isRoundRobinSearchCommand()) {
      ca.add(idx1).add(idx2);
    } else {
      ca.key(idx1).key(idx2);
    }
    return ca;
  }

  private CommandArguments checkAndRoundRobinSearchCommand(CommandArguments commandArguments, byte[] indexName) {
    return isRoundRobinSearchCommand() ? commandArguments.add(indexName) : commandArguments.key(indexName);
  }

  private  CommandObject directSearchCommand(CommandObject object, String indexName) {
    object.getArguments().processKey(indexName);
    return object;
  }

  public final CommandObject ftCreate(String indexName, IndexOptions indexOptions, Schema schema) {
    CommandArguments args = checkAndRoundRobinSearchCommand(SearchCommand.CREATE, indexName)
        .addParams(indexOptions).add(SearchKeyword.SCHEMA);
    schema.fields.forEach(field -> args.addParams(field));
    return new CommandObject<>(args, BuilderFactory.STRING);
  }

  public final CommandObject ftCreate(String indexName, FTCreateParams createParams,
      Iterable schemaFields) {
    CommandArguments args = checkAndRoundRobinSearchCommand(SearchCommand.CREATE, indexName)
        .addParams(createParams).add(SearchKeyword.SCHEMA);
    schemaFields.forEach(field -> args.addParams(field));
    return new CommandObject<>(args, BuilderFactory.STRING);
  }

  public final CommandObject ftAlter(String indexName, Schema schema) {
    CommandArguments args = checkAndRoundRobinSearchCommand(SearchCommand.ALTER, indexName)
        .add(SearchKeyword.SCHEMA).add(SearchKeyword.ADD);
    schema.fields.forEach(field -> args.addParams(field));
    return new CommandObject<>(args, BuilderFactory.STRING);
  }

  public final CommandObject ftAlter(String indexName, Iterable schemaFields) {
    CommandArguments args = checkAndRoundRobinSearchCommand(SearchCommand.ALTER, indexName)
        .add(SearchKeyword.SCHEMA).add(SearchKeyword.ADD);
    schemaFields.forEach(field -> args.addParams(field));
    return new CommandObject<>(args, BuilderFactory.STRING);
  }

  public final CommandObject ftAliasAdd(String aliasName, String indexName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.ALIASADD, aliasName, indexName), BuilderFactory.STRING);
  }

  public final CommandObject ftAliasUpdate(String aliasName, String indexName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.ALIASUPDATE, aliasName, indexName), BuilderFactory.STRING);
  }

   public final CommandObject ftAliasDel(String aliasName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.ALIASDEL, aliasName), BuilderFactory.STRING);
  }

  public final CommandObject ftDropIndex(String indexName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.DROPINDEX, indexName), BuilderFactory.STRING);
  }

  public final CommandObject ftDropIndexDD(String indexName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.DROPINDEX, indexName).add(SearchKeyword.DD),
        BuilderFactory.STRING);
  }

  public final CommandObject ftSearch(String indexName, String query) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName).add(query),
        getSearchResultBuilder(() -> new SearchResultBuilder(true, false, true)));
  }

  public final CommandObject ftSearch(String indexName, String query, FTSearchParams params) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName)
        .add(query).addParams(params.dialectOptional(searchDialect.get())),
        getSearchResultBuilder(() -> new SearchResultBuilder(!params.getNoContent(), params.getWithScores(), true)));
  }

  public final CommandObject ftSearch(String indexName, Query query) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SEARCH, indexName)
        .addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(() -> 
        new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true)));
  }

  @Deprecated
  public final CommandObject ftSearch(byte[] indexName, Query query) {
    if (protocol == RedisProtocol.RESP3) {
      throw new UnsupportedOperationException("binary ft.search is not implemented with resp3.");
    }
    return new CommandObject<>(checkAndRoundRobinSearchCommand(commandArguments(SearchCommand.SEARCH), indexName)
        .addParams(query.dialectOptional(searchDialect.get())), getSearchResultBuilder(() -> 
        new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), false)));
  }

  public final CommandObject ftExplain(String indexName, Query query) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.EXPLAIN, indexName)
        .addParams(query.dialectOptional(searchDialect.get())), BuilderFactory.STRING);
  }

  public final CommandObject> ftExplainCLI(String indexName, Query query) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.EXPLAINCLI, indexName)
        .addParams(query.dialectOptional(searchDialect.get())), BuilderFactory.STRING_LIST);
  }

  public final CommandObject ftAggregate(String indexName, AggregationBuilder aggr) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.AGGREGATE, indexName)
        .addParams(aggr.dialectOptional(searchDialect.get())), !aggr.isWithCursor() ? AggregationResult.SEARCH_AGGREGATION_RESULT
        : AggregationResult.SEARCH_AGGREGATION_RESULT_WITH_CURSOR);
  }

  public final CommandObject ftCursorRead(String indexName, long cursorId, int count) {
    return new CommandObject<>(commandArguments(SearchCommand.CURSOR).add(SearchKeyword.READ)
        .key(indexName).add(cursorId).add(SearchKeyword.COUNT).add(count),
        AggregationResult.SEARCH_AGGREGATION_RESULT_WITH_CURSOR);
  }

  public final CommandObject ftCursorDel(String indexName, long cursorId) {
    return new CommandObject<>(commandArguments(SearchCommand.CURSOR).add(SearchKeyword.DEL)
        .key(indexName).add(cursorId), BuilderFactory.STRING);
  }

  public final CommandObject>> ftProfileAggregate(
      String indexName, FTProfileParams profileParams, AggregationBuilder aggr) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.PROFILE, indexName)
        .add(SearchKeyword.AGGREGATE).addParams(profileParams).add(SearchKeyword.QUERY)
        .addParams(aggr.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>(
        !aggr.isWithCursor() ? AggregationResult.SEARCH_AGGREGATION_RESULT
        : AggregationResult.SEARCH_AGGREGATION_RESULT_WITH_CURSOR));
  }

  public final CommandObject>> ftProfileSearch(
      String indexName, FTProfileParams profileParams, Query query) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.PROFILE, indexName)
        .add(SearchKeyword.SEARCH).addParams(profileParams).add(SearchKeyword.QUERY)
        .addParams(query.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>(
            getSearchResultBuilder(() -> new SearchResultBuilder(!query.getNoContent(), query.getWithScores(), true))));
  }

  public final CommandObject>> ftProfileSearch(
      String indexName, FTProfileParams profileParams, String query, FTSearchParams searchParams) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.PROFILE, indexName)
        .add(SearchKeyword.SEARCH).addParams(profileParams).add(SearchKeyword.QUERY).add(query)
        .addParams(searchParams.dialectOptional(searchDialect.get())), new SearchProfileResponseBuilder<>(
            getSearchResultBuilder(() -> new SearchResultBuilder(!searchParams.getNoContent(), searchParams.getWithScores(), true))));
  }

  private Builder getSearchResultBuilder(Supplier> resp2) {
    if (protocol == RedisProtocol.RESP3) return SearchResult.SEARCH_RESULT_BUILDER;
    return resp2.get();
  }

  public final CommandObject ftSynUpdate(String indexName, String synonymGroupId, String... terms) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SYNUPDATE, indexName)
        .add(synonymGroupId).addObjects((Object[]) terms), BuilderFactory.STRING);
  }

  public final CommandObject>> ftSynDump(String indexName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SYNDUMP, indexName),
        SearchBuilderFactory.SEARCH_SYNONYM_GROUPS);
  }

  public final CommandObject ftDictAdd(String dictionary, String... terms) {
    return new CommandObject<>(commandArguments(SearchCommand.DICTADD).add(dictionary).addObjects((Object[]) terms),
        BuilderFactory.LONG);
  }

  public final CommandObject ftDictDel(String dictionary, String... terms) {
    return new CommandObject<>(commandArguments(SearchCommand.DICTDEL).add(dictionary).addObjects((Object[]) terms),
        BuilderFactory.LONG);
  }

  public final CommandObject> ftDictDump(String dictionary) {
    return new CommandObject<>(commandArguments(SearchCommand.DICTDUMP).add(dictionary), BuilderFactory.STRING_SET);
  }

  public final CommandObject ftDictAddBySampleKey(String indexName, String dictionary, String... terms) {
    return directSearchCommand(ftDictAdd(dictionary, terms), indexName);
  }

  public final CommandObject ftDictDelBySampleKey(String indexName, String dictionary, String... terms) {
    return directSearchCommand(ftDictDel(dictionary, terms), indexName);
  }

  public final CommandObject> ftDictDumpBySampleKey(String indexName, String dictionary) {
    return directSearchCommand(ftDictDump(dictionary), indexName);
  }

  public final CommandObject>> ftSpellCheck(String index, String query) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SPELLCHECK, index).add(query),
        SearchBuilderFactory.SEARCH_SPELLCHECK_RESPONSE);
  }

  public final CommandObject>> ftSpellCheck(String index, String query,
      FTSpellCheckParams spellCheckParams) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.SPELLCHECK, index).add(query)
        .addParams(spellCheckParams.dialectOptional(searchDialect.get())), SearchBuilderFactory.SEARCH_SPELLCHECK_RESPONSE);
  }

  public final CommandObject> ftInfo(String indexName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.INFO, indexName),
        protocol == RedisProtocol.RESP3 ? BuilderFactory.AGGRESSIVE_ENCODED_OBJECT_MAP : BuilderFactory.ENCODED_OBJECT_MAP);
  }

  public final CommandObject> ftTagVals(String indexName, String fieldName) {
    return new CommandObject<>(checkAndRoundRobinSearchCommand(SearchCommand.TAGVALS, indexName)
        .add(fieldName), BuilderFactory.STRING_SET);
  }

  public final CommandObject> ftConfigGet(String option) {
    return new CommandObject<>(commandArguments(SearchCommand.CONFIG).add(SearchKeyword.GET).add(option),
        protocol == RedisProtocol.RESP3 ? BuilderFactory.AGGRESSIVE_ENCODED_OBJECT_MAP : BuilderFactory.ENCODED_OBJECT_MAP_FROM_PAIRS);
  }

  public final CommandObject> ftConfigGet(String indexName, String option) {
    return directSearchCommand(ftConfigGet(option), indexName);
  }

  public final CommandObject ftConfigSet(String option, String value) {
    return new CommandObject<>(commandArguments(SearchCommand.CONFIG).add(SearchKeyword.SET).add(option).add(value), BuilderFactory.STRING);
  }

  public final CommandObject ftConfigSet(String indexName, String option, String value) {
    return directSearchCommand(ftConfigSet(option, value), indexName);
  }

  public final CommandObject ftSugAdd(String key, String string, double score) {
    return new CommandObject<>(commandArguments(SearchCommand.SUGADD).key(key).add(string).add(score), BuilderFactory.LONG);
  }

  public final CommandObject ftSugAddIncr(String key, String string, double score) {
    return new CommandObject<>(commandArguments(SearchCommand.SUGADD).key(key).add(string).add(score).add(SearchKeyword.INCR), BuilderFactory.LONG);
  }

  public final CommandObject> ftSugGet(String key, String prefix) {
    return new CommandObject<>(commandArguments(SearchCommand.SUGGET).key(key).add(prefix), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> ftSugGet(String key, String prefix, boolean fuzzy, int max) {
    CommandArguments args = commandArguments(SearchCommand.SUGGET).key(key).add(prefix);
    if (fuzzy) args.add(SearchKeyword.FUZZY);
    args.add(SearchKeyword.MAX).add(max);
    return new CommandObject<>(args, BuilderFactory.STRING_LIST);
  }

  public final CommandObject> ftSugGetWithScores(String key, String prefix) {
    return new CommandObject<>(commandArguments(SearchCommand.SUGGET).key(key).add(prefix)
        .add(SearchKeyword.WITHSCORES), BuilderFactory.TUPLE_LIST);
  }

  public final CommandObject> ftSugGetWithScores(String key, String prefix, boolean fuzzy, int max) {
    CommandArguments args = commandArguments(SearchCommand.SUGGET).key(key).add(prefix);
    if (fuzzy) args.add(SearchKeyword.FUZZY);
    args.add(SearchKeyword.MAX).add(max);
    args.add(SearchKeyword.WITHSCORES);
    return new CommandObject<>(args, BuilderFactory.TUPLE_LIST);
  }

  public final CommandObject ftSugDel(String key, String string) {
    return new CommandObject<>(commandArguments(SearchCommand.SUGDEL).key(key).add(string), BuilderFactory.BOOLEAN);
  }

  public final CommandObject ftSugLen(String key) {
    return new CommandObject<>(commandArguments(SearchCommand.SUGLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject> ftList() {
    return new CommandObject<>(commandArguments(SearchCommand._LIST), BuilderFactory.STRING_SET);
  }
  // RediSearch commands

  // RedisJSON commands
  public final CommandObject jsonSet(String key, Path2 path, Object object) {
    return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(object), BuilderFactory.STRING);
  }

  public final CommandObject jsonSetWithEscape(String key, Path2 path, Object object) {
    return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(
        getJsonObjectMapper().toJson(object)), BuilderFactory.STRING);
  }

  @Deprecated
  public final CommandObject jsonSet(String key, Path path, Object pojo) {
    return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(
        getJsonObjectMapper().toJson(pojo)), BuilderFactory.STRING);
  }

  @Deprecated
  public final CommandObject jsonSetWithPlainString(String key, Path path, String string) {
    return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(string), BuilderFactory.STRING);
  }

  public final CommandObject jsonSet(String key, Path2 path, Object object, JsonSetParams params) {
    return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(object).addParams(params), BuilderFactory.STRING);
  }

  public final CommandObject jsonSetWithEscape(String key, Path2 path, Object object, JsonSetParams params) {
    return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(
        getJsonObjectMapper().toJson(object)).addParams(params), BuilderFactory.STRING);
  }

  @Deprecated
  public final CommandObject jsonSet(String key, Path path, Object pojo, JsonSetParams params) {
    return new CommandObject<>(commandArguments(JsonCommand.SET).key(key).add(path).add(
        getJsonObjectMapper().toJson(pojo)).addParams(params), BuilderFactory.STRING);
  }

  public final CommandObject jsonMerge(String key, Path2 path, Object object) {
    return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add(object), BuilderFactory.STRING);
  }

  @Deprecated
  public final CommandObject jsonMerge(String key, Path path, Object pojo) {
    return new CommandObject<>(commandArguments(JsonCommand.MERGE).key(key).add(path).add(
        getJsonObjectMapper().toJson(pojo)), BuilderFactory.STRING);
  }

  public final CommandObject jsonGet(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.GET).key(key),
        protocol != RedisProtocol.RESP3 ? JSON_GENERIC_OBJECT : JsonBuilderFactory.JSON_OBJECT);
  }

  @Deprecated
  public final  CommandObject jsonGet(String key, Class clazz) {
    return new CommandObject<>(commandArguments(JsonCommand.GET).key(key), new JsonObjectBuilder<>(clazz));
  }

  public final CommandObject jsonGet(String key, Path2... paths) {
    return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), JsonBuilderFactory.JSON_OBJECT);
  }

  @Deprecated
  public final CommandObject jsonGet(String key, Path... paths) {
    return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), JSON_GENERIC_OBJECT);
  }

  @Deprecated
  public final CommandObject jsonGetAsPlainString(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).add(path), BuilderFactory.STRING);
  }

  @Deprecated
  public final  CommandObject jsonGet(String key, Class clazz, Path... paths) {
    return new CommandObject<>(commandArguments(JsonCommand.GET).key(key).addObjects((Object[]) paths), new JsonObjectBuilder<>(clazz));
  }

  public final CommandObject> jsonMGet(Path2 path, String... keys) {
    return new CommandObject<>(commandArguments(JsonCommand.MGET).keys((Object[]) keys).add(path), JsonBuilderFactory.JSON_ARRAY_LIST);
  }

  @Deprecated
  public final  CommandObject> jsonMGet(Path path, Class clazz, String... keys) {
    return new CommandObject<>(commandArguments(JsonCommand.MGET).keys((Object[]) keys).add(path), new JsonObjectListBuilder<>(clazz));
  }

  public final CommandObject jsonDel(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.DEL).key(key), BuilderFactory.LONG);
  }

  public final CommandObject jsonDel(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.DEL).key(key).add(path), BuilderFactory.LONG);
  }

  @Deprecated
  public final CommandObject jsonDel(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.DEL).key(key).add(path), BuilderFactory.LONG);
  }

  public final CommandObject jsonClear(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.CLEAR).key(key), BuilderFactory.LONG);
  }

  public final CommandObject jsonClear(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.CLEAR).key(key).add(path), BuilderFactory.LONG);
  }

  @Deprecated
  public final CommandObject jsonClear(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.CLEAR).key(key).add(path), BuilderFactory.LONG);
  }

  public final CommandObject> jsonToggle(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.TOGGLE).key(key).add(path), BuilderFactory.BOOLEAN_LIST);
  }

  @Deprecated
  public final CommandObject jsonToggle(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.TOGGLE).key(key).add(path), BuilderFactory.STRING);
  }

  @Deprecated
  public final CommandObject> jsonType(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key), JsonBuilderFactory.JSON_TYPE);
  }

  public final CommandObject>> jsonType(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path),
        protocol != RedisProtocol.RESP3 ? JsonBuilderFactory.JSON_TYPE_LIST : JsonBuilderFactory.JSON_TYPE_RESPONSE_RESP3_COMPATIBLE);
  }

  @Deprecated
  public final CommandObject> jsonType(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.TYPE).key(key).add(path), JsonBuilderFactory.JSON_TYPE);
  }

  @Deprecated
  public final CommandObject jsonStrAppend(String key, Object string) {
    return new CommandObject<>(commandArguments(JsonCommand.STRAPPEND).key(key).add(
        getJsonObjectMapper().toJson(string)), BuilderFactory.LONG);
  }

  public final CommandObject> jsonStrAppend(String key, Path2 path, Object string) {
    return new CommandObject<>(commandArguments(JsonCommand.STRAPPEND).key(key).add(path).add(
        getJsonObjectMapper().toJson(string)), BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject jsonStrAppend(String key, Path path, Object string) {
    return new CommandObject<>(commandArguments(JsonCommand.STRAPPEND).key(key).add(path).add(
        getJsonObjectMapper().toJson(string)), BuilderFactory.LONG);
  }

  @Deprecated
  public final CommandObject jsonStrLen(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject> jsonStrLen(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key).add(path), BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject jsonStrLen(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.STRLEN).key(key).add(path), BuilderFactory.LONG);
  }

  public final CommandObject jsonNumIncrBy(String key, Path2 path, double value) {
    return new CommandObject<>(commandArguments(JsonCommand.NUMINCRBY).key(key).add(path).add(value),
        JsonBuilderFactory.JSON_ARRAY_OR_DOUBLE_LIST);
  }

  @Deprecated
  public final CommandObject jsonNumIncrBy(String key, Path path, double value) {
    return new CommandObject<>(commandArguments(JsonCommand.NUMINCRBY).key(key).add(path).add(value), BuilderFactory.DOUBLE);
  }

  public final CommandObject jsonArrAppend(String key, String path, JSONObject... objects) {
    CommandArguments args = commandArguments(JsonCommand.ARRAPPEND).key(key).add(path);
    for (Object object : objects) {
      args.add(object);
    }
    return new CommandObject<>(args, BuilderFactory.LONG);
  }

  public final CommandObject> jsonArrAppend(String key, Path2 path, Object... objects) {
    CommandArguments args = commandArguments(JsonCommand.ARRAPPEND).key(key).add(path).addObjects(objects);
    return new CommandObject<>(args, BuilderFactory.LONG_LIST);
  }

  public final CommandObject> jsonArrAppendWithEscape(String key, Path2 path, Object... objects) {
    CommandArguments args = commandArguments(JsonCommand.ARRAPPEND).key(key).add(path);
    for (Object object : objects) {
      args.add(getJsonObjectMapper().toJson(object));
    }
    return new CommandObject<>(args, BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject jsonArrAppend(String key, Path path, Object... pojos) {
    CommandArguments args = commandArguments(JsonCommand.ARRAPPEND).key(key).add(path);
    for (Object pojo : pojos) {
      args.add(getJsonObjectMapper().toJson(pojo));
    }
    return new CommandObject<>(args, BuilderFactory.LONG);
  }

  public final CommandObject> jsonArrIndex(String key, Path2 path, Object scalar) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRINDEX).key(key).add(path).add(scalar), BuilderFactory.LONG_LIST);
  }

  public final CommandObject> jsonArrIndexWithEscape(String key, Path2 path, Object scalar) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRINDEX).key(key).add(path).add(
        getJsonObjectMapper().toJson(scalar)), BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject jsonArrIndex(String key, Path path, Object scalar) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRINDEX).key(key).add(path).add(
        getJsonObjectMapper().toJson(scalar)), BuilderFactory.LONG);
  }

  public final CommandObject> jsonArrInsert(String key, Path2 path, int index, Object... objects) {
    CommandArguments args = commandArguments(JsonCommand.ARRINSERT).key(key).add(path).add(index).addObjects(objects);
    return new CommandObject<>(args, BuilderFactory.LONG_LIST);
  }

  public final CommandObject> jsonArrInsertWithEscape(String key, Path2 path, int index, Object... objects) {
    CommandArguments args = commandArguments(JsonCommand.ARRINSERT).key(key).add(path).add(index);
    for (Object object : objects) {
      args.add(getJsonObjectMapper().toJson(object));
    }
    return new CommandObject<>(args, BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject jsonArrInsert(String key, Path path, int index, Object... pojos) {
    CommandArguments args = commandArguments(JsonCommand.ARRINSERT).key(key).add(path).add(index);
    for (Object pojo : pojos) {
      args.add(getJsonObjectMapper().toJson(pojo));
    }
    return new CommandObject<>(args, BuilderFactory.LONG);
  }

  @Deprecated
  public final CommandObject jsonArrPop(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key), new JsonObjectBuilder<>(Object.class));
  }

  @Deprecated
  public final  CommandObject jsonArrPop(String key, Class clazz) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key), new JsonObjectBuilder<>(clazz));
  }

  public final CommandObject> jsonArrPop(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path), new JsonObjectListBuilder<>(Object.class));
  }

  @Deprecated
  public final CommandObject jsonArrPop(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path), new JsonObjectBuilder<>(Object.class));
  }

  @Deprecated
  public final  CommandObject jsonArrPop(String key, Class clazz, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path), new JsonObjectBuilder<>(clazz));
  }

  public final CommandObject> jsonArrPop(String key, Path2 path, int index) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path).add(index), new JsonObjectListBuilder<>(Object.class));
  }

  @Deprecated
  public final CommandObject jsonArrPop(String key, Path path, int index) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path).add(index), new JsonObjectBuilder<>(Object.class));
  }

  @Deprecated
  public final  CommandObject jsonArrPop(String key, Class clazz, Path path, int index) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRPOP).key(key).add(path).add(index), new JsonObjectBuilder<>(clazz));
  }

  @Deprecated
  public final CommandObject jsonArrLen(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRLEN).key(key), BuilderFactory.LONG);
  }

  public final CommandObject> jsonArrLen(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRLEN).key(key).add(path), BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject jsonArrLen(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRLEN).key(key).add(path), BuilderFactory.LONG);
  }

  public final CommandObject> jsonArrTrim(String key, Path2 path, int start, int stop) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRTRIM).key(key).add(path).add(start).add(stop), BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject jsonArrTrim(String key, Path path, int start, int stop) {
    return new CommandObject<>(commandArguments(JsonCommand.ARRTRIM).key(key).add(path).add(start).add(stop), BuilderFactory.LONG);
  }

  @Deprecated
  public final CommandObject jsonObjLen(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.OBJLEN).key(key), BuilderFactory.LONG);
  }

  @Deprecated
  public final CommandObject jsonObjLen(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.OBJLEN).key(key).add(path), BuilderFactory.LONG);
  }

  public final CommandObject> jsonObjLen(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.OBJLEN).key(key).add(path), BuilderFactory.LONG_LIST);
  }

  @Deprecated
  public final CommandObject> jsonObjKeys(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.OBJKEYS).key(key), BuilderFactory.STRING_LIST);
  }

  @Deprecated
  public final CommandObject> jsonObjKeys(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.OBJKEYS).key(key).add(path), BuilderFactory.STRING_LIST);
  }

  public final CommandObject>> jsonObjKeys(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.OBJKEYS).key(key).add(path), BuilderFactory.STRING_LIST_LIST);
  }

  @Deprecated
  public final CommandObject jsonDebugMemory(String key) {
    return new CommandObject<>(commandArguments(JsonCommand.DEBUG).add("MEMORY").key(key), BuilderFactory.LONG);
  }

  @Deprecated
  public final CommandObject jsonDebugMemory(String key, Path path) {
    return new CommandObject<>(commandArguments(JsonCommand.DEBUG).add("MEMORY").key(key).add(path), BuilderFactory.LONG);
  }

  public final CommandObject> jsonDebugMemory(String key, Path2 path) {
    return new CommandObject<>(commandArguments(JsonCommand.DEBUG).add("MEMORY").key(key).add(path), BuilderFactory.LONG_LIST);
  }
  // RedisJSON commands

  // RedisTimeSeries commands
  public final CommandObject tsCreate(String key) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.CREATE).key(key), BuilderFactory.STRING);
  }

  public final CommandObject tsCreate(String key, TSCreateParams createParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.CREATE).key(key).addParams(createParams), BuilderFactory.STRING);
  }

  public final CommandObject tsDel(String key, long fromTimestamp, long toTimestamp) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.DEL).key(key)
        .add(fromTimestamp).add(toTimestamp), BuilderFactory.LONG);
  }

  public final CommandObject tsAlter(String key, TSAlterParams alterParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.ALTER).key(key).addParams(alterParams), BuilderFactory.STRING);
  }

  public final CommandObject tsAdd(String key, double value) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(Protocol.BYTES_ASTERISK).add(value), BuilderFactory.LONG);
  }

  public final CommandObject tsAdd(String key, long timestamp, double value) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key).add(timestamp).add(value), BuilderFactory.LONG);
  }

  public final CommandObject tsAdd(String key, long timestamp, double value, TSCreateParams createParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.ADD).key(key)
        .add(timestamp).add(value).addParams(createParams), BuilderFactory.LONG);
  }

  public final CommandObject> tsMAdd(Map.Entry... entries) {
    CommandArguments args = commandArguments(TimeSeriesCommand.MADD);
    for (Map.Entry entry : entries) {
      args.key(entry.getKey()).add(entry.getValue().getTimestamp()).add(entry.getValue().getValue());
    }
    return new CommandObject<>(args, BuilderFactory.LONG_LIST);
  }

  public final CommandObject tsIncrBy(String key, double value) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.INCRBY).key(key).add(value), BuilderFactory.LONG);
  }

  public final CommandObject tsIncrBy(String key, double value, long timestamp) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.INCRBY).key(key).add(value)
        .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG);
  }

  public final CommandObject tsDecrBy(String key, double value) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(value), BuilderFactory.LONG);
  }

  public final CommandObject tsDecrBy(String key, double value, long timestamp) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.DECRBY).key(key).add(value)
        .add(TimeSeriesKeyword.TIMESTAMP).add(timestamp), BuilderFactory.LONG);
  }

  public final CommandObject> tsRange(String key, long fromTimestamp, long toTimestamp) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.RANGE).key(key)
        .add(fromTimestamp).add(toTimestamp), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST);
  }

  public final CommandObject> tsRange(String key, TSRangeParams rangeParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.RANGE).key(key)
        .addParams(rangeParams), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST);
  }

  public final CommandObject> tsRevRange(String key, long fromTimestamp, long toTimestamp) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.REVRANGE).key(key)
        .add(fromTimestamp).add(toTimestamp), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST);
  }

  public final CommandObject> tsRevRange(String key, TSRangeParams rangeParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.REVRANGE).key(key)
        .addParams(rangeParams), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT_LIST);
  }

  public final CommandObject> tsMRange(long fromTimestamp, long toTimestamp, String... filters) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MRANGE).add(fromTimestamp)
        .add(toTimestamp).add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters),
        getTimeseriesMultiRangeResponseBuilder());
  }

  public final CommandObject> tsMRange(TSMRangeParams multiRangeParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MRANGE)
        .addParams(multiRangeParams), getTimeseriesMultiRangeResponseBuilder());
  }

  public final CommandObject> tsMRevRange(long fromTimestamp, long toTimestamp, String... filters) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MREVRANGE).add(fromTimestamp)
        .add(toTimestamp).add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters),
        getTimeseriesMultiRangeResponseBuilder());
  }

  public final CommandObject> tsMRevRange(TSMRangeParams multiRangeParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MREVRANGE).addParams(multiRangeParams),
        getTimeseriesMultiRangeResponseBuilder());
  }

  public final CommandObject tsGet(String key) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.GET).key(key), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT);
  }

  public final CommandObject tsGet(String key, TSGetParams getParams) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.GET).key(key).addParams(getParams), TimeSeriesBuilderFactory.TIMESERIES_ELEMENT);
  }

  public final CommandObject> tsMGet(TSMGetParams multiGetParams, String... filters) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.MGET).addParams(multiGetParams)
        .add(TimeSeriesKeyword.FILTER).addObjects((Object[]) filters),
        protocol == RedisProtocol.RESP3 ? TimeSeriesBuilderFactory.TIMESERIES_MGET_RESPONSE_RESP3
            : TimeSeriesBuilderFactory.TIMESERIES_MGET_RESPONSE);
  }

  public final CommandObject tsCreateRule(String sourceKey, String destKey, AggregationType aggregationType,
      long timeBucket) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.CREATERULE).key(sourceKey).key(destKey)
        .add(TimeSeriesKeyword.AGGREGATION).add(aggregationType).add(timeBucket), BuilderFactory.STRING);
  }

  public final CommandObject tsCreateRule(String sourceKey, String destKey, AggregationType aggregationType,
      long bucketDuration, long alignTimestamp) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.CREATERULE).key(sourceKey).key(destKey)
        .add(TimeSeriesKeyword.AGGREGATION).add(aggregationType).add(bucketDuration).add(alignTimestamp), BuilderFactory.STRING);
  }

  public final CommandObject tsDeleteRule(String sourceKey, String destKey) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.DELETERULE).key(sourceKey).key(destKey), BuilderFactory.STRING);
  }

  public final CommandObject> tsQueryIndex(String... filters) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.QUERYINDEX)
        .addObjects((Object[]) filters), BuilderFactory.STRING_LIST);
  }

  public final CommandObject tsInfo(String key) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.INFO).key(key), getTimeseriesInfoBuilder());
  }

  public final CommandObject tsInfoDebug(String key) {
    return new CommandObject<>(commandArguments(TimeSeriesCommand.INFO).key(key).add(TimeSeriesKeyword.DEBUG),
        getTimeseriesInfoBuilder());
  }

  private Builder> getTimeseriesMultiRangeResponseBuilder() {
    return protocol == RedisProtocol.RESP3 ? TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE_RESP3
        : TimeSeriesBuilderFactory.TIMESERIES_MRANGE_RESPONSE;
  }

  private Builder getTimeseriesInfoBuilder() {
    return protocol == RedisProtocol.RESP3 ? TSInfo.TIMESERIES_INFO_RESP3 : TSInfo.TIMESERIES_INFO;
  }
  // RedisTimeSeries commands

  // RedisBloom commands
  public final CommandObject bfReserve(String key, double errorRate, long capacity) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.RESERVE).key(key)
        .add(errorRate).add(capacity), BuilderFactory.STRING);
  }

  public final CommandObject bfReserve(String key, double errorRate, long capacity, BFReserveParams reserveParams) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.RESERVE).key(key)
        .add(errorRate).add(capacity).addParams(reserveParams), BuilderFactory.STRING);
  }

  public final CommandObject bfAdd(String key, String item) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.ADD).key(key).add(item), BuilderFactory.BOOLEAN);
  }

  public final CommandObject> bfMAdd(String key, String... items) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.MADD).key(key).
        addObjects((Object[]) items), BuilderFactory.BOOLEAN_WITH_ERROR_LIST);
  }

  public final CommandObject> bfInsert(String key, String... items) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.INSERT).key(key)
        .add(RedisBloomKeyword.ITEMS).addObjects((Object[]) items), BuilderFactory.BOOLEAN_WITH_ERROR_LIST);
  }

  public final CommandObject> bfInsert(String key, BFInsertParams insertParams, String... items) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.INSERT).key(key).addParams(insertParams)
        .add(RedisBloomKeyword.ITEMS).addObjects((Object[]) items), BuilderFactory.BOOLEAN_WITH_ERROR_LIST);
  }

  public final CommandObject bfExists(String key, String item) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.EXISTS).key(key).add(item), BuilderFactory.BOOLEAN);
  }

  public final CommandObject> bfMExists(String key, String... items) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.MEXISTS).key(key).
        addObjects((Object[]) items), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject> bfScanDump(String key, long iterator) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.SCANDUMP).key(key).add(iterator), BLOOM_SCANDUMP_RESPONSE);
  }

  public final CommandObject bfLoadChunk(String key, long iterator, byte[] data) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.LOADCHUNK).key(key).add(iterator).add(data), BuilderFactory.STRING);
  }

  public final CommandObject bfCard(String key) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.CARD).key(key), BuilderFactory.LONG);
  }

  public final CommandObject> bfInfo(String key) {
    return new CommandObject<>(commandArguments(BloomFilterCommand.INFO).key(key), BuilderFactory.ENCODED_OBJECT_MAP);
  }

  public final CommandObject cfReserve(String key, long capacity) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.RESERVE).key(key).add(capacity), BuilderFactory.STRING);
  }

  public final CommandObject cfReserve(String key, long capacity, CFReserveParams reserveParams) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.RESERVE).key(key).add(capacity).addParams(reserveParams), BuilderFactory.STRING);
  }

  public final CommandObject cfAdd(String key, String item) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.ADD).key(key).add(item), BuilderFactory.BOOLEAN);
  }

  public final CommandObject cfAddNx(String key, String item) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.ADDNX).key(key).add(item), BuilderFactory.BOOLEAN);
  }

  public final CommandObject> cfInsert(String key, String... items) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.INSERT).key(key)
        .add(RedisBloomKeyword.ITEMS).addObjects((Object[]) items), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject> cfInsert(String key, CFInsertParams insertParams, String... items) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.INSERT).key(key)
        .addParams(insertParams).add(RedisBloomKeyword.ITEMS).addObjects((Object[]) items), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject> cfInsertNx(String key, String... items) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.INSERTNX).key(key)
        .add(RedisBloomKeyword.ITEMS).addObjects((Object[]) items), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject> cfInsertNx(String key, CFInsertParams insertParams, String... items) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.INSERTNX).key(key)
        .addParams(insertParams).add(RedisBloomKeyword.ITEMS).addObjects((Object[]) items), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject cfExists(String key, String item) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.EXISTS).key(key).add(item), BuilderFactory.BOOLEAN);
  }

  public final CommandObject> cfMExists(String key, String... items) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.MEXISTS).key(key)
        .addObjects((Object[]) items), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject cfDel(String key, String item) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.DEL).key(key).add(item), BuilderFactory.BOOLEAN);
  }

  public final CommandObject cfCount(String key, String item) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.COUNT).key(key).add(item), BuilderFactory.LONG);
  }

  public final CommandObject> cfScanDump(String key, long iterator) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.SCANDUMP).key(key).add(iterator), BLOOM_SCANDUMP_RESPONSE);
  }

  public final CommandObject cfLoadChunk(String key, long iterator, byte[] data) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.LOADCHUNK).key(key).add(iterator).add(data), BuilderFactory.STRING);
  }

  public final CommandObject> cfInfo(String key) {
    return new CommandObject<>(commandArguments(CuckooFilterCommand.INFO).key(key), BuilderFactory.ENCODED_OBJECT_MAP);
  }

  public final CommandObject cmsInitByDim(String key, long width, long depth) {
    return new CommandObject<>(commandArguments(CountMinSketchCommand.INITBYDIM).key(key).add(width)
        .add(depth), BuilderFactory.STRING);
  }

  public final CommandObject cmsInitByProb(String key, double error, double probability) {
    return new CommandObject<>(commandArguments(CountMinSketchCommand.INITBYPROB).key(key).add(error)
        .add(probability), BuilderFactory.STRING);
  }

  public final CommandObject> cmsIncrBy(String key, Map itemIncrements) {
    CommandArguments args = commandArguments(CountMinSketchCommand.INCRBY).key(key);
    itemIncrements.entrySet().forEach(entry -> args.add(entry.getKey()).add(entry.getValue()));
    return new CommandObject<>(args, BuilderFactory.LONG_LIST);
  }

  public final CommandObject> cmsQuery(String key, String... items) {
    return new CommandObject<>(commandArguments(CountMinSketchCommand.QUERY).key(key)
        .addObjects((Object[]) items), BuilderFactory.LONG_LIST);
  }

  public final CommandObject cmsMerge(String destKey, String... keys) {
    return new CommandObject<>(commandArguments(CountMinSketchCommand.MERGE).key(destKey)
        .add(keys.length).keys((Object[]) keys), BuilderFactory.STRING);
  }

  public final CommandObject cmsMerge(String destKey, Map keysAndWeights) {
    CommandArguments args = commandArguments(CountMinSketchCommand.MERGE).key(destKey);
    args.add(keysAndWeights.size());
    keysAndWeights.entrySet().forEach(entry -> args.key(entry.getKey()));
    args.add(RedisBloomKeyword.WEIGHTS);
    keysAndWeights.entrySet().forEach(entry -> args.add(entry.getValue()));
    return new CommandObject<>(args, BuilderFactory.STRING);
  }

  public final CommandObject> cmsInfo(String key) {
    return new CommandObject<>(commandArguments(CountMinSketchCommand.INFO).key(key), BuilderFactory.ENCODED_OBJECT_MAP);
  }

  public final CommandObject topkReserve(String key, long topk) {
    return new CommandObject<>(commandArguments(TopKCommand.RESERVE).key(key).add(topk), BuilderFactory.STRING);
  }

  public final CommandObject topkReserve(String key, long topk, long width, long depth, double decay) {
    return new CommandObject<>(commandArguments(TopKCommand.RESERVE).key(key).add(topk)
        .add(width).add(depth).add(decay), BuilderFactory.STRING);
  }

  public final CommandObject> topkAdd(String key, String... items) {
    return new CommandObject<>(commandArguments(TopKCommand.ADD).key(key).addObjects((Object[]) items), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> topkIncrBy(String key, Map itemIncrements) {
    CommandArguments args = commandArguments(TopKCommand.INCRBY).key(key);
    itemIncrements.entrySet().forEach(entry -> args.add(entry.getKey()).add(entry.getValue()));
    return new CommandObject<>(args, BuilderFactory.STRING_LIST);
  }

  public final CommandObject> topkQuery(String key, String... items) {
    return new CommandObject<>(commandArguments(TopKCommand.QUERY).key(key).addObjects((Object[]) items), BuilderFactory.BOOLEAN_LIST);
  }

  public final CommandObject> topkList(String key) {
    return new CommandObject<>(commandArguments(TopKCommand.LIST).key(key), BuilderFactory.STRING_LIST);
  }

  public final CommandObject> topkListWithCount(String key) {
    return new CommandObject<>(commandArguments(TopKCommand.LIST).key(key)
        .add(RedisBloomKeyword.WITHCOUNT), BuilderFactory.STRING_LONG_MAP);
  }

  public final CommandObject> topkInfo(String key) {
    return new CommandObject<>(commandArguments(TopKCommand.INFO).key(key), BuilderFactory.ENCODED_OBJECT_MAP);
  }

  public final CommandObject tdigestCreate(String key) {
    return new CommandObject<>(commandArguments(TDigestCommand.CREATE).key(key), BuilderFactory.STRING);
  }

  public final CommandObject tdigestCreate(String key, int compression) {
    return new CommandObject<>(commandArguments(TDigestCommand.CREATE).key(key).add(RedisBloomKeyword.COMPRESSION)
        .add(compression), BuilderFactory.STRING);
  }

  public final CommandObject tdigestReset(String key) {
    return new CommandObject<>(commandArguments(TDigestCommand.RESET).key(key), BuilderFactory.STRING);
  }

  public final CommandObject tdigestMerge(String destinationKey, String... sourceKeys) {
    return new CommandObject<>(commandArguments(TDigestCommand.MERGE).key(destinationKey)
        .add(sourceKeys.length).keys((Object[]) sourceKeys), BuilderFactory.STRING);
  }

  public final CommandObject tdigestMerge(TDigestMergeParams mergeParams,
      String destinationKey, String... sourceKeys) {
    return new CommandObject<>(commandArguments(TDigestCommand.MERGE).key(destinationKey)
        .add(sourceKeys.length).keys((Object[]) sourceKeys).addParams(mergeParams), BuilderFactory.STRING);
  }

  public final CommandObject> tdigestInfo(String key) {
    return new CommandObject<>(commandArguments(TDigestCommand.INFO).key(key), BuilderFactory.ENCODED_OBJECT_MAP);
  }

  public final CommandObject tdigestAdd(String key, double... values) {
    return new CommandObject<>(addFlatArgs(commandArguments(TDigestCommand.ADD).key(key), values),
        BuilderFactory.STRING);
  }

  public final CommandObject> tdigestCDF(String key, double... values) {
    return new CommandObject<>(addFlatArgs(commandArguments(TDigestCommand.CDF).key(key), values),
        BuilderFactory.DOUBLE_LIST);
  }

  public final CommandObject> tdigestQuantile(String key, double... quantiles) {
    return new CommandObject<>(addFlatArgs(commandArguments(TDigestCommand.QUANTILE).key(key),
        quantiles), BuilderFactory.DOUBLE_LIST);
  }

  public final CommandObject tdigestMin(String key) {
    return new CommandObject<>(commandArguments(TDigestCommand.MIN).key(key), BuilderFactory.DOUBLE);
  }

  public final CommandObject tdigestMax(String key) {
    return new CommandObject<>(commandArguments(TDigestCommand.MAX).key(key), BuilderFactory.DOUBLE);
  }

  public final CommandObject tdigestTrimmedMean(String key, double lowCutQuantile, double highCutQuantile) {
    return new CommandObject<>(commandArguments(TDigestCommand.TRIMMED_MEAN).key(key).add(lowCutQuantile)
        .add(highCutQuantile), BuilderFactory.DOUBLE);
  }

  public final CommandObject> tdigestRank(String key, double... values) {
    return new CommandObject<>(addFlatArgs(commandArguments(TDigestCommand.RANK).key(key),
        values), BuilderFactory.LONG_LIST);
  }

  public final CommandObject> tdigestRevRank(String key, double... values) {
    return new CommandObject<>(addFlatArgs(commandArguments(TDigestCommand.REVRANK).key(key),
        values), BuilderFactory.LONG_LIST);
  }

  public final CommandObject> tdigestByRank(String key, long... ranks) {
    return new CommandObject<>(addFlatArgs(commandArguments(TDigestCommand.BYRANK).key(key),
        ranks), BuilderFactory.DOUBLE_LIST);
  }

  public final CommandObject> tdigestByRevRank(String key, long... ranks) {
    return new CommandObject<>(addFlatArgs(commandArguments(TDigestCommand.BYREVRANK).key(key),
        ranks), BuilderFactory.DOUBLE_LIST);
  }
  // RedisBloom commands

  // RedisGraph commands
  @Deprecated
  public final CommandObject> graphList() {
    return new CommandObject<>(commandArguments(GraphCommand.LIST), BuilderFactory.STRING_LIST);
  }

  @Deprecated
  public final CommandObject> graphProfile(String graphName, String query) {
    return new CommandObject<>(commandArguments(GraphCommand.PROFILE).key(graphName).add(query), BuilderFactory.STRING_LIST);
  }

  @Deprecated
  public final CommandObject> graphExplain(String graphName, String query) {
    return new CommandObject<>(commandArguments(GraphCommand.EXPLAIN).key(graphName).add(query), BuilderFactory.STRING_LIST);
  }

  @Deprecated
  public final CommandObject>> graphSlowlog(String graphName) {
    return new CommandObject<>(commandArguments(GraphCommand.SLOWLOG).key(graphName), BuilderFactory.ENCODED_OBJECT_LIST_LIST);
  }

  @Deprecated
  public final CommandObject graphConfigSet(String configName, Object value) {
    return new CommandObject<>(commandArguments(GraphCommand.CONFIG).add(GraphKeyword.SET).add(configName).add(value), BuilderFactory.STRING);
  }

  @Deprecated
  public final CommandObject> graphConfigGet(String configName) {
    return new CommandObject<>(commandArguments(GraphCommand.CONFIG).add(GraphKeyword.GET).add(configName), BuilderFactory.ENCODED_OBJECT_MAP);
  }
  // RedisGraph commands

  // RedisGears commands
  public final CommandObject tFunctionLoad(String libraryCode, TFunctionLoadParams params) {
    return new CommandObject<>(commandArguments(GearsCommand.TFUNCTION).add(GearsKeyword.LOAD)
        .addParams(params).add(libraryCode), BuilderFactory.STRING);
  }

  public final CommandObject tFunctionDelete(String libraryName) {
    return new CommandObject<>(commandArguments(GearsCommand.TFUNCTION).add(GearsKeyword.DELETE)
        .add(libraryName), BuilderFactory.STRING);
  }

  public final CommandObject> tFunctionList(TFunctionListParams params) {
    return new CommandObject<>(commandArguments(GearsCommand.TFUNCTION).add(GearsKeyword.LIST)
        .addParams(params), GearsLibraryInfo.GEARS_LIBRARY_INFO_LIST);
  }

  public final CommandObject tFunctionCall(String library, String function, List keys, List args) {
    return new CommandObject<>(commandArguments(GearsCommand.TFCALL).add(library + "." + function)
        .add(keys.size()).keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }

  public final CommandObject tFunctionCallAsync(String library, String function, List keys, List args) {
    return new CommandObject<>(commandArguments(GearsCommand.TFCALLASYNC).add(library + "." + function)
        .add(keys.size()).keys(keys).addObjects(args), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT);
  }
  // RedisGears commands

  /**
   * Get the instance for JsonObjectMapper if not null, otherwise a new instance reference with
   * default implementation will be created and returned.
   * 

This process of checking whether or not * the instance reference exists follows 'double-checked lock optimization' approach to reduce the overhead of * acquiring a lock by testing the lock criteria (the "lock hint") before acquiring the lock.

* @return the JsonObjectMapper instance reference * @see DefaultGsonObjectMapper */ private JsonObjectMapper getJsonObjectMapper() { JsonObjectMapper localRef = this.jsonObjectMapper; if (Objects.isNull(localRef)) { synchronized (this) { localRef = this.jsonObjectMapper; if (Objects.isNull(localRef)) { this.jsonObjectMapper = localRef = new DefaultGsonObjectMapper(); } } } return localRef; } public void setJsonObjectMapper(JsonObjectMapper jsonObjectMapper) { this.jsonObjectMapper = jsonObjectMapper; } public void setDefaultSearchDialect(int dialect) { if (dialect == 0) throw new IllegalArgumentException("DIALECT=0 cannot be set."); this.searchDialect.set(dialect); } private class SearchProfileResponseBuilder extends Builder>> { private static final String PROFILE_STR = "profile"; private final Builder replyBuilder; public SearchProfileResponseBuilder(Builder replyBuilder) { this.replyBuilder = replyBuilder; } @Override public Map.Entry> build(Object data) { List list = (List) data; if (list == null || list.isEmpty()) return null; if (list.get(0) instanceof KeyValue) { for (KeyValue keyValue : (List) data) { if (PROFILE_STR.equals(BuilderFactory.STRING.build(keyValue.getKey()))) { return KeyValue.of(replyBuilder.build(data), BuilderFactory.AGGRESSIVE_ENCODED_OBJECT_MAP.build(keyValue.getValue())); } } } return KeyValue.of(replyBuilder.build(list.get(0)), SearchBuilderFactory.SEARCH_PROFILE_PROFILE.build(list.get(1))); } } private class JsonObjectBuilder extends Builder { private final Class clazz; public JsonObjectBuilder(Class clazz) { this.clazz = clazz; } @Override public T build(Object data) { return getJsonObjectMapper().fromJson(BuilderFactory.STRING.build(data), clazz); } } /** * {@link JsonObjectBuilder} for {@code Object.class}. */ private final Builder JSON_GENERIC_OBJECT = new JsonObjectBuilder<>(Object.class); private class JsonObjectListBuilder extends Builder> { private final Class clazz; public JsonObjectListBuilder(Class clazz) { this.clazz = clazz; } @Override public List build(Object data) { if (data == null) { return null; } List list = BuilderFactory.STRING_LIST.build(data); return list.stream().map(s -> getJsonObjectMapper().fromJson(s, clazz)).collect(Collectors.toList()); } } private static final Builder> BLOOM_SCANDUMP_RESPONSE = new Builder>() { @Override public Map.Entry build(Object data) { List list = (List) data; return new KeyValue<>(BuilderFactory.LONG.build(list.get(0)), BuilderFactory.BINARY.build(list.get(1))); } }; private CommandArguments addFlatArgs(CommandArguments args, long... values) { for (long value : values) { args.add(value); } return args; } private CommandArguments addFlatArgs(CommandArguments args, double... values) { for (double value : values) { args.add(value); } return args; } private CommandArguments addFlatKeyValueArgs(CommandArguments args, String... keyvalues) { for (int i = 0; i < keyvalues.length; i += 2) { args.key(keyvalues[i]).add(keyvalues[i + 1]); } return args; } private CommandArguments addFlatKeyValueArgs(CommandArguments args, byte[]... keyvalues) { for (int i = 0; i < keyvalues.length; i += 2) { args.key(keyvalues[i]).add(keyvalues[i + 1]); } return args; } private CommandArguments addFlatMapArgs(CommandArguments args, Map map) { for (Map.Entry entry : map.entrySet()) { args.add(entry.getKey()); args.add(entry.getValue()); } return args; } private CommandArguments addSortedSetFlatMapArgs(CommandArguments args, Map map) { for (Map.Entry entry : map.entrySet()) { args.add(entry.getValue()); args.add(entry.getKey()); } return args; } private CommandArguments addGeoCoordinateFlatMapArgs(CommandArguments args, Map map) { for (Map.Entry entry : map.entrySet()) { GeoCoordinate ord = entry.getValue(); args.add(ord.getLongitude()); args.add(ord.getLatitude()); args.add(entry.getKey()); } return args; } }