///|
fn ArgsBuilder::push_score_items(
  self : ArgsBuilder,
  items : ArrayView[(String, Double)],
) -> Unit {
  for item in items {
    self.push_double(item.1)
    self.push_string(item.0)
  }
}

///|
fn Command::zadd(
  key : String,
  items : ArrayView[(String, Double)],
) -> Command[Int] {
  Command(
    ArgsBuilder(b"ZADD")..push_string(key)..push_score_items(items).build(),
    value => value.as_int(),
  )
}

///|
fn Command::zrem(key : String, members : ArrayView[String]) -> Command[Int] {
  Command(
    ArgsBuilder(b"ZREM")..push_string(key)..push_strings(members).build(),
    value => value.as_int(),
  )
}

///|
fn Command::zscore(key : String, value : String) -> Command[Double?] {
  Command(
    ArgsBuilder(b"ZSCORE")..push_string(key)..push_string(value).build(),
    value => value.as_option(value => value.as_double()),
  )
}

///|
fn Command::zcard(key : String) -> Command[Int] {
  Command(ArgsBuilder(b"ZCARD")..push_string(key).build(), value => {
    value.as_int()
  })
}

///|
fn Command::zcount(key : String, min : Double, max : Double) -> Command[Int] {
  Command(
    ArgsBuilder(b"ZCOUNT")
    ..push_string(key)
    ..push_double(min)
    ..push_double(max)
    .build(),
    value => value.as_int(),
  )
}

///|
fn Command::zrank(key : String, value : String) -> Command[Int?] {
  Command(ArgsBuilder(b"ZRANK")..push_string(key)..push_string(value).build(), value => {
    value.as_option(value => value.as_int())
  })
}

///|
fn Command::zrevrank(key : String, value : String) -> Command[Int?] {
  Command(
    ArgsBuilder(b"ZREVRANK")..push_string(key)..push_string(value).build(),
    value => value.as_option(value => value.as_int()),
  )
}

///|
fn Command::zrange(
  key : String,
  start : Int,
  stop : Int,
) -> Command[Array[String]] {
  Command(
    ArgsBuilder(b"ZRANGE")
    ..push_string(key)
    ..push_int(start)
    ..push_int(stop)
    .build(),
    value => value.as_array(value => value.as_string()),
  )
}

///|
fn Command::zrange_with_scores(
  key : String,
  start : Int,
  stop : Int,
) -> Command[Array[(String, Double)]] {
  Command(
    ArgsBuilder(b"ZRANGE")
    ..push_string(key)
    ..push_int(start)
    ..push_int(stop)
    ..push_bytes(b"WITHSCORES")
    .build(),
    value => value.as_score_pairs(),
  )
}

///|
fn Command::zrevrange(
  key : String,
  start : Int,
  stop : Int,
) -> Command[Array[String]] {
  Command(
    ArgsBuilder(b"ZREVRANGE")
    ..push_string(key)
    ..push_int(start)
    ..push_int(stop)
    .build(),
    value => value.as_array(value => value.as_string()),
  )
}

///|
fn Command::zrevrange_with_scores(
  key : String,
  start : Int,
  stop : Int,
) -> Command[Array[(String, Double)]] {
  Command(
    ArgsBuilder(b"ZREVRANGE")
    ..push_string(key)
    ..push_int(start)
    ..push_int(stop)
    ..push_bytes(b"WITHSCORES")
    .build(),
    value => value.as_score_pairs(),
  )
}

///|
fn Command::zrangebyscore(
  key : String,
  min : Double,
  max : Double,
  offset? : Int,
  count? : Int,
) -> Command[Array[String]] raise {
  Command(
    ArgsBuilder(b"ZRANGEBYSCORE")
    ..push_string(key)
    ..push_double(min)
    ..push_double(max)
    ..push_limit_options(offset, count)
    .build(),
    value => value.as_array(value => value.as_string()),
  )
}

///|
fn Command::zrangebyscore_with_scores(
  key : String,
  min : Double,
  max : Double,
  offset? : Int,
  count? : Int,
) -> Command[Array[(String, Double)]] raise {
  Command(
    ArgsBuilder(b"ZRANGEBYSCORE")
    ..push_string(key)
    ..push_double(min)
    ..push_double(max)
    ..push_bytes(b"WITHSCORES")
    ..push_limit_options(offset, count)
    .build(),
    value => value.as_score_pairs(),
  )
}

///|
fn Command::zincrby(
  key : String,
  increment : Double,
  value : String,
) -> Command[Double] {
  Command(
    ArgsBuilder(b"ZINCRBY")
    ..push_string(key)
    ..push_double(increment)
    ..push_string(value)
    .build(),
    value => value.as_double(),
  )
}

///|
fn Command::zremrangebyrank(
  key : String,
  start : Int,
  stop : Int,
) -> Command[Int] {
  Command(
    ArgsBuilder(b"ZREMRANGEBYRANK")
    ..push_string(key)
    ..push_int(start)
    ..push_int(stop)
    .build(),
    value => value.as_int(),
  )
}

///|
fn Command::zremrangebyscore(
  key : String,
  min : Double,
  max : Double,
) -> Command[Int] {
  Command(
    ArgsBuilder(b"ZREMRANGEBYSCORE")
    ..push_string(key)
    ..push_double(min)
    ..push_double(max)
    .build(),
    value => value.as_int(),
  )
}

///|
fn Command::zpopmin(
  key : String,
  count? : Int,
) -> Command[Array[(String, Double)]] {
  let args = ArgsBuilder(b"ZPOPMIN")
  args.push_string(key)
  if count is Some(count) {
    args.push_int(count)
  }
  Command(args.build(), value => value.as_score_pairs())
}

///|
fn Command::zpopmax(
  key : String,
  count? : Int,
) -> Command[Array[(String, Double)]] {
  let args = ArgsBuilder(b"ZPOPMAX")
  args.push_string(key)
  if count is Some(count) {
    args.push_int(count)
  }
  Command(args.build(), value => value.as_score_pairs())
}

///|
fn Command::zscan(
  key : String,
  cursor : String,
  pattern? : String,
  count? : Int,
) -> Command[(String, Array[(String, Double)])] {
  Command(
    ArgsBuilder(b"ZSCAN")
    ..push_string(key)
    ..push_string(cursor)
    ..push_scan_options(pattern, count)
    .build(),
    value => value.as_scan_score_pairs(),
  )
}