@Override
 public RedisClient zcount(
     String key, double min, double max, Handler<AsyncResult<Long>> handler) {
   String minVal = (min == Double.NEGATIVE_INFINITY) ? "-inf" : String.valueOf(min);
   String maxVal = (max == Double.POSITIVE_INFINITY) ? "+inf" : String.valueOf(max);
   sendLong(ZCOUNT, RedisCommandUtils.toPayload(key, minVal, maxVal), handler);
   return this;
 }
 @Override
 public RedisClient evalsha(
     String sha1, List<String> keys, List<String> args, Handler<AsyncResult<Void>> handler) {
   keys = (keys != null) ? keys : Collections.emptyList();
   args = (args != null) ? args : Collections.emptyList();
   sendVoid(EVALSHA, RedisCommandUtils.toPayload(sha1, keys.size(), keys, args), handler);
   return this;
 }
 @Override
 public RedisClient zaddMany(
     String key, Map<String, Double> members, Handler<AsyncResult<Long>> handler) {
   // flip from <String, Double> to <Double, String> when wrapping
   Stream flipped = members.entrySet().stream().map(e -> new Object[] {e.getValue(), e.getKey()});
   sendLong(ZADD, RedisCommandUtils.toPayload(key, flipped), handler);
   return this;
 }
 @Override
 public RedisClient sort(
     String key, SortOptions options, Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(
       SORT,
       RedisCommandUtils.toPayload(key, options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient bitop(
     BitOperation operation,
     String destkey,
     List<String> keys,
     Handler<AsyncResult<Long>> handler) {
   sendLong(BITOP, RedisCommandUtils.toPayload(operation.name(), destkey, keys), handler);
   return this;
 }
 @Override
 public RedisClient zscan(
     String key, String cursor, ScanOptions options, Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(
       ZSCAN,
       RedisCommandUtils.toPayload(key, cursor, options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient pubsubChannels(String pattern, Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(
       PUBSUB,
       RedisCommandUtils.toPayload(
           "CHANNELS", pattern == null || "".equals(pattern) ? null : pattern),
       handler);
   return this;
 }
 @Override
 public RedisClient setWithOptions(
     String key, String value, SetOptions options, Handler<AsyncResult<Void>> handler) {
   sendVoid(
       SET,
       RedisCommandUtils.toPayload(key, value, options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient linsert(
     String key,
     InsertOptions option,
     String pivot,
     String value,
     Handler<AsyncResult<Long>> handler) {
   sendLong(LINSERT, RedisCommandUtils.toPayload(key, option.name(), pivot, value), handler);
   return this;
 }
 @Override
 public RedisClient restore(
     String key, long millis, String serialized, Handler<AsyncResult<String>> handler) {
   send(
       RESTORE,
       RedisCommandUtils.toPayload(key, millis, RedisEncoding.decode(serialized)),
       String.class,
       true,
       handler);
   return this;
 }
 @Override
 public RedisClient zunionstore(
     String destkey,
     List<String> sets,
     AggregateOptions options,
     Handler<AsyncResult<Long>> handler) {
   sendLong(
       ZUNIONSTORE,
       RedisCommandUtils.toPayload(
           destkey, sets.size(), sets, options != null ? options.name() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient zrevrangebyscore(
     String key,
     String max,
     String min,
     RangeLimitOptions options,
     Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(
       ZREVRANGEBYSCORE,
       RedisCommandUtils.toPayload(key, max, min, options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient zrangebylex(
     String key,
     String min,
     String max,
     LimitOptions options,
     Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(
       ZRANGEBYLEX,
       RedisCommandUtils.toPayload(key, min, max, options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient eval(
     String script, List<String> keys, List<String> args, Handler<AsyncResult<Void>> handler) {
   keys = (keys != null) ? keys : Collections.emptyList();
   args = (args != null) ? args : Collections.emptyList();
   if (keys.size() != args.size()) {
     handler.handle(
         Future.failedFuture(
             new IllegalArgumentException("Key list, and argument list are not the same size")));
   } else {
     sendVoid(EVAL, RedisCommandUtils.toPayload(script, keys.size(), keys, args), handler);
   }
   return this;
 }
 @Override
 public RedisClient zrevrange(
     String key,
     long start,
     long stop,
     RangeOptions options,
     Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(
       ZREVRANGE,
       RedisCommandUtils.toPayload(
           key, start, stop, options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient dump(String key, Handler<AsyncResult<String>> handler) {
   send(
       DUMP,
       RedisCommandUtils.toPayload(key),
       String.class,
       true,
       dump -> {
         if (dump.failed()) {
           handler.handle(dump);
         } else {
           handler.handle(Future.succeededFuture(RedisEncoding.encode(dump.result())));
         }
       });
   return this;
 }
 @Override
 public RedisClient migrate(
     String host,
     int port,
     String key,
     int destdb,
     long timeout,
     MigrateOptions options,
     Handler<AsyncResult<String>> handler) {
   sendString(
       MIGRATE,
       RedisCommandUtils.toPayload(
           host, port, key, destdb, timeout, options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient zunionstoreWeighed(
     String destkey,
     Map<String, Double> sets,
     AggregateOptions options,
     Handler<AsyncResult<Long>> handler) {
   sendLong(
       ZUNIONSTORE,
       RedisCommandUtils.toPayload(
           destkey,
           sets.size(),
           sets.keySet(),
           "WEIGHTS",
           sets.values(),
           options != null ? options.toJsonArray() : null),
       handler);
   return this;
 }
 @Override
 public RedisClient scriptExistsMany(
     List<String> scripts, Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(SCRIPT_EXISTS, RedisCommandUtils.toPayload(scripts), handler);
   return this;
 }
 @Override
 public RedisClient blpopMany(
     List<String> keys, int seconds, Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(BLPOP, RedisCommandUtils.toPayload(keys, seconds), handler);
   return this;
 }
 @Override
 public RedisClient scard(String key, Handler<AsyncResult<Long>> handler) {
   sendLong(SCARD, RedisCommandUtils.toPayload(key), handler);
   return this;
 }
 @Override
 public RedisClient saddMany(
     String key, List<String> members, Handler<AsyncResult<Long>> handler) {
   sendLong(SADD, RedisCommandUtils.toPayload(key, members), handler);
   return this;
 }
 @Override
 public RedisClient rpushx(String key, String value, Handler<AsyncResult<Long>> handler) {
   sendLong(RPUSHX, RedisCommandUtils.toPayload(key, value), handler);
   return this;
 }
 @Override
 public RedisClient rpushMany(
     String key, List<String> values, Handler<AsyncResult<Long>> handler) {
   sendLong(RPUSH, RedisCommandUtils.toPayload(key, values), handler);
   return this;
 }
 @Override
 public RedisClient rpoplpush(String key, String destkey, Handler<AsyncResult<String>> handler) {
   sendString(RPOPLPUSH, RedisCommandUtils.toPayload(key, destkey), handler);
   return this;
 }
 @Override
 public RedisClient renamenx(String key, String newkey, Handler<AsyncResult<Long>> handler) {
   sendLong(RENAMENX, RedisCommandUtils.toPayload(key, newkey), handler);
   return this;
 }
 @Override
 public RedisClient punsubscribe(List<String> patterns, Handler<AsyncResult<Void>> handler) {
   sendVoid(PUNSUBSCRIBE, RedisCommandUtils.toPayload(patterns), handler);
   return this;
 }
 @Override
 public RedisClient publish(String channel, String message, Handler<AsyncResult<Long>> handler) {
   sendLong(PUBLISH, RedisCommandUtils.toPayload(channel, message), handler);
   return this;
 }
 public RedisClient pubsubNumpat(Handler<AsyncResult<Long>> handler) {
   sendLong(PUBSUB, RedisCommandUtils.toPayload("NUMPAT"), handler);
   return this;
 }
 public RedisClient pubsubNumsub(List<String> channels, Handler<AsyncResult<JsonArray>> handler) {
   sendJsonArray(PUBSUB, RedisCommandUtils.toPayload("NUMSUB", channels), handler);
   return this;
 }