From fc43d270d1aacb54c149b794edd04a95fa28b527 Mon Sep 17 00:00:00 2001 From: Anatoly Sergeev Date: Sat, 25 Feb 2023 18:32:39 +0300 Subject: [PATCH] add resp command in order to distinguish resp types (#763) --- .../scala/zio/redis/ClusterExecutor.scala | 4 +- redis/src/main/scala/zio/redis/Input.scala | 494 +++++++++-------- .../main/scala/zio/redis/RedisCommand.scala | 6 +- .../main/scala/zio/redis/RedisExecutor.scala | 4 +- .../main/scala/zio/redis/RespArgument.scala | 64 +++ .../main/scala/zio/redis/RespCommand.scala | 36 ++ .../scala/zio/redis/SingleNodeExecutor.scala | 4 +- .../main/scala/zio/redis/api/Cluster.scala | 8 +- redis/src/main/scala/zio/redis/api/Geo.scala | 31 +- .../src/main/scala/zio/redis/api/Hashes.scala | 48 +- .../scala/zio/redis/api/HyperLogLog.scala | 18 +- redis/src/main/scala/zio/redis/api/Keys.scala | 47 +- .../src/main/scala/zio/redis/api/Lists.scala | 77 ++- redis/src/main/scala/zio/redis/api/Sets.scala | 43 +- .../main/scala/zio/redis/api/SortedSets.scala | 144 +++-- .../main/scala/zio/redis/api/Streams.scala | 96 ++-- .../main/scala/zio/redis/api/Strings.scala | 79 ++- .../src/test/scala/zio/redis/InputSpec.scala | 508 +++++++++--------- redis/src/test/scala/zio/redis/KeysSpec.scala | 26 +- .../test/scala/zio/redis/ScriptingSpec.scala | 14 +- .../test/scala/zio/redis/StreamsSpec.scala | 10 +- 21 files changed, 1057 insertions(+), 704 deletions(-) create mode 100644 redis/src/main/scala/zio/redis/RespArgument.scala create mode 100644 redis/src/main/scala/zio/redis/RespCommand.scala diff --git a/redis/src/main/scala/zio/redis/ClusterExecutor.scala b/redis/src/main/scala/zio/redis/ClusterExecutor.scala index a4ec837..8a0cd60 100644 --- a/redis/src/main/scala/zio/redis/ClusterExecutor.scala +++ b/redis/src/main/scala/zio/redis/ClusterExecutor.scala @@ -31,7 +31,7 @@ final case class ClusterExecutor( scope: Scope.Closeable ) extends RedisExecutor { - def execute(command: Chunk[RespValue.BulkString]): IO[RedisError, RespValue] = { + def execute(command: RespCommand): IO[RedisError, RespValue] = { def execute(keySlot: Slot) = for { @@ -58,7 +58,7 @@ final case class ClusterExecutor( } for { - key <- ZIO.attempt(command(1)).orElseFail(CusterKeyError) + key <- ZIO.attempt(command.args(1).value).orElseFail(CusterKeyError) keySlot = Slot((key.asCRC16 % SlotsAmount).toLong) result <- executeSafe(keySlot) } yield result diff --git a/redis/src/main/scala/zio/redis/Input.scala b/redis/src/main/scala/zio/redis/Input.scala index c4a73c9..99d266c 100644 --- a/redis/src/main/scala/zio/redis/Input.scala +++ b/redis/src/main/scala/zio/redis/Input.scala @@ -17,7 +17,6 @@ package zio.redis import zio._ -import zio.redis.RespValue.BulkString import zio.schema.Schema import zio.schema.codec.BinaryCodec @@ -27,10 +26,10 @@ import java.util.concurrent.TimeUnit sealed trait Input[-A] { self => - private[redis] def encode(data: A)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] + private[redis] def encode(data: A)(implicit codec: BinaryCodec): RespCommand final def contramap[B](f: B => A): Input[B] = new Input[B] { - def encode(data: B)(implicit codec: BinaryCodec): Chunk[BulkString] = self.encode(f(data)) + def encode(data: B)(implicit codec: BinaryCodec): RespCommand = self.encode(f(data)) } } @@ -38,417 +37,466 @@ object Input { def apply[A](implicit input: Input[A]): Input[A] = input - @inline - private[this] def encodeString(s: String): RespValue.BulkString = RespValue.bulkString(s) - @inline - private[this] def encodeBytes[A](value: A)(implicit codec: BinaryCodec, schema: Schema[A]): RespValue.BulkString = - RespValue.BulkString(codec.encode(schema)(value)) - case object AbsTtlInput extends Input[AbsTtl] { - def encode(data: AbsTtl)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: AbsTtl)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object AddressInput extends Input[Address] { - def encode(data: Address)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Address)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.stringify)) } case object AggregateInput extends Input[Aggregate] { - def encode(data: Aggregate)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("AGGREGATE"), encodeString(data.stringify)) + def encode(data: Aggregate)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("AGGREGATE"), RespArgument.Literal(data.stringify)) } case object AlphaInput extends Input[Alpha] { - def encode(data: Alpha)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Alpha)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object AuthInput extends Input[Auth] { - def encode(data: Auth)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("AUTH"), encodeString(data.password)) + def encode(data: Auth)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("AUTH"), RespArgument.Value(data.password)) } case object BoolInput extends Input[Boolean] { - def encode(data: Boolean)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(if (data) "1" else "0")) + def encode(data: Boolean)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(if (data) "1" else "0")) } case object StralgoLcsQueryTypeInput extends Input[StrAlgoLcsQueryType] { - def encode(data: StrAlgoLcsQueryType)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = data match { - case StrAlgoLcsQueryType.Len => Chunk.single(encodeString("LEN")) + def encode(data: StrAlgoLcsQueryType)(implicit codec: BinaryCodec): RespCommand = data match { + case StrAlgoLcsQueryType.Len => RespCommand(RespArgument.Literal("LEN")) case StrAlgoLcsQueryType.Idx(minMatchLength, withMatchLength) => { - val idx = Chunk.single(encodeString("IDX")) + val idx = Chunk.single(RespArgument.Literal("IDX")) val min = - if (minMatchLength > 1) Chunk(encodeString("MINMATCHLEN"), encodeString(minMatchLength.toString)) - else Chunk.empty - val length = if (withMatchLength) Chunk.single(encodeString("WITHMATCHLEN")) else Chunk.empty - Chunk(idx, min, length).flatten + if (minMatchLength > 1) + Chunk(RespArgument.Literal("MINMATCHLEN"), RespArgument.Unknown(minMatchLength.toString)) + else Chunk.empty[RespArgument] + val length = + if (withMatchLength) Chunk.single(RespArgument.Literal("WITHMATCHLEN")) else Chunk.empty[RespArgument] + RespCommand(Chunk(idx, min, length).flatten) } } } case object BitFieldCommandInput extends Input[BitFieldCommand] { - def encode(data: BitFieldCommand)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { + def encode(data: BitFieldCommand)(implicit codec: BinaryCodec): RespCommand = { import BitFieldCommand._ - data match { - case BitFieldGet(t, o) => Chunk(encodeString("GET"), encodeString(t.stringify), encodeString(o.toString)) + val respArgs = data match { + case BitFieldGet(t, o) => + Chunk(RespArgument.Literal("GET"), RespArgument.Unknown(t.stringify), RespArgument.Unknown(o.toString)) case BitFieldSet(t, o, v) => - Chunk(encodeString("SET"), encodeString(t.stringify), encodeString(o.toString), encodeString(v.toString)) + Chunk( + RespArgument.Literal("SET"), + RespArgument.Unknown(t.stringify), + RespArgument.Unknown(o.toString), + RespArgument.Unknown(v.toString) + ) case BitFieldIncr(t, o, i) => - Chunk(encodeString("INCRBY"), encodeString(t.stringify), encodeString(o.toString), encodeString(i.toString)) - case bfo: BitFieldOverflow => Chunk(encodeString("OVERFLOW"), encodeString(bfo.stringify)) + Chunk( + RespArgument.Literal("INCRBY"), + RespArgument.Unknown(t.stringify), + RespArgument.Unknown(o.toString), + RespArgument.Unknown(i.toString) + ) + case bfo: BitFieldOverflow => Chunk(RespArgument.Literal("OVERFLOW"), RespArgument.Literal(bfo.stringify)) } + RespCommand(respArgs) } } case object BitOperationInput extends Input[BitOperation] { - def encode(data: BitOperation)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: BitOperation)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object BitPosRangeInput extends Input[BitPosRange] { - def encode(data: BitPosRange)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { - val start = encodeString(data.start.toString) - data.end.fold(Chunk.single(start))(end => Chunk(start, encodeString(end.toString))) + def encode(data: BitPosRange)(implicit codec: BinaryCodec): RespCommand = { + val start = RespArgument.Unknown(data.start.toString) + val respArgs = data.end.fold(Chunk.single(start))(end => Chunk(start, RespArgument.Unknown(end.toString))) + RespCommand(respArgs) } } case object ByInput extends Input[String] { - def encode(data: String)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("BY"), encodeString(data)) + def encode(data: String)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("BY"), RespArgument.Unknown(data)) } case object ChangedInput extends Input[Changed] { - def encode(data: Changed)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Changed)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object ClientKillInput extends Input[ClientKillFilter] { - def encode(data: ClientKillFilter)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = data match { - case addr: ClientKillFilter.Address => Chunk(encodeString("ADDR"), encodeString(addr.stringify)) - case laddr: ClientKillFilter.LocalAddress => Chunk(encodeString("LADDR"), encodeString(laddr.stringify)) - case ClientKillFilter.Id(clientId) => Chunk(encodeString("ID"), encodeString(clientId.toString)) - case ClientKillFilter.Type(clientType) => Chunk(encodeString("TYPE"), encodeString(clientType.stringify)) - case ClientKillFilter.User(username) => Chunk(encodeString("USER"), encodeString(username)) - case ClientKillFilter.SkipMe(skip) => Chunk(encodeString("SKIPME"), encodeString(if (skip) "YES" else "NO")) + def encode(data: ClientKillFilter)(implicit codec: BinaryCodec): RespCommand = data match { + case addr: ClientKillFilter.Address => + RespCommand(RespArgument.Literal("ADDR"), RespArgument.Unknown(addr.stringify)) + case laddr: ClientKillFilter.LocalAddress => + RespCommand(RespArgument.Literal("LADDR"), RespArgument.Unknown(laddr.stringify)) + case ClientKillFilter.Id(clientId) => + RespCommand(RespArgument.Literal("ID"), RespArgument.Unknown(clientId.toString)) + case ClientKillFilter.Type(clientType) => + RespCommand(RespArgument.Literal("TYPE"), RespArgument.Literal(clientType.stringify)) + case ClientKillFilter.User(username) => RespCommand(RespArgument.Literal("USER"), RespArgument.Unknown(username)) + case ClientKillFilter.SkipMe(skip) => + RespCommand(RespArgument.Literal("SKIPME"), RespArgument.Literal(if (skip) "YES" else "NO")) } } case object ClientPauseModeInput extends Input[ClientPauseMode] { - def encode(data: ClientPauseMode)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: ClientPauseMode)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object ClientTrackingInput extends Input[Option[(Option[Long], Option[ClientTrackingMode], Boolean, Chunk[String])]] { def encode( data: Option[(Option[Long], Option[ClientTrackingMode], Boolean, Chunk[String])] - )(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + )(implicit codec: BinaryCodec): RespCommand = data match { case Some((clientRedir, mode, noLoop, prefixes)) => val modeChunk = mode match { - case Some(ClientTrackingMode.OptIn) => Chunk(encodeString("OPTIN")) - case Some(ClientTrackingMode.OptOut) => Chunk(encodeString("OPTOUT")) - case Some(ClientTrackingMode.Broadcast) => Chunk(encodeString("BCAST")) - case None => Chunk.empty + case Some(ClientTrackingMode.OptIn) => RespCommand(RespArgument.Literal("OPTIN")) + case Some(ClientTrackingMode.OptOut) => RespCommand(RespArgument.Literal("OPTOUT")) + case Some(ClientTrackingMode.Broadcast) => RespCommand(RespArgument.Literal("BCAST")) + case None => RespCommand.empty } - val loopChunk = if (noLoop) Chunk(encodeString("NOLOOP")) else Chunk.empty - Chunk(encodeString("ON")) ++ - clientRedir.fold(Chunk.empty: Chunk[RespValue.BulkString])(id => - Chunk(encodeString("REDIRECT"), encodeString(id.toString)) + val loopChunk = if (noLoop) RespCommand(RespArgument.Literal("NOLOOP")) else RespCommand.empty + RespCommand(RespArgument.Literal("ON")) ++ + clientRedir.fold(RespCommand.empty)(id => + RespCommand(RespArgument.Literal("REDIRECT"), RespArgument.Unknown(id.toString)) + ) ++ + RespCommand( + prefixes.flatMap(prefix => Chunk(RespArgument.Literal("PREFIX"), RespArgument.Unknown(prefix))) ) ++ - prefixes.flatMap(prefix => Chunk(encodeString("PREFIX"), encodeString(prefix))) ++ modeChunk ++ loopChunk case None => - Chunk(encodeString("OFF")) + RespCommand(RespArgument.Literal("OFF")) } } case object CopyInput extends Input[Copy] { - def encode(data: Copy)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Copy)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object CountInput extends Input[Count] { - def encode(data: Count)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("COUNT"), encodeString(data.count.toString)) + def encode(data: Count)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("COUNT"), RespArgument.Unknown(data.count.toString)) } case object RedisTypeInput extends Input[RedisType] { - def encode(data: RedisType)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("TYPE"), encodeString(data.stringify)) + def encode(data: RedisType)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("TYPE"), RespArgument.Literal(data.stringify)) } case object PatternInput extends Input[Pattern] { - def encode(data: Pattern)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("MATCH"), encodeString(data.pattern)) + def encode(data: Pattern)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("MATCH"), RespArgument.Unknown(data.pattern)) } case object GetInput extends Input[String] { - def encode(data: String)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("GET"), encodeString(data)) + def encode(data: String)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("GET"), RespArgument.Unknown(data)) } case object PositionInput extends Input[Position] { - def encode(data: Position)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Position)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object SideInput extends Input[Side] { - def encode(data: Side)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Side)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object DoubleInput extends Input[Double] { - def encode(data: Double)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.toString)) + def encode(data: Double)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.toString)) } case object DurationMillisecondsInput extends Input[Duration] { - def encode(data: Duration)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.toMillis.toString)) + def encode(data: Duration)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.toMillis.toString)) } case object DurationSecondsInput extends Input[Duration] { - def encode(data: Duration)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { + def encode(data: Duration)(implicit codec: BinaryCodec): RespCommand = { val seconds = TimeUnit.MILLISECONDS.toSeconds(data.toMillis) - Chunk.single(encodeString(seconds.toString)) + RespCommand(RespArgument.Unknown(seconds.toString)) } } case object DurationTtlInput extends Input[Duration] { - def encode(data: Duration)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { + def encode(data: Duration)(implicit codec: BinaryCodec): RespCommand = { val milliseconds = data.toMillis - Chunk(encodeString("PX"), encodeString(milliseconds.toString)) + RespCommand(RespArgument.Literal("PX"), RespArgument.Unknown(milliseconds.toString)) } } case object FreqInput extends Input[Freq] { - def encode(data: Freq)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("FREQ"), encodeString(data.frequency)) + def encode(data: Freq)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("FREQ"), RespArgument.Unknown(data.frequency)) } case object IdleTimeInput extends Input[IdleTime] { - def encode(data: IdleTime)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("IDLETIME"), encodeString(data.seconds.toString)) + def encode(data: IdleTime)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("IDLETIME"), RespArgument.Unknown(data.seconds.toString)) } case object IncrementInput extends Input[Increment] { - def encode(data: Increment)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Increment)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object KeepTtlInput extends Input[KeepTtl] { - def encode(data: KeepTtl)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: KeepTtl)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object LimitInput extends Input[Limit] { - def encode(data: Limit)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("LIMIT"), encodeString(data.offset.toString), encodeString(data.count.toString)) + def encode(data: Limit)(implicit codec: BinaryCodec): RespCommand = + RespCommand( + RespArgument.Literal("LIMIT"), + RespArgument.Unknown(data.offset.toString), + RespArgument.Unknown(data.count.toString) + ) } case object LongInput extends Input[Long] { - def encode(data: Long)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.toString)) + def encode(data: Long)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.toString)) } case object LongLatInput extends Input[LongLat] { - def encode(data: LongLat)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString(data.longitude.toString), encodeString(data.latitude.toString)) + def encode(data: LongLat)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.longitude.toString), RespArgument.Unknown(data.latitude.toString)) } final case class MemberScoreInput[M: Schema]() extends Input[MemberScore[M]] { - def encode(data: MemberScore[M])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString(data.score.toString), encodeBytes(data.member)) + def encode(data: MemberScore[M])(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.score.toString), RespArgument.Value(data.member)) } case object NoInput extends Input[Unit] { - def encode(data: Unit)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = Chunk.empty + def encode(data: Unit)(implicit codec: BinaryCodec): RespCommand = RespCommand.empty } final case class NonEmptyList[-A](input: Input[A]) extends Input[(A, List[A])] { - def encode(data: (A, List[A]))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - (data._1 :: data._2).foldLeft(Chunk.empty: Chunk[RespValue.BulkString])((acc, a) => acc ++ input.encode(a)) + def encode(data: (A, List[A]))(implicit codec: BinaryCodec): RespCommand = + (data._1 :: data._2).foldLeft(RespCommand.empty)((acc, a) => acc ++ input.encode(a)) } case object OrderInput extends Input[Order] { - def encode(data: Order)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Order)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.stringify)) } case object RadiusUnitInput extends Input[RadiusUnit] { - def encode(data: RadiusUnit)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: RadiusUnit)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.stringify)) } case object RangeInput extends Input[Range] { - def encode(data: Range)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString(data.start.toString), encodeString(data.end.toString)) + def encode(data: Range)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.start.toString), RespArgument.Unknown(data.end.toString)) } case object ReplaceInput extends Input[Replace] { - def encode(data: Replace)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Replace)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object StoreDistInput extends Input[StoreDist] { - def encode(data: StoreDist)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("STOREDIST"), encodeString(data.key)) + def encode(data: StoreDist)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("STOREDIST"), RespArgument.Unknown(data.key)) } case object StoreInput extends Input[Store] { - def encode(data: Store)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("STORE"), encodeString(data.key)) + def encode(data: Store)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("STORE"), RespArgument.Unknown(data.key)) } case object StringInput extends Input[String] { - def encode(data: String)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data)) + def encode(data: String)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data)) + } + + case object CommandNameInput extends Input[String] { + def encode(data: String)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.CommandName(data)) } - final case class ArbitraryInput[A: Schema]() extends Input[A] { - def encode(data: A)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeBytes(data)) + final case class ArbitraryValueInput[A: Schema]() extends Input[A] { + def encode(data: A)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Value(data)) } - case object ByteInput extends Input[Chunk[Byte]] { - def encode(data: Chunk[Byte])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(RespValue.BulkString(data)) + final case class ArbitraryKeyInput[A: Schema]() extends Input[A] { + def encode(data: A)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Key(data)) + } + + case object ValueInput extends Input[Chunk[Byte]] { + def encode(data: Chunk[Byte])(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Value(data)) } final case class OptionalInput[-A](a: Input[A]) extends Input[Option[A]] { - def encode(data: Option[A])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - data.fold(Chunk.empty: Chunk[RespValue.BulkString])(a.encode) + def encode(data: Option[A])(implicit codec: BinaryCodec): RespCommand = + data.fold(RespCommand.empty)(a.encode) } case object TimeSecondsInput extends Input[Instant] { - def encode(data: Instant)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.getEpochSecond.toString)) + def encode(data: Instant)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.getEpochSecond.toString)) } case object TimeMillisecondsInput extends Input[Instant] { - def encode(data: Instant)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.toEpochMilli.toString)) + def encode(data: Instant)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.toEpochMilli.toString)) } case object WeightsInput extends Input[::[Double]] { - def encode(data: ::[Double])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - data.foldLeft(Chunk.single(encodeString("WEIGHTS")): Chunk[RespValue.BulkString])((acc, a) => - acc ++ Chunk.single(encodeString(a.toString)) - ) + def encode(data: ::[Double])(implicit codec: BinaryCodec): RespCommand = { + val args = data.foldLeft(Chunk.single[RespArgument](RespArgument.Literal("WEIGHTS"))) { (acc, a) => + acc ++ Chunk.single(RespArgument.Unknown(a.toString)) + } + RespCommand(args) + } } case object IdleInput extends Input[Duration] { - def encode(data: Duration)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("IDLE"), encodeString(data.toMillis.toString)) + def encode(data: Duration)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("IDLE"), RespArgument.Unknown(data.toMillis.toString)) } case object TimeInput extends Input[Duration] { - def encode(data: Duration)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("TIME"), encodeString(data.toMillis.toString)) + def encode(data: Duration)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("TIME"), RespArgument.Unknown(data.toMillis.toString)) } case object RetryCountInput extends Input[Long] { - def encode(data: Long)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("RETRYCOUNT"), encodeString(data.toString)) + def encode(data: Long)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("RETRYCOUNT"), RespArgument.Unknown(data.toString)) } final case class XGroupCreateInput[K: Schema, G: Schema, I: Schema]() extends Input[XGroupCommand.Create[K, G, I]] { - def encode(data: XGroupCommand.Create[K, G, I])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { - val chunk = Chunk(encodeString("CREATE"), encodeBytes(data.key), encodeBytes(data.group), encodeBytes(data.id)) + def encode(data: XGroupCommand.Create[K, G, I])(implicit codec: BinaryCodec): RespCommand = { + val chunk = Chunk( + RespArgument.Literal("CREATE"), + RespArgument.Key(data.key), + RespArgument.Unknown(data.group), + RespArgument.Unknown(data.id) + ) - if (data.mkStream) chunk :+ encodeString(MkStream.stringify) - else chunk + RespCommand(if (data.mkStream) chunk :+ RespArgument.Literal(MkStream.stringify) else chunk) } } final case class XGroupSetIdInput[K: Schema, G: Schema, I: Schema]() extends Input[XGroupCommand.SetId[K, G, I]] { - def encode(data: XGroupCommand.SetId[K, G, I])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("SETID"), encodeBytes(data.key), encodeBytes(data.group), encodeBytes(data.id)) + def encode(data: XGroupCommand.SetId[K, G, I])(implicit codec: BinaryCodec): RespCommand = + RespCommand( + RespArgument.Literal("SETID"), + RespArgument.Key(data.key), + RespArgument.Unknown(data.group), + RespArgument.Unknown(data.id) + ) } final case class XGroupDestroyInput[K: Schema, G: Schema]() extends Input[XGroupCommand.Destroy[K, G]] { - def encode(data: XGroupCommand.Destroy[K, G])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("DESTROY"), encodeBytes(data.key), encodeBytes(data.group)) + def encode(data: XGroupCommand.Destroy[K, G])(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("DESTROY"), RespArgument.Key(data.key), RespArgument.Unknown(data.group)) } final case class XGroupCreateConsumerInput[K: Schema, G: Schema, C: Schema]() extends Input[XGroupCommand.CreateConsumer[K, G, C]] { - def encode(data: XGroupCommand.CreateConsumer[K, G, C])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("CREATECONSUMER"), encodeBytes(data.key), encodeBytes(data.group), encodeBytes(data.consumer)) + def encode(data: XGroupCommand.CreateConsumer[K, G, C])(implicit codec: BinaryCodec): RespCommand = + RespCommand( + RespArgument.Literal("CREATECONSUMER"), + RespArgument.Key(data.key), + RespArgument.Unknown(data.group), + RespArgument.Unknown(data.consumer) + ) } final case class XGroupDelConsumerInput[K: Schema, G: Schema, C: Schema]() extends Input[XGroupCommand.DelConsumer[K, G, C]] { - def encode(data: XGroupCommand.DelConsumer[K, G, C])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("DELCONSUMER"), encodeBytes(data.key), encodeBytes(data.group), encodeBytes(data.consumer)) + def encode(data: XGroupCommand.DelConsumer[K, G, C])(implicit codec: BinaryCodec): RespCommand = + RespCommand( + RespArgument.Literal("DELCONSUMER"), + RespArgument.Key(data.key), + RespArgument.Unknown(data.group), + RespArgument.Unknown(data.consumer) + ) } case object BlockInput extends Input[Duration] { - def encode(data: Duration)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("BLOCK"), encodeString(data.toMillis.toString)) + def encode(data: Duration)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("BLOCK"), RespArgument.Unknown(data.toMillis.toString)) } final case class StreamsInput[K: Schema, V: Schema]() extends Input[((K, V), Chunk[(K, V)])] { - def encode(data: ((K, V), Chunk[(K, V)]))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { + def encode(data: ((K, V), Chunk[(K, V)]))(implicit codec: BinaryCodec): RespCommand = { val (keys, ids) = (data._1 +: data._2).map { case (key, value) => - (encodeBytes(key), encodeBytes(value)) + (RespArgument.Key(key), RespArgument.Value(value)) }.unzip - Chunk.single(encodeString("STREAMS")) ++ keys ++ ids + RespCommand(Chunk.single(RespArgument.Literal("STREAMS")) ++ keys ++ ids) } } case object NoAckInput extends Input[NoAck] { - def encode(data: NoAck)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: NoAck)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.stringify)) } case object StreamMaxLenInput extends Input[StreamMaxLen] { - def encode(data: StreamMaxLen)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { + def encode(data: StreamMaxLen)(implicit codec: BinaryCodec): RespCommand = { val chunk = - if (data.approximate) - Chunk(encodeString("MAXLEN"), encodeString("~")) - else - Chunk.single(encodeString("MAXLEN")) + if (data.approximate) Chunk(RespArgument.Literal("MAXLEN"), RespArgument.Literal("~")) + else Chunk.single(RespArgument.Literal("MAXLEN")) - chunk :+ encodeString(data.count.toString) + RespCommand(chunk :+ RespArgument.Unknown(data.count.toString)) } } case object ListMaxLenInput extends Input[ListMaxLen] { - def encode(data: ListMaxLen)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("MAXLEN"), encodeString(data.count.toString)) + def encode(data: ListMaxLen)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("MAXLEN"), RespArgument.Unknown(data.count.toString)) } case object RankInput extends Input[Rank] { - def encode(data: Rank)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("RANK"), encodeString(data.rank.toString)) + def encode(data: Rank)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("RANK"), RespArgument.Unknown(data.rank.toString)) } final case class Tuple2[-A, -B](_1: Input[A], _2: Input[B]) extends Input[(A, B)] { - def encode(data: (A, B))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) } final case class Tuple3[-A, -B, -C](_1: Input[A], _2: Input[B], _3: Input[C]) extends Input[(A, B, C)] { - def encode(data: (A, B, C))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) } final case class Tuple4[-A, -B, -C, -D](_1: Input[A], _2: Input[B], _3: Input[C], _4: Input[D]) extends Input[(A, B, C, D)] { - def encode(data: (A, B, C, D))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C, D))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) ++ _4.encode(data._4) } final case class Tuple5[-A, -B, -C, -D, -E](_1: Input[A], _2: Input[B], _3: Input[C], _4: Input[D], _5: Input[E]) extends Input[(A, B, C, D, E)] { - def encode(data: (A, B, C, D, E))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C, D, E))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) ++ _4.encode(data._4) ++ _5.encode(data._5) } @@ -460,7 +508,7 @@ object Input { _5: Input[E], _6: Input[F] ) extends Input[(A, B, C, D, E, F)] { - def encode(data: (A, B, C, D, E, F))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C, D, E, F))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) ++ _4.encode(data._4) ++ _5.encode(data._5) ++ _6.encode(data._6) } @@ -474,7 +522,7 @@ object Input { _6: Input[F], _7: Input[G] ) extends Input[(A, B, C, D, E, F, G)] { - def encode(data: (A, B, C, D, E, F, G))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C, D, E, F, G))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) ++ _4.encode(data._4) ++ _5.encode(data._5) ++ _6.encode(data._6) ++ _7.encode(data._7) } @@ -490,7 +538,7 @@ object Input { _8: Input[H], _9: Input[I] ) extends Input[(A, B, C, D, E, F, G, H, I)] { - def encode(data: (A, B, C, D, E, F, G, H, I))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C, D, E, F, G, H, I))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) ++ _4.encode(data._4) ++ _5.encode(data._5) ++ _6.encode(data._6) ++ _7.encode(data._7) ++ _8.encode(data._8) ++ _9.encode(data._9) } @@ -507,7 +555,7 @@ object Input { _9: Input[I], _10: Input[J] ) extends Input[(A, B, C, D, E, F, G, H, I, J)] { - def encode(data: (A, B, C, D, E, F, G, H, I, J))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C, D, E, F, G, H, I, J))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) ++ _4.encode(data._4) ++ _5.encode(data._5) ++ _6.encode(data._6) ++ _7.encode(data._7) ++ _8.encode(data._8) ++ _9.encode(data._9) ++ _10.encode(data._10) @@ -526,114 +574,116 @@ object Input { _10: Input[J], _11: Input[K] ) extends Input[(A, B, C, D, E, F, G, H, I, J, K)] { - def encode(data: (A, B, C, D, E, F, G, H, I, J, K))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (A, B, C, D, E, F, G, H, I, J, K))(implicit codec: BinaryCodec): RespCommand = _1.encode(data._1) ++ _2.encode(data._2) ++ _3.encode(data._3) ++ _4.encode(data._4) ++ _5.encode(data._5) ++ _6.encode(data._6) ++ _7.encode(data._7) ++ _8.encode(data._8) ++ _9.encode(data._9) ++ _10.encode(data._10) ++ _11.encode(data._11) } case object UpdateInput extends Input[Update] { - def encode(data: Update)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: Update)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.stringify)) } final case class GetExPersistInput[K: Schema]() extends Input[(K, Boolean)] { - def encode(data: (K, Boolean))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - if (data._2) Chunk(encodeBytes(data._1), encodeString("PERSIST")) else Chunk(encodeBytes(data._1)) + def encode(data: (K, Boolean))(implicit codec: BinaryCodec): RespCommand = + RespCommand( + if (data._2) Chunk(RespArgument.Key(data._1), RespArgument.Literal("PERSIST")) + else Chunk(RespArgument.Key(data._1)) + ) } + final case class GetExInput[K: Schema]() extends Input[(K, Expire, Duration)] { - def encode( - data: (K, Expire, Duration) - )(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (K, Expire, Duration))(implicit codec: BinaryCodec): RespCommand = data match { case (key, Expire.SetExpireSeconds, duration) => - Chunk(encodeBytes(key), encodeString("EX")) ++ DurationSecondsInput.encode(duration) + RespCommand(RespArgument.Key(key), RespArgument.Literal("EX")) ++ DurationSecondsInput.encode(duration) case (key, Expire.SetExpireMilliseconds, duration) => - Chunk(encodeBytes(key), encodeString("PX")) ++ DurationMillisecondsInput.encode(duration) - case _ => Chunk(encodeBytes(data._1)) + RespCommand(RespArgument.Key(key), RespArgument.Literal("PX")) ++ DurationMillisecondsInput.encode(duration) } } final case class GetExAtInput[K: Schema]() extends Input[(K, ExpiredAt, Instant)] { - def encode( - data: (K, ExpiredAt, Instant) - )(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = + def encode(data: (K, ExpiredAt, Instant))(implicit codec: BinaryCodec): RespCommand = data match { case (key, ExpiredAt.SetExpireAtSeconds, instant) => - Chunk(encodeBytes(key), encodeString("EXAT")) ++ TimeSecondsInput.encode(instant) + RespCommand(RespArgument.Key(key), RespArgument.Literal("EXAT")) ++ TimeSecondsInput.encode(instant) case (key, ExpiredAt.SetExpireAtMilliseconds, instant) => - Chunk(encodeBytes(key), encodeString("PXAT")) ++ TimeMillisecondsInput.encode(instant) - case _ => Chunk(encodeBytes(data._1)) + RespCommand(RespArgument.Key(key), RespArgument.Literal("PXAT")) ++ TimeMillisecondsInput.encode(instant) } } case object IdInput extends Input[Long] { - def encode(data: Long)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk(encodeString("ID"), encodeString(data.toString)) + def encode(data: Long)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal("ID"), RespArgument.Unknown(data.toString)) } case object UnblockBehaviorInput extends Input[UnblockBehavior] { - def encode(data: UnblockBehavior)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: UnblockBehavior)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Unknown(data.stringify)) } final case class Varargs[-A](input: Input[A]) extends Input[Iterable[A]] { - def encode(data: Iterable[A])(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - data.foldLeft(Chunk.empty: Chunk[RespValue.BulkString])((acc, a) => acc ++ input.encode(a)) + def encode(data: Iterable[A])(implicit codec: BinaryCodec): RespCommand = + data.foldLeft(RespCommand.empty)((acc, a) => acc ++ input.encode(a)) } final case class EvalInput[-K, -V](inputK: Input[K], inputV: Input[V]) extends Input[(String, Chunk[K], Chunk[V])] { - def encode(data: (String, Chunk[K], Chunk[V]))(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = { + def encode(data: (String, Chunk[K], Chunk[V]))(implicit codec: BinaryCodec): RespCommand = { val (lua, keys, args) = data - val encodedScript = Chunk(encodeString(lua), encodeString(keys.size.toString)) - val encodedKeys = keys.flatMap(inputK.encode) - val encodedArgs = args.flatMap(inputV.encode) + val encodedScript = RespCommand(RespArgument.Unknown(lua), RespArgument.Unknown(keys.size.toString)) + val encodedKeys = keys.foldLeft(RespCommand.empty)((acc, a) => + acc ++ inputK.encode(a).mapArguments(arg => RespArgument.Key(arg.value.value)) + ) + val encodedArgs = args.foldLeft(RespCommand.empty)((acc, a) => + acc ++ inputV.encode(a).mapArguments(arg => RespArgument.Value(arg.value.value)) + ) encodedScript ++ encodedKeys ++ encodedArgs } } case object ScriptDebugInput extends Input[DebugMode] { - def encode(data: DebugMode)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: DebugMode)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object ScriptFlushInput extends Input[FlushMode] { - def encode(data: FlushMode)(implicit codec: BinaryCodec): Chunk[BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: FlushMode)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object WithScoresInput extends Input[WithScores] { - def encode(data: WithScores)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: WithScores)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object WithCoordInput extends Input[WithCoord] { - def encode(data: WithCoord)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: WithCoord)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object WithDistInput extends Input[WithDist] { - def encode(data: WithDist)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: WithDist)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object WithHashInput extends Input[WithHash] { - def encode(data: WithHash)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: WithHash)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object WithForceInput extends Input[WithForce] { - def encode(data: WithForce)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: WithForce)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object WithJustIdInput extends Input[WithJustId] { - def encode(data: WithJustId)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(data.stringify)) + def encode(data: WithJustId)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(data.stringify)) } case object YesNoInput extends Input[Boolean] { - def encode(data: Boolean)(implicit codec: BinaryCodec): Chunk[RespValue.BulkString] = - Chunk.single(encodeString(if (data) "YES" else "NO")) + def encode(data: Boolean)(implicit codec: BinaryCodec): RespCommand = + RespCommand(RespArgument.Literal(if (data) "YES" else "NO")) } } diff --git a/redis/src/main/scala/zio/redis/RedisCommand.scala b/redis/src/main/scala/zio/redis/RedisCommand.scala index 05f8fc6..9385c15 100644 --- a/redis/src/main/scala/zio/redis/RedisCommand.scala +++ b/redis/src/main/scala/zio/redis/RedisCommand.scala @@ -17,7 +17,7 @@ package zio.redis import zio._ -import zio.redis.Input.{StringInput, Varargs} +import zio.redis.Input.{CommandNameInput, Varargs} import zio.schema.codec.BinaryCodec final class RedisCommand[-In, +Out] private ( @@ -34,8 +34,8 @@ final class RedisCommand[-In, +Out] private ( .flatMap[Any, Throwable, Out](out => ZIO.attempt(output.unsafeDecode(out)(codec))) .refineToOrDie[RedisError] - private[redis] def resp(in: In): Chunk[RespValue.BulkString] = - Varargs(StringInput).encode(name.split(" "))(codec) ++ input.encode(in)(codec) + private[redis] def resp(in: In): RespCommand = + Varargs(CommandNameInput).encode(name.split(" "))(codec) ++ input.encode(in)(codec) } object RedisCommand { diff --git a/redis/src/main/scala/zio/redis/RedisExecutor.scala b/redis/src/main/scala/zio/redis/RedisExecutor.scala index 8c228a1..7e041c0 100644 --- a/redis/src/main/scala/zio/redis/RedisExecutor.scala +++ b/redis/src/main/scala/zio/redis/RedisExecutor.scala @@ -16,10 +16,10 @@ package zio.redis -import zio.{Chunk, IO, ZLayer} +import zio.{IO, ZLayer} trait RedisExecutor { - def execute(command: Chunk[RespValue.BulkString]): IO[RedisError, RespValue] + def execute(command: RespCommand): IO[RedisError, RespValue] } object RedisExecutor { diff --git a/redis/src/main/scala/zio/redis/RespArgument.scala b/redis/src/main/scala/zio/redis/RespArgument.scala new file mode 100644 index 0000000..49e1686 --- /dev/null +++ b/redis/src/main/scala/zio/redis/RespArgument.scala @@ -0,0 +1,64 @@ +/* + * Copyright 2021 John A. De Goes and the ZIO contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package zio.redis + +import zio.Chunk +import zio.redis.RespValue.BulkString +import zio.schema.Schema +import zio.schema.codec.BinaryCodec + +import java.nio.charset.StandardCharsets + +sealed trait RespArgument { + def value: RespValue.BulkString +} + +object RespArgument { + + final case class Unknown(bytes: Chunk[Byte]) extends RespArgument { + lazy val value: BulkString = RespValue.BulkString(bytes) + } + + object Unknown { + def apply(str: String): Unknown = Unknown(Chunk.fromArray(str.getBytes(StandardCharsets.UTF_8))) + def apply[A](data: A)(implicit codec: BinaryCodec, schema: Schema[A]): Unknown = Unknown(codec.encode(schema)(data)) + } + + final case class CommandName(str: String) extends RespArgument { + lazy val value: BulkString = RespValue.bulkString(str) + } + + final case class Literal(str: String) extends RespArgument { + lazy val value: BulkString = RespValue.bulkString(str) + } + + final case class Key(bytes: Chunk[Byte]) extends RespArgument { + lazy val value: BulkString = RespValue.BulkString(bytes) + } + + object Key { + def apply[A](data: A)(implicit codec: BinaryCodec, schema: Schema[A]): Key = Key(codec.encode(schema)(data)) + } + + final case class Value(bytes: Chunk[Byte]) extends RespArgument { + lazy val value: BulkString = RespValue.BulkString(bytes) + } + + object Value { + def apply[A](data: A)(implicit codec: BinaryCodec, schema: Schema[A]): Value = Value(codec.encode(schema)(data)) + } +} diff --git a/redis/src/main/scala/zio/redis/RespCommand.scala b/redis/src/main/scala/zio/redis/RespCommand.scala new file mode 100644 index 0000000..94bd8d5 --- /dev/null +++ b/redis/src/main/scala/zio/redis/RespCommand.scala @@ -0,0 +1,36 @@ +/* + * Copyright 2021 John A. De Goes and the ZIO contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package zio.redis + +import zio.Chunk + +final case class RespCommand(args: Chunk[RespArgument]) { + def ++(that: RespCommand): RespCommand = RespCommand(this.args ++ that.args) + + def mapArguments(f: RespArgument => RespArgument): RespCommand = RespCommand(args.map(f(_))) +} + +object RespCommand { + + def empty: RespCommand = new RespCommand(Chunk.empty) + + def apply(args: Chunk[RespArgument]): RespCommand = new RespCommand(args) + + def apply(args: RespArgument*): RespCommand = new RespCommand(Chunk.fromIterable(args)) + + def apply(arg: RespArgument): RespCommand = new RespCommand(Chunk.single(arg)) +} diff --git a/redis/src/main/scala/zio/redis/SingleNodeExecutor.scala b/redis/src/main/scala/zio/redis/SingleNodeExecutor.scala index a1ccdcf..b227b90 100644 --- a/redis/src/main/scala/zio/redis/SingleNodeExecutor.scala +++ b/redis/src/main/scala/zio/redis/SingleNodeExecutor.scala @@ -26,10 +26,10 @@ final class SingleNodeExecutor( ) extends RedisExecutor { // TODO NodeExecutor doesn't throw connection errors, timeout errors, it is hanging forever - def execute(command: Chunk[RespValue.BulkString]): IO[RedisError, RespValue] = + def execute(command: RespCommand): IO[RedisError, RespValue] = Promise .make[RedisError, RespValue] - .flatMap(promise => reqQueue.offer(Request(command, promise)) *> promise.await) + .flatMap(promise => reqQueue.offer(Request(command.args.map(_.value), promise)) *> promise.await) /** * Opens a connection to the server and launches send and receive operations. All failures are retried by opening a diff --git a/redis/src/main/scala/zio/redis/api/Cluster.scala b/redis/src/main/scala/zio/redis/api/Cluster.scala index 88b5ec7..30bc11c 100644 --- a/redis/src/main/scala/zio/redis/api/Cluster.scala +++ b/redis/src/main/scala/zio/redis/api/Cluster.scala @@ -58,7 +58,7 @@ trait Cluster extends RedisEnvironment { */ final def setSlotStable(slot: Slot): IO[RedisError, Unit] = { val command = - RedisCommand(ClusterSetSlots, Tuple2(LongInput, ArbitraryInput[String]()), UnitOutput, codec, executor) + RedisCommand(ClusterSetSlots, Tuple2(LongInput, ArbitraryValueInput[String]()), UnitOutput, codec, executor) command.run((slot.number, Stable.stringify)) } @@ -76,7 +76,7 @@ trait Cluster extends RedisEnvironment { final def setSlotMigrating(slot: Slot, nodeId: String): IO[RedisError, Unit] = { val command = RedisCommand( ClusterSetSlots, - Tuple3(LongInput, ArbitraryInput[String](), ArbitraryInput[String]()), + Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), UnitOutput, codec, executor @@ -98,7 +98,7 @@ trait Cluster extends RedisEnvironment { final def setSlotImporting(slot: Slot, nodeId: String): IO[RedisError, Unit] = { val command = RedisCommand( ClusterSetSlots, - Tuple3(LongInput, ArbitraryInput[String](), ArbitraryInput[String]()), + Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), UnitOutput, codec, executor @@ -120,7 +120,7 @@ trait Cluster extends RedisEnvironment { final def setSlotNode(slot: Slot, nodeId: String): IO[RedisError, Unit] = { val command = RedisCommand( ClusterSetSlots, - Tuple3(LongInput, ArbitraryInput[String](), ArbitraryInput[String]()), + Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), UnitOutput, codec, executor diff --git a/redis/src/main/scala/zio/redis/api/Geo.scala b/redis/src/main/scala/zio/redis/api/Geo.scala index b4ecff6..bf3fd52 100644 --- a/redis/src/main/scala/zio/redis/api/Geo.scala +++ b/redis/src/main/scala/zio/redis/api/Geo.scala @@ -44,7 +44,7 @@ trait Geo extends RedisEnvironment { ): IO[RedisError, Long] = { val command = RedisCommand( GeoAdd, - Tuple2(ArbitraryInput[K](), NonEmptyList(Tuple2(LongLatInput, ArbitraryInput[M]()))), + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(LongLatInput, ArbitraryValueInput[M]()))), LongOutput, codec, executor @@ -74,7 +74,12 @@ trait Geo extends RedisEnvironment { ): IO[RedisError, Option[Double]] = { val command = RedisCommand( GeoDist, - Tuple4(ArbitraryInput[K](), ArbitraryInput[M](), ArbitraryInput[M](), OptionalInput(RadiusUnitInput)), + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[M](), + ArbitraryValueInput[M](), + OptionalInput(RadiusUnitInput) + ), OptionalOutput(DoubleOutput), codec, executor @@ -102,7 +107,7 @@ trait Geo extends RedisEnvironment { ): IO[RedisError, Chunk[Option[String]]] = { val command = RedisCommand( GeoHash, - Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[M]())), + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), ChunkOutput(OptionalOutput(MultiStringOutput)), codec, executor @@ -129,7 +134,13 @@ trait Geo extends RedisEnvironment { members: M* ): IO[RedisError, Chunk[Option[LongLat]]] = { val command = - RedisCommand(GeoPos, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[M]())), GeoOutput, codec, executor) + RedisCommand( + GeoPos, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + GeoOutput, + codec, + executor + ) command.run((key, (member, members.toList))) } @@ -172,7 +183,7 @@ trait Geo extends RedisEnvironment { val command = RedisCommand( GeoRadius, Tuple9( - ArbitraryInput[K](), + ArbitraryKeyInput[K](), LongLatInput, DoubleInput, RadiusUnitInput, @@ -235,7 +246,7 @@ trait Geo extends RedisEnvironment { val command = RedisCommand( GeoRadius, Tuple11( - ArbitraryInput[K](), + ArbitraryKeyInput[K](), LongLatInput, DoubleInput, RadiusUnitInput, @@ -295,8 +306,8 @@ trait Geo extends RedisEnvironment { val command = RedisCommand( GeoRadiusByMember, Tuple9( - ArbitraryInput[K](), - ArbitraryInput[M](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[M](), DoubleInput, RadiusUnitInput, OptionalInput(WithCoordInput), @@ -358,8 +369,8 @@ trait Geo extends RedisEnvironment { val command = RedisCommand( GeoRadiusByMember, Tuple11( - ArbitraryInput[K](), - ArbitraryInput[M](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[M](), DoubleInput, RadiusUnitInput, OptionalInput(WithCoordInput), diff --git a/redis/src/main/scala/zio/redis/api/Hashes.scala b/redis/src/main/scala/zio/redis/api/Hashes.scala index dcbe8f8..202376e 100644 --- a/redis/src/main/scala/zio/redis/api/Hashes.scala +++ b/redis/src/main/scala/zio/redis/api/Hashes.scala @@ -40,7 +40,13 @@ trait Hashes extends RedisEnvironment { */ final def hDel[K: Schema, F: Schema](key: K, field: F, fields: F*): IO[RedisError, Long] = { val command = - RedisCommand(HDel, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[F]())), LongOutput, codec, executor) + RedisCommand( + HDel, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[F]())), + LongOutput, + codec, + executor + ) command.run((key, (field, fields.toList))) } @@ -55,7 +61,8 @@ trait Hashes extends RedisEnvironment { * true if the field exists, otherwise false. */ final def hExists[K: Schema, F: Schema](key: K, field: F): IO[RedisError, Boolean] = { - val command = RedisCommand(HExists, Tuple2(ArbitraryInput[K](), ArbitraryInput[F]()), BoolOutput, codec, executor) + val command = + RedisCommand(HExists, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), BoolOutput, codec, executor) command.run((key, field)) } @@ -74,7 +81,7 @@ trait Hashes extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[V]] = RedisCommand( HGet, - Tuple2(ArbitraryInput[K](), ArbitraryInput[F]()), + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), OptionalOutput(ArbitraryOutput[V]()), codec, executor @@ -95,7 +102,7 @@ trait Hashes extends RedisEnvironment { val command = RedisCommand( HGetAll, - ArbitraryInput[K](), + ArbitraryKeyInput[K](), KeyValueOutput(ArbitraryOutput[F](), ArbitraryOutput[V]()), codec, executor @@ -119,7 +126,13 @@ trait Hashes extends RedisEnvironment { */ final def hIncrBy[K: Schema, F: Schema](key: K, field: F, increment: Long): IO[RedisError, Long] = { val command = - RedisCommand(HIncrBy, Tuple3(ArbitraryInput[K](), ArbitraryInput[F](), LongInput), LongOutput, codec, executor) + RedisCommand( + HIncrBy, + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), LongInput), + LongOutput, + codec, + executor + ) command.run((key, field, increment)) } @@ -144,7 +157,7 @@ trait Hashes extends RedisEnvironment { val command = RedisCommand( HIncrByFloat, - Tuple3(ArbitraryInput[K](), ArbitraryInput[F](), DoubleInput), + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), DoubleInput), DoubleOutput, codec, executor @@ -163,7 +176,7 @@ trait Hashes extends RedisEnvironment { final def hKeys[K: Schema](key: K): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { def returning[F: Schema]: IO[RedisError, Chunk[F]] = - RedisCommand(HKeys, ArbitraryInput[K](), ChunkOutput(ArbitraryOutput[F]()), codec, executor).run(key) + RedisCommand(HKeys, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[F]()), codec, executor).run(key) } /** @@ -175,7 +188,7 @@ trait Hashes extends RedisEnvironment { * number of fields. */ final def hLen[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(HLen, ArbitraryInput[K](), LongOutput, codec, executor) + val command = RedisCommand(HLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) command.run(key) } @@ -200,7 +213,7 @@ trait Hashes extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Chunk[Option[V]]] = { val command = RedisCommand( HmGet, - Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[F]())), + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[F]())), ChunkOutput(OptionalOutput(ArbitraryOutput[V]())), codec, executor @@ -229,7 +242,7 @@ trait Hashes extends RedisEnvironment { ): IO[RedisError, Unit] = { val command = RedisCommand( HmSet, - Tuple2(ArbitraryInput[K](), NonEmptyList(Tuple2(ArbitraryInput[F](), ArbitraryInput[V]()))), + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(ArbitraryValueInput[F](), ArbitraryValueInput[V]()))), UnitOutput, codec, executor @@ -261,7 +274,7 @@ trait Hashes extends RedisEnvironment { def returning[F: Schema, V: Schema]: IO[RedisError, (Long, Chunk[(F, V)])] = { val command = RedisCommand( HScan, - Tuple4(ArbitraryInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), + Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), Tuple2Output(ArbitraryOutput[Long](), ChunkTuple2Output(ArbitraryOutput[F](), ArbitraryOutput[V]())), codec, executor @@ -289,7 +302,7 @@ trait Hashes extends RedisEnvironment { ): IO[RedisError, Long] = { val command = RedisCommand( HSet, - Tuple2(ArbitraryInput[K](), NonEmptyList(Tuple2(ArbitraryInput[F](), ArbitraryInput[V]()))), + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(ArbitraryValueInput[F](), ArbitraryValueInput[V]()))), LongOutput, codec, executor @@ -317,7 +330,7 @@ trait Hashes extends RedisEnvironment { val command = RedisCommand( HSetNx, - Tuple3(ArbitraryInput[K](), ArbitraryInput[F](), ArbitraryInput[V]()), + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), ArbitraryValueInput[V]()), BoolOutput, codec, executor @@ -336,7 +349,8 @@ trait Hashes extends RedisEnvironment { * string length of the value in field, or zero if either field or key do not exist. */ final def hStrLen[K: Schema, F: Schema](key: K, field: F): IO[RedisError, Long] = { - val command = RedisCommand(HStrLen, Tuple2(ArbitraryInput[K](), ArbitraryInput[F]()), LongOutput, codec, executor) + val command = + RedisCommand(HStrLen, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), LongOutput, codec, executor) command.run((key, field)) } @@ -351,7 +365,7 @@ trait Hashes extends RedisEnvironment { final def hVals[K: Schema](key: K): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { def returning[V: Schema]: IO[RedisError, Chunk[V]] = - RedisCommand(HVals, ArbitraryInput[K](), ChunkOutput(ArbitraryOutput[V]()), codec, executor).run(key) + RedisCommand(HVals, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[V]()), codec, executor).run(key) } /** @@ -365,7 +379,7 @@ trait Hashes extends RedisEnvironment { final def hRandField[K: Schema](key: K): ResultBuilder1[Option] = new ResultBuilder1[Option] { def returning[V: Schema]: IO[RedisError, Option[V]] = - RedisCommand(HRandField, ArbitraryInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) + RedisCommand(HRandField, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) } /** @@ -387,7 +401,7 @@ trait Hashes extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Chunk[V]] = { val command = RedisCommand( HRandField, - Tuple3(ArbitraryInput[K](), LongInput, OptionalInput(StringInput)), + Tuple3(ArbitraryKeyInput[K](), LongInput, OptionalInput(StringInput)), ChunkOutput(ArbitraryOutput[V]()), codec, executor diff --git a/redis/src/main/scala/zio/redis/api/HyperLogLog.scala b/redis/src/main/scala/zio/redis/api/HyperLogLog.scala index 5b97b12..928973a 100644 --- a/redis/src/main/scala/zio/redis/api/HyperLogLog.scala +++ b/redis/src/main/scala/zio/redis/api/HyperLogLog.scala @@ -39,7 +39,13 @@ trait HyperLogLog extends RedisEnvironment { */ final def pfAdd[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Boolean] = { val command = - RedisCommand(PfAdd, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[V]())), BoolOutput, codec, executor) + RedisCommand( + PfAdd, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + BoolOutput, + codec, + executor + ) command.run((key, (element, elements.toList))) } @@ -54,7 +60,7 @@ trait HyperLogLog extends RedisEnvironment { * approximate number of unique elements observed via PFADD. */ final def pfCount[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(PfCount, NonEmptyList(ArbitraryInput[K]()), LongOutput, codec, executor) + val command = RedisCommand(PfCount, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) command.run((key, keys.toList)) } @@ -70,7 +76,13 @@ trait HyperLogLog extends RedisEnvironment { */ final def pfMerge[K: Schema](destKey: K, sourceKey: K, sourceKeys: K*): IO[RedisError, Unit] = { val command = - RedisCommand(PfMerge, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[K]())), UnitOutput, codec, executor) + RedisCommand( + PfMerge, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryKeyInput[K]())), + UnitOutput, + codec, + executor + ) command.run((destKey, (sourceKey, sourceKeys.toList))) } } diff --git a/redis/src/main/scala/zio/redis/api/Keys.scala b/redis/src/main/scala/zio/redis/api/Keys.scala index 9e098fb..bc20959 100644 --- a/redis/src/main/scala/zio/redis/api/Keys.scala +++ b/redis/src/main/scala/zio/redis/api/Keys.scala @@ -42,7 +42,7 @@ trait Keys extends RedisEnvironment { * [[unlink]] */ final def del[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Del, NonEmptyList(ArbitraryInput[K]()), LongOutput, codec, executor) + val command = RedisCommand(Del, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) command.run((key, keys.toList)) } @@ -55,7 +55,7 @@ trait Keys extends RedisEnvironment { * bytes for value stored at key. */ final def dump[K: Schema](key: K): IO[RedisError, Chunk[Byte]] = { - val command = RedisCommand(Dump, ArbitraryInput[K](), BulkStringOutput, codec, executor) + val command = RedisCommand(Dump, ArbitraryKeyInput[K](), BulkStringOutput, codec, executor) command.run(key) } @@ -71,7 +71,7 @@ trait Keys extends RedisEnvironment { * The number of keys existing. */ final def exists[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Exists, NonEmptyList(ArbitraryInput[K]()), LongOutput, codec, executor) + val command = RedisCommand(Exists, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) command.run((key, keys.toList)) } @@ -89,7 +89,8 @@ trait Keys extends RedisEnvironment { * [[expireAt]] */ final def expire[K: Schema](key: K, timeout: Duration): IO[RedisError, Boolean] = { - val command = RedisCommand(Expire, Tuple2(ArbitraryInput[K](), DurationSecondsInput), BoolOutput, codec, executor) + val command = + RedisCommand(Expire, Tuple2(ArbitraryKeyInput[K](), DurationSecondsInput), BoolOutput, codec, executor) command.run((key, timeout)) } @@ -107,7 +108,7 @@ trait Keys extends RedisEnvironment { * [[expire]] */ final def expireAt[K: Schema](key: K, timestamp: Instant): IO[RedisError, Boolean] = { - val command = RedisCommand(ExpireAt, Tuple2(ArbitraryInput[K](), TimeSecondsInput), BoolOutput, codec, executor) + val command = RedisCommand(ExpireAt, Tuple2(ArbitraryKeyInput[K](), TimeSecondsInput), BoolOutput, codec, executor) command.run((key, timestamp)) } @@ -166,13 +167,13 @@ trait Keys extends RedisEnvironment { Tuple9( StringInput, LongInput, - ArbitraryInput[K](), + ArbitraryKeyInput[K](), LongInput, LongInput, OptionalInput(CopyInput), OptionalInput(ReplaceInput), OptionalInput(AuthInput), - OptionalInput(NonEmptyList(ArbitraryInput[K]())) + OptionalInput(NonEmptyList(ArbitraryKeyInput[K]())) ), StringOutput, codec, @@ -193,7 +194,7 @@ trait Keys extends RedisEnvironment { * true if the key was moved. */ final def move[K: Schema](key: K, destinationDb: Long): IO[RedisError, Boolean] = { - val command = RedisCommand(Move, Tuple2(ArbitraryInput[K](), LongInput), BoolOutput, codec, executor) + val command = RedisCommand(Move, Tuple2(ArbitraryKeyInput[K](), LongInput), BoolOutput, codec, executor) command.run((key, destinationDb)) } @@ -206,7 +207,7 @@ trait Keys extends RedisEnvironment { * true if timeout was removed, false if key does not exist or does not have an associated timeout. */ final def persist[K: Schema](key: K): IO[RedisError, Boolean] = { - val command = RedisCommand(Persist, ArbitraryInput[K](), BoolOutput, codec, executor) + val command = RedisCommand(Persist, ArbitraryKeyInput[K](), BoolOutput, codec, executor) command.run(key) } @@ -225,7 +226,7 @@ trait Keys extends RedisEnvironment { */ final def pExpire[K: Schema](key: K, timeout: Duration): IO[RedisError, Boolean] = { val command = - RedisCommand(PExpire, Tuple2(ArbitraryInput[K](), DurationMillisecondsInput), BoolOutput, codec, executor) + RedisCommand(PExpire, Tuple2(ArbitraryKeyInput[K](), DurationMillisecondsInput), BoolOutput, codec, executor) command.run((key, timeout)) } @@ -244,7 +245,7 @@ trait Keys extends RedisEnvironment { */ final def pExpireAt[K: Schema](key: K, timestamp: Instant): IO[RedisError, Boolean] = { val command = - RedisCommand(PExpireAt, Tuple2(ArbitraryInput[K](), TimeMillisecondsInput), BoolOutput, codec, executor) + RedisCommand(PExpireAt, Tuple2(ArbitraryKeyInput[K](), TimeMillisecondsInput), BoolOutput, codec, executor) command.run((key, timestamp)) } @@ -257,7 +258,7 @@ trait Keys extends RedisEnvironment { * remaining time to live of a key that has a timeout, error otherwise. */ final def pTtl[K: Schema](key: K): IO[RedisError, Duration] = { - val command = RedisCommand(PTtl, ArbitraryInput[K](), DurationMillisecondsOutput, codec, executor) + val command = RedisCommand(PTtl, ArbitraryKeyInput[K](), DurationMillisecondsOutput, codec, executor) command.run(key) } @@ -284,7 +285,8 @@ trait Keys extends RedisEnvironment { * unit if successful, error otherwise. */ final def rename[K: Schema](key: K, newKey: K): IO[RedisError, Unit] = { - val command = RedisCommand(Rename, Tuple2(ArbitraryInput[K](), ArbitraryInput[K]()), UnitOutput, codec, executor) + val command = + RedisCommand(Rename, Tuple2(ArbitraryKeyInput[K](), ArbitraryKeyInput[K]()), UnitOutput, codec, executor) command.run((key, newKey)) } @@ -299,7 +301,8 @@ trait Keys extends RedisEnvironment { * true if key was renamed to newKey, false if newKey already exists. */ final def renameNx[K: Schema](key: K, newKey: K): IO[RedisError, Boolean] = { - val command = RedisCommand(RenameNx, Tuple2(ArbitraryInput[K](), ArbitraryInput[K]()), BoolOutput, codec, executor) + val command = + RedisCommand(RenameNx, Tuple2(ArbitraryKeyInput[K](), ArbitraryKeyInput[K]()), BoolOutput, codec, executor) command.run((key, newKey)) } @@ -337,9 +340,9 @@ trait Keys extends RedisEnvironment { val command = RedisCommand( Restore, Tuple7( - ArbitraryInput[K](), + ArbitraryKeyInput[K](), LongInput, - ByteInput, + ValueInput, OptionalInput(ReplaceInput), OptionalInput(AbsTtlInput), OptionalInput(IdleTimeInput), @@ -418,7 +421,7 @@ trait Keys extends RedisEnvironment { val command = RedisCommand( Sort, Tuple6( - ArbitraryInput[K](), + ArbitraryKeyInput[K](), OptionalInput(ByInput), OptionalInput(LimitInput), OptionalInput(NonEmptyList(GetInput)), @@ -469,7 +472,7 @@ trait Keys extends RedisEnvironment { val command = RedisCommand( SortStore, Tuple7( - ArbitraryInput[K](), + ArbitraryKeyInput[K](), OptionalInput(ByInput), OptionalInput(LimitInput), OptionalInput(NonEmptyList(GetInput)), @@ -495,7 +498,7 @@ trait Keys extends RedisEnvironment { * The number of keys that were touched. */ final def touch[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Touch, NonEmptyList(ArbitraryInput[K]()), LongOutput, codec, executor) + val command = RedisCommand(Touch, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) command.run((key, keys.toList)) } @@ -508,7 +511,7 @@ trait Keys extends RedisEnvironment { * remaining time to live of a key that has a timeout, error otherwise. */ final def ttl[K: Schema](key: K): IO[RedisError, Duration] = { - val command = RedisCommand(Ttl, ArbitraryInput[K](), DurationSecondsOutput, codec, executor) + val command = RedisCommand(Ttl, ArbitraryKeyInput[K](), DurationSecondsOutput, codec, executor) command.run(key) } @@ -521,7 +524,7 @@ trait Keys extends RedisEnvironment { * type of the value stored at key. */ final def typeOf[K: Schema](key: K): IO[RedisError, RedisType] = { - val command = RedisCommand(TypeOf, ArbitraryInput[K](), TypeOutput, codec, executor) + val command = RedisCommand(TypeOf, ArbitraryKeyInput[K](), TypeOutput, codec, executor) command.run(key) } @@ -540,7 +543,7 @@ trait Keys extends RedisEnvironment { * [[del]] */ final def unlink[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Unlink, NonEmptyList(ArbitraryInput[K]()), LongOutput, codec, executor) + val command = RedisCommand(Unlink, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) command.run((key, keys.toList)) } diff --git a/redis/src/main/scala/zio/redis/api/Lists.scala b/redis/src/main/scala/zio/redis/api/Lists.scala index e12b6b4..ab9421e 100644 --- a/redis/src/main/scala/zio/redis/api/Lists.scala +++ b/redis/src/main/scala/zio/redis/api/Lists.scala @@ -49,7 +49,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[V]] = { val command = RedisCommand( BrPopLPush, - Tuple3(ArbitraryInput[S](), ArbitraryInput[D](), DurationSecondsInput), + Tuple3(ArbitraryValueInput[S](), ArbitraryValueInput[D](), DurationSecondsInput), OptionalOutput(ArbitraryOutput[V]()), codec, executor @@ -75,7 +75,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[V]] = RedisCommand( LIndex, - Tuple2(ArbitraryInput[K](), LongInput), + Tuple2(ArbitraryKeyInput[K](), LongInput), OptionalOutput(ArbitraryOutput[V]()), codec, executor @@ -92,7 +92,7 @@ trait Lists extends RedisEnvironment { * the length of the list at key. */ final def lLen[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(LLen, ArbitraryInput[K](), LongOutput, codec, executor) + val command = RedisCommand(LLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) command.run(key) } @@ -107,7 +107,7 @@ trait Lists extends RedisEnvironment { final def lPop[K: Schema](key: K): ResultBuilder1[Option] = new ResultBuilder1[Option] { def returning[V: Schema]: IO[RedisError, Option[V]] = - RedisCommand(LPop, ArbitraryInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) + RedisCommand(LPop, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) } /** @@ -125,7 +125,13 @@ trait Lists extends RedisEnvironment { */ final def lPush[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { val command = - RedisCommand(LPush, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[V]())), LongOutput, codec, executor) + RedisCommand( + LPush, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) command.run((key, (element, elements.toList))) } @@ -144,7 +150,13 @@ trait Lists extends RedisEnvironment { */ final def lPushX[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { val command = - RedisCommand(LPushX, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[V]())), LongOutput, codec, executor) + RedisCommand( + LPushX, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) command.run((key, (element, elements.toList))) } @@ -164,7 +176,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Chunk[V]] = RedisCommand( LRange, - Tuple2(ArbitraryInput[K](), RangeInput), + Tuple2(ArbitraryKeyInput[K](), RangeInput), ChunkOutput(ArbitraryOutput[V]()), codec, executor @@ -190,7 +202,8 @@ trait Lists extends RedisEnvironment { * the number of removed elements. */ final def lRem[K: Schema](key: K, count: Long, element: String): IO[RedisError, Long] = { - val command = RedisCommand(LRem, Tuple3(ArbitraryInput[K](), LongInput, StringInput), LongOutput, codec, executor) + val command = + RedisCommand(LRem, Tuple3(ArbitraryKeyInput[K](), LongInput, StringInput), LongOutput, codec, executor) command.run((key, count, element)) } @@ -208,7 +221,13 @@ trait Lists extends RedisEnvironment { */ final def lSet[K: Schema, V: Schema](key: K, index: Long, element: V): IO[RedisError, Unit] = { val command = - RedisCommand(LSet, Tuple3(ArbitraryInput[K](), LongInput, ArbitraryInput[V]()), UnitOutput, codec, executor) + RedisCommand( + LSet, + Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[V]()), + UnitOutput, + codec, + executor + ) command.run((key, index, element)) } @@ -224,7 +243,7 @@ trait Lists extends RedisEnvironment { * the Unit value. */ final def lTrim[K: Schema](key: K, range: Range): IO[RedisError, Unit] = { - val command = RedisCommand(LTrim, Tuple2(ArbitraryInput[K](), RangeInput), UnitOutput, codec, executor) + val command = RedisCommand(LTrim, Tuple2(ArbitraryKeyInput[K](), RangeInput), UnitOutput, codec, executor) command.run((key, range)) } @@ -239,7 +258,7 @@ trait Lists extends RedisEnvironment { final def rPop[K: Schema](key: K): ResultBuilder1[Option] = new ResultBuilder1[Option] { def returning[V: Schema]: IO[RedisError, Option[V]] = - RedisCommand(RPop, ArbitraryInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) + RedisCommand(RPop, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) } /** @@ -259,7 +278,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[V]] = RedisCommand( RPopLPush, - Tuple2(ArbitraryInput[S](), ArbitraryInput[D]()), + Tuple2(ArbitraryValueInput[S](), ArbitraryValueInput[D]()), OptionalOutput(ArbitraryOutput[V]()), codec, executor @@ -282,7 +301,13 @@ trait Lists extends RedisEnvironment { */ final def rPush[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { val command = - RedisCommand(RPush, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[V]())), LongOutput, codec, executor) + RedisCommand( + RPush, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) command.run((key, (element, elements.toList))) } @@ -301,7 +326,13 @@ trait Lists extends RedisEnvironment { */ final def rPushX[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { val command = - RedisCommand(RPushX, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[V]())), LongOutput, codec, executor) + RedisCommand( + RPushX, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) command.run((key, (element, elements.toList))) } @@ -327,7 +358,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[(K, V)]] = { val command = RedisCommand( BlPop, - Tuple2(NonEmptyList(ArbitraryInput[K]()), DurationSecondsInput), + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), OptionalOutput(Tuple2Output(ArbitraryOutput[K](), ArbitraryOutput[V]())), codec, executor @@ -358,7 +389,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[(K, V)]] = { val command = RedisCommand( BrPop, - Tuple2(NonEmptyList(ArbitraryInput[K]()), DurationSecondsInput), + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), OptionalOutput(Tuple2Output(ArbitraryOutput[K](), ArbitraryOutput[V]())), codec, executor @@ -389,7 +420,7 @@ trait Lists extends RedisEnvironment { ): IO[RedisError, Long] = { val command = RedisCommand( LInsert, - Tuple4(ArbitraryInput[K](), PositionInput, ArbitraryInput[V](), ArbitraryInput[V]()), + Tuple4(ArbitraryKeyInput[K](), PositionInput, ArbitraryValueInput[V](), ArbitraryValueInput[V]()), LongOutput, codec, executor @@ -423,7 +454,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[V]] = { val command = RedisCommand( LMove, - Tuple4(ArbitraryInput[S](), ArbitraryInput[D](), SideInput, SideInput), + Tuple4(ArbitraryValueInput[S](), ArbitraryValueInput[D](), SideInput, SideInput), OptionalOutput(ArbitraryOutput[V]()), codec, executor @@ -462,7 +493,7 @@ trait Lists extends RedisEnvironment { def returning[V: Schema]: IO[RedisError, Option[V]] = { val command = RedisCommand( BlMove, - Tuple5(ArbitraryInput[S](), ArbitraryInput[D](), SideInput, SideInput, DurationSecondsInput), + Tuple5(ArbitraryValueInput[S](), ArbitraryValueInput[D](), SideInput, SideInput, DurationSecondsInput), OptionalOutput(ArbitraryOutput[V]()), codec, executor @@ -497,8 +528,8 @@ trait Lists extends RedisEnvironment { val command = RedisCommand( LPos, Tuple4( - ArbitraryInput[K](), - ArbitraryInput[V](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[V](), OptionalInput(RankInput), OptionalInput(ListMaxLenInput) ), @@ -538,8 +569,8 @@ trait Lists extends RedisEnvironment { val command = RedisCommand( LPos, Tuple5( - ArbitraryInput[K](), - ArbitraryInput[V](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[V](), CountInput, OptionalInput(RankInput), OptionalInput(ListMaxLenInput) diff --git a/redis/src/main/scala/zio/redis/api/Sets.scala b/redis/src/main/scala/zio/redis/api/Sets.scala index 09147ce..83b7269 100644 --- a/redis/src/main/scala/zio/redis/api/Sets.scala +++ b/redis/src/main/scala/zio/redis/api/Sets.scala @@ -41,7 +41,13 @@ trait Sets extends RedisEnvironment { */ final def sAdd[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Long] = { val command = - RedisCommand(SAdd, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[M]())), LongOutput, codec, executor) + RedisCommand( + SAdd, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + LongOutput, + codec, + executor + ) command.run((key, (member, members.toList))) } @@ -54,7 +60,7 @@ trait Sets extends RedisEnvironment { * Returns the cardinality (number of elements) of the set, or 0 if key does not exist. */ final def sCard[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(SCard, ArbitraryInput[K](), LongOutput, codec, executor) + val command = RedisCommand(SCard, ArbitraryKeyInput[K](), LongOutput, codec, executor) command.run(key) } @@ -71,7 +77,7 @@ trait Sets extends RedisEnvironment { final def sDiff[K: Schema](key: K, keys: K*): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { def returning[R: Schema]: IO[RedisError, Chunk[R]] = - RedisCommand(SDiff, NonEmptyList(ArbitraryInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) + RedisCommand(SDiff, NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) .run((key, keys.toList)) } @@ -90,7 +96,7 @@ trait Sets extends RedisEnvironment { final def sDiffStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): IO[RedisError, Long] = { val command = RedisCommand( SDiffStore, - Tuple2(ArbitraryInput[D](), NonEmptyList(ArbitraryInput[K]())), + Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), LongOutput, codec, executor @@ -111,7 +117,7 @@ trait Sets extends RedisEnvironment { final def sInter[K: Schema](destination: K, keys: K*): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { def returning[R: Schema]: IO[RedisError, Chunk[R]] = - RedisCommand(SInter, NonEmptyList(ArbitraryInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) + RedisCommand(SInter, NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) .run((destination, keys.toList)) } @@ -134,7 +140,7 @@ trait Sets extends RedisEnvironment { ): IO[RedisError, Long] = { val command = RedisCommand( SInterStore, - Tuple2(ArbitraryInput[D](), NonEmptyList(ArbitraryInput[K]())), + Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), LongOutput, codec, executor @@ -154,7 +160,8 @@ trait Sets extends RedisEnvironment { * exist. */ final def sIsMember[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Boolean] = { - val command = RedisCommand(SIsMember, Tuple2(ArbitraryInput[K](), ArbitraryInput[M]()), BoolOutput, codec, executor) + val command = + RedisCommand(SIsMember, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), BoolOutput, codec, executor) command.run((key, member)) } @@ -169,7 +176,7 @@ trait Sets extends RedisEnvironment { final def sMembers[K: Schema](key: K): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { def returning[R: Schema]: IO[RedisError, Chunk[R]] = - RedisCommand(SMembers, ArbitraryInput[K](), ChunkOutput(ArbitraryOutput[R]()), codec, executor).run(key) + RedisCommand(SMembers, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[R]()), codec, executor).run(key) } /** @@ -191,7 +198,7 @@ trait Sets extends RedisEnvironment { ): IO[RedisError, Boolean] = { val command = RedisCommand( SMove, - Tuple3(ArbitraryInput[S](), ArbitraryInput[D](), ArbitraryInput[M]()), + Tuple3(ArbitraryValueInput[S](), ArbitraryValueInput[D](), ArbitraryValueInput[M]()), BoolOutput, codec, executor @@ -214,7 +221,7 @@ trait Sets extends RedisEnvironment { def returning[R: Schema]: IO[RedisError, Chunk[R]] = { val command = RedisCommand( SPop, - Tuple2(ArbitraryInput[K](), OptionalInput(LongInput)), + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), MultiStringChunkOutput(ArbitraryOutput[R]()), codec, executor @@ -238,7 +245,7 @@ trait Sets extends RedisEnvironment { def returning[R: Schema]: IO[RedisError, Chunk[R]] = { val command = RedisCommand( SRandMember, - Tuple2(ArbitraryInput[K](), OptionalInput(LongInput)), + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), MultiStringChunkOutput(ArbitraryOutput[R]()), codec, executor @@ -261,7 +268,13 @@ trait Sets extends RedisEnvironment { */ final def sRem[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Long] = { val command = - RedisCommand(SRem, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[M]())), LongOutput, codec, executor) + RedisCommand( + SRem, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + LongOutput, + codec, + executor + ) command.run((key, (member, members.toList))) } @@ -292,7 +305,7 @@ trait Sets extends RedisEnvironment { def returning[R: Schema]: IO[RedisError, (Long, Chunk[R])] = { val command = RedisCommand( SScan, - Tuple4(ArbitraryInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), + Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), Tuple2Output(MultiStringOutput.map(_.toLong), ChunkOutput(ArbitraryOutput[R]())), codec, executor @@ -314,7 +327,7 @@ trait Sets extends RedisEnvironment { final def sUnion[K: Schema](key: K, keys: K*): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { def returning[R: Schema]: IO[RedisError, Chunk[R]] = - RedisCommand(SUnion, NonEmptyList(ArbitraryInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) + RedisCommand(SUnion, NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) .run((key, keys.toList)) } @@ -337,7 +350,7 @@ trait Sets extends RedisEnvironment { ): IO[RedisError, Long] = { val command = RedisCommand( SUnionStore, - Tuple2(ArbitraryInput[D](), NonEmptyList(ArbitraryInput[K]())), + Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), LongOutput, codec, executor diff --git a/redis/src/main/scala/zio/redis/api/SortedSets.scala b/redis/src/main/scala/zio/redis/api/SortedSets.scala index 5755a18..dd8b2b4 100644 --- a/redis/src/main/scala/zio/redis/api/SortedSets.scala +++ b/redis/src/main/scala/zio/redis/api/SortedSets.scala @@ -53,7 +53,7 @@ trait SortedSets extends RedisEnvironment { } val command = RedisCommand( BzPopMax, - Tuple2(NonEmptyList(ArbitraryInput[K]()), DurationSecondsInput), + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), OptionalOutput(memberScoreOutput), codec, executor @@ -89,7 +89,7 @@ trait SortedSets extends RedisEnvironment { } val command = RedisCommand( BzPopMin, - Tuple2(NonEmptyList(ArbitraryInput[K]()), DurationSecondsInput), + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), OptionalOutput(memberScoreOutput), codec, executor @@ -122,7 +122,7 @@ trait SortedSets extends RedisEnvironment { val command = RedisCommand( ZAdd, Tuple4( - ArbitraryInput[K](), + ArbitraryKeyInput[K](), OptionalInput(UpdateInput), OptionalInput(ChangedInput), NonEmptyList(MemberScoreInput[M]()) @@ -161,7 +161,7 @@ trait SortedSets extends RedisEnvironment { val command = RedisCommand( ZAdd, Tuple5( - ArbitraryInput[K](), + ArbitraryKeyInput[K](), OptionalInput(UpdateInput), OptionalInput(ChangedInput), IncrementInput, @@ -183,7 +183,7 @@ trait SortedSets extends RedisEnvironment { * The cardinality (number of elements) of the sorted set, or 0 if key does not exist. */ final def zCard[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(ZCard, ArbitraryInput[K](), LongOutput, codec, executor) + val command = RedisCommand(ZCard, ArbitraryKeyInput[K](), LongOutput, codec, executor) command.run(key) } @@ -198,7 +198,7 @@ trait SortedSets extends RedisEnvironment { * the number of elements in the specified score range. */ final def zCount[K: Schema](key: K, range: Range): IO[RedisError, Long] = { - val command = RedisCommand(ZCount, Tuple2(ArbitraryInput[K](), RangeInput), LongOutput, codec, executor) + val command = RedisCommand(ZCount, Tuple2(ArbitraryKeyInput[K](), RangeInput), LongOutput, codec, executor) command.run((key, range)) } @@ -226,7 +226,7 @@ trait SortedSets extends RedisEnvironment { ZDiff, Tuple2( LongInput, - NonEmptyList(ArbitraryInput[K]()) + NonEmptyList(ArbitraryKeyInput[K]()) ), ChunkOutput(ArbitraryOutput[M]()), codec, @@ -260,8 +260,8 @@ trait SortedSets extends RedisEnvironment { ZDiff, Tuple3( LongInput, - NonEmptyList(ArbitraryInput[K]()), - ArbitraryInput[String]() + NonEmptyList(ArbitraryKeyInput[K]()), + ArbitraryValueInput[String]() ), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), @@ -296,9 +296,9 @@ trait SortedSets extends RedisEnvironment { RedisCommand( ZDiffStore, Tuple3( - ArbitraryInput[DK](), + ArbitraryValueInput[DK](), LongInput, - NonEmptyList(ArbitraryInput[K]()) + NonEmptyList(ArbitraryKeyInput[K]()) ), LongOutput, codec, @@ -325,7 +325,13 @@ trait SortedSets extends RedisEnvironment { member: M ): IO[RedisError, Double] = { val command = - RedisCommand(ZIncrBy, Tuple3(ArbitraryInput[K](), LongInput, ArbitraryInput[M]()), DoubleOutput, codec, executor) + RedisCommand( + ZIncrBy, + Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[M]()), + DoubleOutput, + codec, + executor + ) command.run((key, increment, member)) } @@ -357,7 +363,7 @@ trait SortedSets extends RedisEnvironment { ZInter, Tuple4( LongInput, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), OptionalInput(AggregateInput), OptionalInput(WeightsInput) ), @@ -397,10 +403,10 @@ trait SortedSets extends RedisEnvironment { ZInter, Tuple5( LongInput, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), OptionalInput(AggregateInput), OptionalInput(WeightsInput), - ArbitraryInput[String]() + ArbitraryValueInput[String]() ), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), @@ -438,9 +444,9 @@ trait SortedSets extends RedisEnvironment { val command = RedisCommand( ZInterStore, Tuple5( - ArbitraryInput[DK](), + ArbitraryValueInput[DK](), LongInput, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), OptionalInput(AggregateInput), OptionalInput(WeightsInput) ), @@ -464,7 +470,7 @@ trait SortedSets extends RedisEnvironment { final def zLexCount[K: Schema](key: K, lexRange: LexRange): IO[RedisError, Long] = { val command = RedisCommand( ZLexCount, - Tuple3(ArbitraryInput[K](), ArbitraryInput[String](), ArbitraryInput[String]()), + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), LongOutput, codec, executor @@ -492,7 +498,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { val command = RedisCommand( ZPopMax, - Tuple2(ArbitraryInput[K](), OptionalInput(LongInput)), + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), codec, @@ -522,7 +528,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { val command = RedisCommand( ZPopMin, - Tuple2(ArbitraryInput[K](), OptionalInput(LongInput)), + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), codec, @@ -547,7 +553,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[M]] = { val command = RedisCommand( ZRange, - Tuple2(ArbitraryInput[K](), RangeInput), + Tuple2(ArbitraryKeyInput[K](), RangeInput), ChunkOutput(ArbitraryOutput[M]()), codec, executor @@ -574,7 +580,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { val command = RedisCommand( ZRange, - Tuple3(ArbitraryInput[K](), RangeInput, ArbitraryInput[String]()), + Tuple3(ArbitraryKeyInput[K](), RangeInput, ArbitraryValueInput[String]()), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), codec, @@ -606,7 +612,12 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[M]] = { val command = RedisCommand( ZRangeByLex, - Tuple4(ArbitraryInput[K](), ArbitraryInput[String](), ArbitraryInput[String](), OptionalInput(LimitInput)), + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), ChunkOutput(ArbitraryOutput[M]()), codec, executor @@ -637,7 +648,12 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[M]] = { val command = RedisCommand( ZRangeByScore, - Tuple4(ArbitraryInput[K](), ArbitraryInput[String](), ArbitraryInput[String](), OptionalInput(LimitInput)), + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), ChunkOutput(ArbitraryOutput[M]()), codec, executor @@ -669,10 +685,10 @@ trait SortedSets extends RedisEnvironment { val command = RedisCommand( ZRangeByScore, Tuple5( - ArbitraryInput[K](), - ArbitraryInput[String](), - ArbitraryInput[String](), - ArbitraryInput[String](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), OptionalInput(LimitInput) ), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) @@ -696,7 +712,13 @@ trait SortedSets extends RedisEnvironment { */ final def zRank[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Long]] = { val command = - RedisCommand(ZRank, Tuple2(ArbitraryInput[K](), ArbitraryInput[M]()), OptionalOutput(LongOutput), codec, executor) + RedisCommand( + ZRank, + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), + OptionalOutput(LongOutput), + codec, + executor + ) command.run((key, member)) } @@ -718,7 +740,13 @@ trait SortedSets extends RedisEnvironment { restMembers: M* ): IO[RedisError, Long] = { val command = - RedisCommand(ZRem, Tuple2(ArbitraryInput[K](), NonEmptyList(ArbitraryInput[M]())), LongOutput, codec, executor) + RedisCommand( + ZRem, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + LongOutput, + codec, + executor + ) command.run((key, (firstMember, restMembers.toList))) } @@ -735,7 +763,7 @@ trait SortedSets extends RedisEnvironment { final def zRemRangeByLex[K: Schema](key: K, lexRange: LexRange): IO[RedisError, Long] = { val command = RedisCommand( ZRemRangeByLex, - Tuple3(ArbitraryInput[K](), ArbitraryInput[String](), ArbitraryInput[String]()), + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), LongOutput, codec, executor @@ -754,7 +782,7 @@ trait SortedSets extends RedisEnvironment { * The number of elements removed. */ final def zRemRangeByRank[K: Schema](key: K, range: Range): IO[RedisError, Long] = { - val command = RedisCommand(ZRemRangeByRank, Tuple2(ArbitraryInput[K](), RangeInput), LongOutput, codec, executor) + val command = RedisCommand(ZRemRangeByRank, Tuple2(ArbitraryKeyInput[K](), RangeInput), LongOutput, codec, executor) command.run((key, range)) } @@ -771,7 +799,7 @@ trait SortedSets extends RedisEnvironment { final def zRemRangeByScore[K: Schema](key: K, scoreRange: ScoreRange): IO[RedisError, Long] = { val command = RedisCommand( ZRemRangeByScore, - Tuple3(ArbitraryInput[K](), ArbitraryInput[String](), ArbitraryInput[String]()), + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), LongOutput, codec, executor @@ -794,7 +822,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[M]] = { val command = RedisCommand( ZRevRange, - Tuple2(ArbitraryInput[K](), RangeInput), + Tuple2(ArbitraryKeyInput[K](), RangeInput), ChunkOutput(ArbitraryOutput[M]()), codec, executor @@ -821,7 +849,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { val command = RedisCommand( ZRevRange, - Tuple3(ArbitraryInput[K](), RangeInput, ArbitraryInput[String]()), + Tuple3(ArbitraryKeyInput[K](), RangeInput, ArbitraryValueInput[String]()), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), codec, @@ -853,7 +881,12 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[M]] = { val command = RedisCommand( ZRevRangeByLex, - Tuple4(ArbitraryInput[K](), ArbitraryInput[String](), ArbitraryInput[String](), OptionalInput(LimitInput)), + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), ChunkOutput(ArbitraryOutput[M]()), codec, executor @@ -885,9 +918,9 @@ trait SortedSets extends RedisEnvironment { val command = RedisCommand( ZRevRangeByScore, Tuple4( - ArbitraryInput[K](), - ArbitraryInput[String](), - ArbitraryInput[String](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), OptionalInput(LimitInput) ), ChunkOutput(ArbitraryOutput[M]()), @@ -921,10 +954,10 @@ trait SortedSets extends RedisEnvironment { val command = RedisCommand( ZRevRangeByScore, Tuple5( - ArbitraryInput[K](), - ArbitraryInput[String](), - ArbitraryInput[String](), - ArbitraryInput[String](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), OptionalInput(LimitInput) ), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) @@ -949,7 +982,7 @@ trait SortedSets extends RedisEnvironment { final def zRevRank[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Long]] = { val command = RedisCommand( ZRevRank, - Tuple2(ArbitraryInput[K](), ArbitraryInput[M]()), + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), OptionalOutput(LongOutput), codec, executor @@ -983,7 +1016,7 @@ trait SortedSets extends RedisEnvironment { ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput).map(_.map { case (m, s) => MemberScore(s, m) }) val command = RedisCommand( ZScan, - Tuple4(ArbitraryInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), + Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), Tuple2Output(MultiStringOutput.map(_.toLong), memberScoresOutput), codec, executor @@ -1005,7 +1038,7 @@ trait SortedSets extends RedisEnvironment { final def zScore[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Double]] = { val command = RedisCommand( ZScore, - Tuple2(ArbitraryInput[K](), ArbitraryInput[M]()), + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), OptionalOutput(DoubleOutput), codec, executor @@ -1042,7 +1075,7 @@ trait SortedSets extends RedisEnvironment { ZUnion, Tuple4( LongInput, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), OptionalInput(WeightsInput), OptionalInput(AggregateInput) ), @@ -1083,10 +1116,10 @@ trait SortedSets extends RedisEnvironment { ZUnion, Tuple5( LongInput, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), OptionalInput(WeightsInput), OptionalInput(AggregateInput), - ArbitraryInput[String]() + ArbitraryValueInput[String]() ), ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), @@ -1124,9 +1157,9 @@ trait SortedSets extends RedisEnvironment { val command = RedisCommand( ZUnionStore, Tuple5( - ArbitraryInput[DK](), + ArbitraryValueInput[DK](), LongInput, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), OptionalInput(WeightsInput), OptionalInput(AggregateInput) ), @@ -1150,7 +1183,7 @@ trait SortedSets extends RedisEnvironment { final def zMScore[K: Schema](key: K, keys: K*): IO[RedisError, Chunk[Option[Double]]] = { val command = RedisCommand( ZMScore, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(OptionalOutput(DoubleOutput)), codec, executor @@ -1169,7 +1202,8 @@ trait SortedSets extends RedisEnvironment { final def zRandMember[K: Schema](key: K): ResultBuilder1[Option] = new ResultBuilder1[Option] { def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand(ZRandMember, ArbitraryInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor).run(key) + RedisCommand(ZRandMember, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) + .run(key) } /** @@ -1191,7 +1225,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[M]] = { val command = RedisCommand( ZRandMember, - Tuple2(ArbitraryInput[K](), LongInput), + Tuple2(ArbitraryKeyInput[K](), LongInput), ZRandMemberOutput(ArbitraryOutput[M]()), codec, executor @@ -1221,7 +1255,7 @@ trait SortedSets extends RedisEnvironment { def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { val command = RedisCommand( ZRandMember, - Tuple3(ArbitraryInput[K](), LongInput, ArbitraryInput[String]()), + Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[String]()), ZRandMemberTuple2Output(ArbitraryOutput[M](), DoubleOutput) .map(_.map { case (m, s) => MemberScore(s, m) }), codec, diff --git a/redis/src/main/scala/zio/redis/api/Streams.scala b/redis/src/main/scala/zio/redis/api/Streams.scala index 281f1b4..f9ec152 100644 --- a/redis/src/main/scala/zio/redis/api/Streams.scala +++ b/redis/src/main/scala/zio/redis/api/Streams.scala @@ -50,7 +50,7 @@ trait Streams extends RedisEnvironment { ): IO[RedisError, Long] = { val command = RedisCommand( XAck, - Tuple3(ArbitraryInput[SK](), ArbitraryInput[G](), NonEmptyList(ArbitraryInput[I]())), + Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[G](), NonEmptyList(ArbitraryValueInput[I]())), LongOutput, codec, executor @@ -83,10 +83,10 @@ trait Streams extends RedisEnvironment { val command = RedisCommand( XAdd, Tuple4( - ArbitraryInput[SK](), + ArbitraryKeyInput[SK](), OptionalInput(StreamMaxLenInput), - ArbitraryInput[I](), - NonEmptyList(Tuple2(ArbitraryInput[K](), ArbitraryInput[V]())) + ArbitraryValueInput[I](), + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())) ), ArbitraryOutput[R](), codec, @@ -108,7 +108,7 @@ trait Streams extends RedisEnvironment { key: SK ): ResultBuilder3[StreamInfo] = new ResultBuilder3[StreamInfo] { def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, StreamInfo[RI, RK, RV]] = { - val command = RedisCommand(XInfoStream, ArbitraryInput[SK](), StreamInfoOutput[RI, RK, RV](), codec, executor) + val command = RedisCommand(XInfoStream, ArbitraryKeyInput[SK](), StreamInfoOutput[RI, RK, RV](), codec, executor) command.run(key) } } @@ -127,7 +127,7 @@ trait Streams extends RedisEnvironment { def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, FullStreamInfo[RI, RK, RV]] = { val command = RedisCommand( XInfoStream, - Tuple2(ArbitraryInput[SK](), ArbitraryInput[String]()), + Tuple2(ArbitraryKeyInput[SK](), ArbitraryValueInput[String]()), StreamInfoFullOutput[RI, RK, RV](), codec, executor @@ -153,7 +153,7 @@ trait Streams extends RedisEnvironment { def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, FullStreamInfo[RI, RK, RV]] = { val command = RedisCommand( XInfoStream, - Tuple3(ArbitraryInput[SK](), ArbitraryInput[String](), CountInput), + Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[String](), CountInput), StreamInfoFullOutput[RI, RK, RV](), codec, executor @@ -171,7 +171,7 @@ trait Streams extends RedisEnvironment { * List of consumer groups associated with the stream stored at the specified key. */ final def xInfoGroups[SK: Schema](key: SK): IO[RedisError, Chunk[StreamGroupsInfo]] = { - val command = RedisCommand(XInfoGroups, ArbitraryInput[SK](), StreamGroupsInfoOutput, codec, executor) + val command = RedisCommand(XInfoGroups, ArbitraryKeyInput[SK](), StreamGroupsInfoOutput, codec, executor) command.run(key) } @@ -192,7 +192,7 @@ trait Streams extends RedisEnvironment { val command = RedisCommand( XInfoConsumers, - Tuple2(ArbitraryInput[SK](), ArbitraryInput[SG]()), + Tuple2(ArbitraryKeyInput[SK](), ArbitraryValueInput[SG]()), StreamConsumersInfoOutput, codec, executor @@ -232,10 +232,10 @@ trait Streams extends RedisEnvironment { val command = RedisCommand( XAdd, Tuple4( - ArbitraryInput[SK](), + ArbitraryKeyInput[SK](), OptionalInput(StreamMaxLenInput), - ArbitraryInput[I](), - NonEmptyList(Tuple2(ArbitraryInput[K](), ArbitraryInput[V]())) + ArbitraryValueInput[I](), + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())) ), ArbitraryOutput[R](), codec, @@ -287,11 +287,11 @@ trait Streams extends RedisEnvironment { val command = RedisCommand( XClaim, Tuple9( - ArbitraryInput[SK](), - ArbitraryInput[SG](), - ArbitraryInput[SC](), + ArbitraryKeyInput[SK](), + ArbitraryValueInput[SG](), + ArbitraryValueInput[SC](), DurationMillisecondsInput, - NonEmptyList(ArbitraryInput[I]()), + NonEmptyList(ArbitraryValueInput[I]()), OptionalInput(IdleInput), OptionalInput(TimeInput), OptionalInput(RetryCountInput), @@ -348,11 +348,11 @@ trait Streams extends RedisEnvironment { val command = RedisCommand( XClaim, Tuple10( - ArbitraryInput[SK](), - ArbitraryInput[SG](), - ArbitraryInput[SC](), + ArbitraryKeyInput[SK](), + ArbitraryValueInput[SG](), + ArbitraryValueInput[SC](), DurationMillisecondsInput, - NonEmptyList(ArbitraryInput[I]()), + NonEmptyList(ArbitraryValueInput[I]()), OptionalInput(IdleInput), OptionalInput(TimeInput), OptionalInput(RetryCountInput), @@ -382,7 +382,13 @@ trait Streams extends RedisEnvironment { */ final def xDel[SK: Schema, I: Schema](key: SK, id: I, ids: I*): IO[RedisError, Long] = { val command = - RedisCommand(XDel, Tuple2(ArbitraryInput[SK](), NonEmptyList(ArbitraryInput[I]())), LongOutput, codec, executor) + RedisCommand( + XDel, + Tuple2(ArbitraryKeyInput[SK](), NonEmptyList(ArbitraryValueInput[I]())), + LongOutput, + codec, + executor + ) command.run((key, (id, ids.toList))) } @@ -491,7 +497,7 @@ trait Streams extends RedisEnvironment { * the number of entries inside a stream. */ final def xLen[SK: Schema](key: SK): IO[RedisError, Long] = { - val command = RedisCommand(XLen, ArbitraryInput[SK](), LongOutput, codec, executor) + val command = RedisCommand(XLen, ArbitraryKeyInput[SK](), LongOutput, codec, executor) command.run(key) } @@ -508,7 +514,7 @@ trait Streams extends RedisEnvironment { final def xPending[SK: Schema, SG: Schema](key: SK, group: SG): IO[RedisError, PendingInfo] = { val command = RedisCommand( XPending, - Tuple3(ArbitraryInput[SK](), ArbitraryInput[SG](), OptionalInput(IdleInput)), + Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[SG](), OptionalInput(IdleInput)), XPendingOutput, codec, executor @@ -548,13 +554,13 @@ trait Streams extends RedisEnvironment { val command = RedisCommand( XPending, Tuple7( - ArbitraryInput[SK](), - ArbitraryInput[SG](), + ArbitraryKeyInput[SK](), + ArbitraryValueInput[SG](), OptionalInput(IdleInput), - ArbitraryInput[I](), - ArbitraryInput[I](), + ArbitraryValueInput[I](), + ArbitraryValueInput[I](), LongInput, - OptionalInput(ArbitraryInput[SC]()) + OptionalInput(ArbitraryValueInput[SC]()) ), PendingMessagesOutput, codec, @@ -584,7 +590,12 @@ trait Streams extends RedisEnvironment { def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { val command = RedisCommand( XRange, - Tuple4(ArbitraryInput[SK](), ArbitraryInput[I](), ArbitraryInput[I](), OptionalInput(CountInput)), + Tuple4( + ArbitraryKeyInput[SK](), + ArbitraryValueInput[I](), + ArbitraryValueInput[I](), + OptionalInput(CountInput) + ), StreamEntriesOutput[I, RK, RV](), codec, executor @@ -617,7 +628,12 @@ trait Streams extends RedisEnvironment { def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { val command = RedisCommand( XRange, - Tuple4(ArbitraryInput[SK](), ArbitraryInput[I](), ArbitraryInput[I](), OptionalInput(CountInput)), + Tuple4( + ArbitraryKeyInput[SK](), + ArbitraryValueInput[I](), + ArbitraryValueInput[I](), + OptionalInput(CountInput) + ), StreamEntriesOutput[I, RK, RV](), codec, executor @@ -695,8 +711,8 @@ trait Streams extends RedisEnvironment { val command = RedisCommand( XReadGroup, Tuple6( - ArbitraryInput[SG](), - ArbitraryInput[SC](), + ArbitraryValueInput[SG](), + ArbitraryValueInput[SC](), OptionalInput(CountInput), OptionalInput(BlockInput), OptionalInput(NoAckInput), @@ -732,7 +748,12 @@ trait Streams extends RedisEnvironment { def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { val command = RedisCommand( XRevRange, - Tuple4(ArbitraryInput[SK](), ArbitraryInput[I](), ArbitraryInput[I](), OptionalInput(CountInput)), + Tuple4( + ArbitraryKeyInput[SK](), + ArbitraryValueInput[I](), + ArbitraryValueInput[I](), + OptionalInput(CountInput) + ), StreamEntriesOutput[I, RK, RV](), codec, executor @@ -765,7 +786,12 @@ trait Streams extends RedisEnvironment { def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { val command = RedisCommand( XRevRange, - Tuple4(ArbitraryInput[SK](), ArbitraryInput[I](), ArbitraryInput[I](), OptionalInput(CountInput)), + Tuple4( + ArbitraryKeyInput[SK](), + ArbitraryValueInput[I](), + ArbitraryValueInput[I](), + OptionalInput(CountInput) + ), StreamEntriesOutput[I, RK, RV](), codec, executor @@ -791,7 +817,7 @@ trait Streams extends RedisEnvironment { count: Long, approximate: Boolean = false ): IO[RedisError, Long] = { - val command = RedisCommand(XTrim, Tuple2(ArbitraryInput[SK](), StreamMaxLenInput), LongOutput, codec, executor) + val command = RedisCommand(XTrim, Tuple2(ArbitraryKeyInput[SK](), StreamMaxLenInput), LongOutput, codec, executor) command.run((key, StreamMaxLen(approximate, count))) } } diff --git a/redis/src/main/scala/zio/redis/api/Strings.scala b/redis/src/main/scala/zio/redis/api/Strings.scala index ec20c3a..7976f1a 100644 --- a/redis/src/main/scala/zio/redis/api/Strings.scala +++ b/redis/src/main/scala/zio/redis/api/Strings.scala @@ -39,7 +39,8 @@ trait Strings extends RedisEnvironment { * Returns the length of the string after the append operation. */ final def append[K: Schema, V: Schema](key: K, value: V): IO[RedisError, Long] = { - val command = RedisCommand(Append, Tuple2(ArbitraryInput[K](), ArbitraryInput[V]()), LongOutput, codec, executor) + val command = + RedisCommand(Append, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), LongOutput, codec, executor) command.run((key, value)) } @@ -55,7 +56,7 @@ trait Strings extends RedisEnvironment { */ final def bitCount[K: Schema](key: K, range: Option[Range] = None): IO[RedisError, Long] = { val command = - RedisCommand(BitCount, Tuple2(ArbitraryInput[K](), OptionalInput(RangeInput)), LongOutput, codec, executor) + RedisCommand(BitCount, Tuple2(ArbitraryKeyInput[K](), OptionalInput(RangeInput)), LongOutput, codec, executor) command.run((key, range)) } @@ -78,7 +79,7 @@ trait Strings extends RedisEnvironment { ): IO[RedisError, Chunk[Option[Long]]] = { val command = RedisCommand( BitField, - Tuple2(ArbitraryInput[K](), NonEmptyList(BitFieldCommandInput)), + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(BitFieldCommandInput)), ChunkOutput(OptionalOutput(LongOutput)), codec, executor @@ -109,7 +110,7 @@ trait Strings extends RedisEnvironment { val command = RedisCommand( BitOp, - Tuple3(BitOperationInput, ArbitraryInput[D](), NonEmptyList(ArbitraryInput[S]())), + Tuple3(BitOperationInput, ArbitraryValueInput[D](), NonEmptyList(ArbitraryValueInput[S]())), LongOutput, codec, executor @@ -137,7 +138,7 @@ trait Strings extends RedisEnvironment { val command = RedisCommand( BitPos, - Tuple3(ArbitraryInput[K](), BoolInput, OptionalInput(BitPosRangeInput)), + Tuple3(ArbitraryKeyInput[K](), BoolInput, OptionalInput(BitPosRangeInput)), LongOutput, codec, executor @@ -154,7 +155,7 @@ trait Strings extends RedisEnvironment { * Returns the value of key after the decrement. */ final def decr[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(Decr, ArbitraryInput[K](), LongOutput, codec, executor) + val command = RedisCommand(Decr, ArbitraryKeyInput[K](), LongOutput, codec, executor) command.run(key) } @@ -169,7 +170,7 @@ trait Strings extends RedisEnvironment { * Returns the value of key after the decrement. */ final def decrBy[K: Schema](key: K, decrement: Long): IO[RedisError, Long] = { - val command = RedisCommand(DecrBy, Tuple2(ArbitraryInput[K](), LongInput), LongOutput, codec, executor) + val command = RedisCommand(DecrBy, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) command.run((key, decrement)) } @@ -184,7 +185,7 @@ trait Strings extends RedisEnvironment { final def get[K: Schema](key: K): ResultBuilder1[Option] = new ResultBuilder1[Option] { def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand(Get, ArbitraryInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor).run(key) + RedisCommand(Get, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor).run(key) } /** @@ -198,7 +199,7 @@ trait Strings extends RedisEnvironment { * Returns the bit value stored at offset. */ final def getBit[K: Schema](key: K, offset: Long): IO[RedisError, Long] = { - val command = RedisCommand(GetBit, Tuple2(ArbitraryInput[K](), LongInput), LongOutput, codec, executor) + val command = RedisCommand(GetBit, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) command.run((key, offset)) } @@ -217,7 +218,7 @@ trait Strings extends RedisEnvironment { def returning[R: Schema]: IO[RedisError, Option[R]] = RedisCommand( GetRange, - Tuple2(ArbitraryInput[K](), RangeInput), + Tuple2(ArbitraryKeyInput[K](), RangeInput), OptionalOutput(ArbitraryOutput[R]()), codec, executor @@ -240,7 +241,7 @@ trait Strings extends RedisEnvironment { def returning[R: Schema]: IO[RedisError, Option[R]] = RedisCommand( GetSet, - Tuple2(ArbitraryInput[K](), ArbitraryInput[V]()), + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), OptionalOutput(ArbitraryOutput[R]()), codec, executor @@ -259,7 +260,7 @@ trait Strings extends RedisEnvironment { final def getDel[K: Schema](key: K): ResultBuilder1[Option] = new ResultBuilder1[Option] { def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand(GetDel, ArbitraryInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor).run(key) + RedisCommand(GetDel, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor).run(key) } /** @@ -328,7 +329,7 @@ trait Strings extends RedisEnvironment { * Returns the value of key after the increment. */ final def incr[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(Incr, ArbitraryInput[K](), LongOutput, codec, executor) + val command = RedisCommand(Incr, ArbitraryKeyInput[K](), LongOutput, codec, executor) command.run(key) } @@ -344,7 +345,7 @@ trait Strings extends RedisEnvironment { */ final def incrBy[K: Schema](key: K, increment: Long): IO[RedisError, Long] = { val command = - RedisCommand(IncrBy, Tuple2(ArbitraryInput[K](), LongInput), LongOutput, codec, executor) + RedisCommand(IncrBy, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) command.run((key, increment)) } @@ -359,7 +360,7 @@ trait Strings extends RedisEnvironment { * Returns the value of key after the increment. */ final def incrByFloat[K: Schema](key: K, increment: Double): IO[RedisError, Double] = { - val command = RedisCommand(IncrByFloat, Tuple2(ArbitraryInput[K](), DoubleInput), DoubleOutput, codec, executor) + val command = RedisCommand(IncrByFloat, Tuple2(ArbitraryKeyInput[K](), DoubleInput), DoubleOutput, codec, executor) command.run((key, increment)) } @@ -382,7 +383,7 @@ trait Strings extends RedisEnvironment { val command = RedisCommand( MGet, - NonEmptyList(ArbitraryInput[K]()), + NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(OptionalOutput(ArbitraryOutput[V]())), codec, executor @@ -401,7 +402,13 @@ trait Strings extends RedisEnvironment { */ final def mSet[K: Schema, V: Schema](keyValue: (K, V), keyValues: (K, V)*): IO[RedisError, Unit] = { val command = - RedisCommand(MSet, NonEmptyList(Tuple2(ArbitraryInput[K](), ArbitraryInput[V]())), UnitOutput, codec, executor) + RedisCommand( + MSet, + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())), + UnitOutput, + codec, + executor + ) command.run((keyValue, keyValues.toList)) } @@ -420,7 +427,13 @@ trait Strings extends RedisEnvironment { keyValues: (K, V)* ): IO[RedisError, Boolean] = { val command = - RedisCommand(MSetNx, NonEmptyList(Tuple2(ArbitraryInput[K](), ArbitraryInput[V]())), BoolOutput, codec, executor) + RedisCommand( + MSetNx, + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())), + BoolOutput, + codec, + executor + ) command.run((keyValue, keyValues.toList)) } @@ -442,7 +455,7 @@ trait Strings extends RedisEnvironment { val command = RedisCommand( PSetEx, - Tuple3(ArbitraryInput[K](), DurationMillisecondsInput, ArbitraryInput[V]()), + Tuple3(ArbitraryKeyInput[K](), DurationMillisecondsInput, ArbitraryValueInput[V]()), UnitOutput, codec, executor @@ -475,8 +488,8 @@ trait Strings extends RedisEnvironment { keepTtl: Option[KeepTtl] = None ): IO[RedisError, Boolean] = { val input = Tuple5( - ArbitraryInput[K](), - ArbitraryInput[V](), + ArbitraryKeyInput[K](), + ArbitraryValueInput[V](), OptionalInput(DurationTtlInput), OptionalInput(UpdateInput), OptionalInput(KeepTtlInput) @@ -498,7 +511,8 @@ trait Strings extends RedisEnvironment { * Returns the original bit value stored at offset. */ final def setBit[K: Schema](key: K, offset: Long, value: Boolean): IO[RedisError, Boolean] = { - val command = RedisCommand(SetBit, Tuple3(ArbitraryInput[K](), LongInput, BoolInput), BoolOutput, codec, executor) + val command = + RedisCommand(SetBit, Tuple3(ArbitraryKeyInput[K](), LongInput, BoolInput), BoolOutput, codec, executor) command.run((key, offset, value)) } @@ -520,7 +534,7 @@ trait Strings extends RedisEnvironment { val command = RedisCommand( SetEx, - Tuple3(ArbitraryInput[K](), DurationSecondsInput, ArbitraryInput[V]()), + Tuple3(ArbitraryKeyInput[K](), DurationSecondsInput, ArbitraryValueInput[V]()), UnitOutput, codec, executor @@ -539,7 +553,8 @@ trait Strings extends RedisEnvironment { * Returns 1 if the key was set. 0 if the key was not set. */ final def setNx[K: Schema, V: Schema](key: K, value: V): IO[RedisError, Boolean] = { - val command = RedisCommand(SetNx, Tuple2(ArbitraryInput[K](), ArbitraryInput[V]()), BoolOutput, codec, executor) + val command = + RedisCommand(SetNx, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), BoolOutput, codec, executor) command.run((key, value)) } @@ -557,7 +572,13 @@ trait Strings extends RedisEnvironment { */ final def setRange[K: Schema, V: Schema](key: K, offset: Long, value: V): IO[RedisError, Long] = { val command = - RedisCommand(SetRange, Tuple3(ArbitraryInput[K](), LongInput, ArbitraryInput[V]()), LongOutput, codec, executor) + RedisCommand( + SetRange, + Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[V]()), + LongOutput, + codec, + executor + ) command.run((key, offset, value)) } @@ -570,7 +591,7 @@ trait Strings extends RedisEnvironment { * Returns the length of the string. */ final def strLen[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(StrLen, ArbitraryInput[K](), LongOutput, codec, executor) + val command = RedisCommand(StrLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) command.run(key) } @@ -600,9 +621,9 @@ trait Strings extends RedisEnvironment { val redisCommand = RedisCommand( StrAlgoLcs, Tuple4( - ArbitraryInput[String](), - ArbitraryInput[K](), - ArbitraryInput[K](), + ArbitraryValueInput[String](), + ArbitraryKeyInput[K](), + ArbitraryKeyInput[K](), OptionalInput(StralgoLcsQueryTypeInput) ), StrAlgoLcsOutput, diff --git a/redis/src/test/scala/zio/redis/InputSpec.scala b/redis/src/test/scala/zio/redis/InputSpec.scala index 8396494..f89b704 100644 --- a/redis/src/test/scala/zio/redis/InputSpec.scala +++ b/redis/src/test/scala/zio/redis/InputSpec.scala @@ -2,6 +2,7 @@ package zio.redis import zio._ import zio.redis.Input._ +import zio.redis.RespArgument._ import zio.test.Assertion._ import zio.test._ @@ -22,7 +23,7 @@ object InputSpec extends BaseSpec { test("valid value") { for { result <- ZIO.attempt(AbsTtlInput.encode(AbsTtl)) - } yield assert(result)(equalTo(respArgs("ABSTTL"))) + } yield assert(result)(equalTo(RespCommand(Literal("ABSTTL")))) } ), suite("Address")( @@ -31,81 +32,81 @@ object InputSpec extends BaseSpec { ip <- ZIO.succeed(InetAddress.getByName("127.0.0.1")) port <- ZIO.succeed(42) result <- ZIO.attempt(AddressInput.encode(Address(ip, port))) - } yield assert(result)(equalTo(respArgs("127.0.0.1:42"))) + } yield assert(result)(equalTo(RespCommand(Unknown("127.0.0.1:42")))) } ), suite("Aggregate")( test("max") { for { result <- ZIO.attempt(AggregateInput.encode(Aggregate.Max)) - } yield assert(result)(equalTo(respArgs("AGGREGATE", "MAX"))) + } yield assert(result)(equalTo(RespCommand(Literal("AGGREGATE"), Literal("MAX")))) }, test("min") { for { result <- ZIO.attempt(AggregateInput.encode(Aggregate.Min)) - } yield assert(result)(equalTo(respArgs("AGGREGATE", "MIN"))) + } yield assert(result)(equalTo(RespCommand(Literal("AGGREGATE"), Literal("MIN")))) }, test("sum") { for { result <- ZIO.attempt(AggregateInput.encode(Aggregate.Sum)) - } yield assert(result)(equalTo(respArgs("AGGREGATE", "SUM"))) + } yield assert(result)(equalTo(RespCommand(Literal("AGGREGATE"), Literal("SUM")))) } ), suite("Alpha")( test("alpha") { for { result <- ZIO.attempt(AlphaInput.encode(Alpha)) - } yield assert(result)(equalTo(respArgs("ALPHA"))) + } yield assert(result)(equalTo(RespCommand(Literal("ALPHA")))) } ), suite("Auth")( test("with empty password") { for { result <- ZIO.attempt(AuthInput.encode(Auth(""))) - } yield assert(result)(equalTo(respArgs("AUTH", ""))) + } yield assert(result)(equalTo(RespCommand(Literal("AUTH"), Value("")))) }, test("with non-empty password") { for { result <- ZIO.attempt(AuthInput.encode(Auth("pass"))) - } yield assert(result)(equalTo(respArgs("AUTH", "pass"))) + } yield assert(result)(equalTo(RespCommand(Literal("AUTH"), Value("pass")))) } ), suite("Bool")( test("true") { for { result <- ZIO.attempt(BoolInput.encode(true)) - } yield assert(result)(equalTo(respArgs("1"))) + } yield assert(result)(equalTo(RespCommand(Literal("1")))) }, test("false") { for { result <- ZIO.attempt(BoolInput.encode(false)) - } yield assert(result)(equalTo(respArgs("0"))) + } yield assert(result)(equalTo(RespCommand(Literal("0")))) } ), suite("Stralgocommand")( test("length option") { assert(StralgoLcsQueryTypeInput.encode(StrAlgoLcsQueryType.Len))( - equalTo(respArgs("LEN")) + equalTo(RespCommand(Literal("LEN"))) ) }, test("idx option default") { assert(StralgoLcsQueryTypeInput.encode(Idx()))( - equalTo(respArgs("IDX")) + equalTo(RespCommand(Literal("IDX"))) ) }, test("idx option with minmatchlength") { assert(StralgoLcsQueryTypeInput.encode(Idx(minMatchLength = 2)))( - equalTo(respArgs("IDX", "MINMATCHLEN", "2")) + equalTo(RespCommand(Literal("IDX"), Literal("MINMATCHLEN"), Unknown("2"))) ) }, test("idx option with withmatchlength") { assert(StralgoLcsQueryTypeInput.encode(Idx(withMatchLength = true)))( - equalTo(respArgs("IDX", "WITHMATCHLEN")) + equalTo(RespCommand(Literal("IDX"), Literal("WITHMATCHLEN"))) ) }, test("idx option with minmatchlength and withmatchlength") { assert(StralgoLcsQueryTypeInput.encode(Idx(minMatchLength = 2, withMatchLength = true)))( - equalTo(respArgs("IDX", "MINMATCHLEN", "2", "WITHMATCHLEN")) + equalTo(RespCommand(Literal("IDX"), Literal("MINMATCHLEN"), Unknown("2"), Literal("WITHMATCHLEN"))) ) } ), @@ -113,110 +114,110 @@ object InputSpec extends BaseSpec { test("get with unsigned type and positive offset") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldGet(UnsignedInt(3), 2))) - } yield assert(result)(equalTo(respArgs("GET", "u3", "2"))) + } yield assert(result)(equalTo(RespCommand(Literal("GET"), Unknown("u3"), Unknown("2")))) }, test("get with signed type and negative offset") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldGet(SignedInt(3), -2))) - } yield assert(result)(equalTo(respArgs("GET", "i3", "-2"))) + } yield assert(result)(equalTo(RespCommand(Literal("GET"), Unknown("i3"), Unknown("-2")))) }, test("get with unsigned type and zero offset") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldGet(UnsignedInt(3), 0))) - } yield assert(result)(equalTo(respArgs("GET", "u3", "0"))) + } yield assert(result)(equalTo(RespCommand(Literal("GET"), Unknown("u3"), Unknown("0")))) }, test("set with unsigned type, positive offset and positive value") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldSet(UnsignedInt(3), 2, 100L))) - } yield assert(result)(equalTo(respArgs("SET", "u3", "2", "100"))) + } yield assert(result)(equalTo(RespCommand(Literal("SET"), Unknown("u3"), Unknown("2"), Unknown("100")))) }, test("set with signed type, negative offset and negative value") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldSet(SignedInt(3), -2, -100L))) - } yield assert(result)(equalTo(respArgs("SET", "i3", "-2", "-100"))) + } yield assert(result)(equalTo(RespCommand(Literal("SET"), Unknown("i3"), Unknown("-2"), Unknown("-100")))) }, test("set with unsigned type, zero offset and zero value") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldSet(UnsignedInt(3), 0, 0L))) - } yield assert(result)(equalTo(respArgs("SET", "u3", "0", "0"))) + } yield assert(result)(equalTo(RespCommand(Literal("SET"), Unknown("u3"), Unknown("0"), Unknown("0")))) }, test("incr with unsigned type, positive offset and positive value") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldIncr(UnsignedInt(3), 2, 100L))) - } yield assert(result)(equalTo(respArgs("INCRBY", "u3", "2", "100"))) + } yield assert(result)(equalTo(RespCommand(Literal("INCRBY"), Unknown("u3"), Unknown("2"), Unknown("100")))) }, test("incr with signed type, negative offset and negative value") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldIncr(SignedInt(3), -2, -100L))) - } yield assert(result)(equalTo(respArgs("INCRBY", "i3", "-2", "-100"))) + } yield assert(result)(equalTo(RespCommand(Literal("INCRBY"), Unknown("i3"), Unknown("-2"), Unknown("-100")))) }, test("incr with unsigned type, zero offset and zero value") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldIncr(UnsignedInt(3), 0, 0L))) - } yield assert(result)(equalTo(respArgs("INCRBY", "u3", "0", "0"))) + } yield assert(result)(equalTo(RespCommand(Literal("INCRBY"), Unknown("u3"), Unknown("0"), Unknown("0")))) }, test("overflow sat") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldOverflow.Sat)) - } yield assert(result)(equalTo(respArgs("OVERFLOW", "SAT"))) + } yield assert(result)(equalTo(RespCommand(Literal("OVERFLOW"), Literal("SAT")))) }, test("overflow fail") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldOverflow.Fail)) - } yield assert(result)(equalTo(respArgs("OVERFLOW", "FAIL"))) + } yield assert(result)(equalTo(RespCommand(Literal("OVERFLOW"), Literal("FAIL")))) }, test("overflow warp") { for { result <- ZIO.attempt(BitFieldCommandInput.encode(BitFieldOverflow.Wrap)) - } yield assert(result)(equalTo(respArgs("OVERFLOW", "WRAP"))) + } yield assert(result)(equalTo(RespCommand(Literal("OVERFLOW"), Literal("WRAP")))) } ), suite("BitOperation")( test("and") { for { result <- ZIO.attempt(BitOperationInput.encode(AND)) - } yield assert(result)(equalTo(respArgs("AND"))) + } yield assert(result)(equalTo(RespCommand(Literal("AND")))) }, test("or") { for { result <- ZIO.attempt(BitOperationInput.encode(OR)) - } yield assert(result)(equalTo(respArgs("OR"))) + } yield assert(result)(equalTo(RespCommand(Literal("OR")))) }, test("xor") { for { result <- ZIO.attempt(BitOperationInput.encode(XOR)) - } yield assert(result)(equalTo(respArgs("XOR"))) + } yield assert(result)(equalTo(RespCommand(Literal("XOR")))) }, test("not") { for { result <- ZIO.attempt(BitOperationInput.encode(NOT)) - } yield assert(result)(equalTo(respArgs("NOT"))) + } yield assert(result)(equalTo(RespCommand(Literal("NOT")))) } ), suite("BitPosRange")( test("with only start") { for { result <- ZIO.attempt(BitPosRangeInput.encode(BitPosRange(1.second.toMillis, None))) - } yield assert(result)(equalTo(respArgs("1000"))) + } yield assert(result)(equalTo(RespCommand(Unknown("1000")))) }, test("with start and the end") { for { result <- ZIO.attempt(BitPosRangeInput.encode(BitPosRange(0.second.toMillis, Some(1.second.toMillis)))) - } yield assert(result)(equalTo(respArgs("0", "1000"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0"), Unknown("1000")))) } ), suite("By")( test("with a pattern") { for { result <- ZIO.attempt(ByInput.encode("mykey_*")) - } yield assert(result)(equalTo(respArgs("BY", "mykey_*"))) + } yield assert(result)(equalTo(RespCommand(Literal("BY"), Unknown("mykey_*")))) } ), suite("Changed")( test("valid value") { for { result <- ZIO.attempt(ChangedInput.encode(Changed)) - } yield assert(result)(equalTo(respArgs("CH"))) + } yield assert(result)(equalTo(RespCommand(Literal("CH")))) } ), suite("ClientKill")( @@ -225,56 +226,56 @@ object InputSpec extends BaseSpec { address <- ZIO.succeed(InetAddress.getByName("127.0.0.1")) port <- ZIO.succeed(42) result <- ZIO.attempt(ClientKillInput.encode(ClientKillFilter.Address(address, port))) - } yield assert(result)(equalTo(respArgs("ADDR", "127.0.0.1:42"))) + } yield assert(result)(equalTo(RespCommand(Literal("ADDR"), Unknown("127.0.0.1:42")))) }, test("local address") { for { address <- ZIO.succeed(InetAddress.getByName("127.0.0.1")) port <- ZIO.succeed(42) result <- ZIO.attempt(ClientKillInput.encode(ClientKillFilter.LocalAddress(address, port))) - } yield assert(result)(equalTo(respArgs("LADDR", s"127.0.0.1:42"))) + } yield assert(result)(equalTo(RespCommand(Literal("LADDR"), Unknown(s"127.0.0.1:42")))) }, test("client id") { for { id <- ZIO.succeed(42L) result <- ZIO.attempt(ClientKillInput.encode(ClientKillFilter.Id(id))) - } yield assert(result)(equalTo(respArgs("ID", "42"))) + } yield assert(result)(equalTo(RespCommand(Literal("ID"), Unknown("42")))) }, test("type") { for { clientType <- ZIO.succeed(ClientType.PubSub) result <- ZIO.attempt(ClientKillInput.encode(ClientKillFilter.Type(clientType))) - } yield assert(result)(equalTo(respArgs("TYPE", "pubsub"))) + } yield assert(result)(equalTo(RespCommand(Literal("TYPE"), Literal("pubsub")))) }, test("user") { for { user <- ZIO.succeed("Foo Bar") result <- ZIO.attempt(ClientKillInput.encode(ClientKillFilter.User(user))) - } yield assert(result)(equalTo(respArgs("USER", "Foo Bar"))) + } yield assert(result)(equalTo(RespCommand(Literal("USER"), Unknown("Foo Bar")))) }, test("skip me") { for { result <- ZIO.attempt(ClientKillInput.encode(ClientKillFilter.SkipMe(true))) - } yield assert(result)(equalTo(respArgs("SKIPME", "YES"))) + } yield assert(result)(equalTo(RespCommand(Literal("SKIPME"), Literal("YES")))) } ), suite("ClientPauseMode")( test("all") { for { result <- ZIO.attempt(ClientPauseModeInput.encode(ClientPauseMode.All)) - } yield assert(result)(equalTo(respArgs("ALL"))) + } yield assert(result)(equalTo(RespCommand(Literal("ALL")))) }, test("write") { for { result <- ZIO.attempt(ClientPauseModeInput.encode(ClientPauseMode.Write)) - } yield assert(result)(equalTo(respArgs("WRITE"))) + } yield assert(result)(equalTo(RespCommand(Literal("WRITE")))) } ), suite("ClientTracking")( test("off") { for { result <- ZIO.attempt(ClientTrackingInput.encode(None)) - } yield assert(result)(equalTo(respArgs("OFF"))) + } yield assert(result)(equalTo(RespCommand(Literal("OFF")))) }, test("client redirect with noloop and prefixes") { for { @@ -283,8 +284,9 @@ object InputSpec extends BaseSpec { result <- ZIO.attempt(ClientTrackingInput.encode(Some((Some(clientId), None, true, prefixes)))) } yield assert(result)( equalTo( - respArgs("ON", "REDIRECT", clientId.toString) ++ prefixes - .flatMap(respArgs("PREFIX", _)) ++ respArgs("NOLOOP") + RespCommand(Literal("ON"), Literal("REDIRECT"), Unknown(clientId.toString)) ++ prefixes + .map(p => RespCommand(Literal("PREFIX"), Unknown(p))) + .fold(RespCommand.empty)(_ ++ _) ++ RespCommand(Literal("NOLOOP")) ) ) }, @@ -294,635 +296,635 @@ object InputSpec extends BaseSpec { ZIO.attempt( ClientTrackingInput.encode(Some((None, Some(ClientTrackingMode.Broadcast), false, Chunk.empty))) ) - } yield assert(result)(equalTo(respArgs("ON", "BCAST"))) + } yield assert(result)(equalTo(RespCommand(Literal("ON"), Literal("BCAST")))) } ), suite("Copy")( test("valid value") { for { result <- ZIO.attempt(CopyInput.encode(Copy)) - } yield assert(result)(equalTo(respArgs("COPY"))) + } yield assert(result)(equalTo(RespCommand(Literal("COPY")))) } ), suite("Count")( test("positive value") { for { result <- ZIO.attempt(CountInput.encode(Count(3L))) - } yield assert(result)(equalTo(respArgs("COUNT", "3"))) + } yield assert(result)(equalTo(RespCommand(Literal("COUNT"), Unknown("3")))) }, test("negative value") { for { result <- ZIO.attempt(CountInput.encode(Count(-3L))) - } yield assert(result)(equalTo(respArgs("COUNT", "-3"))) + } yield assert(result)(equalTo(RespCommand(Literal("COUNT"), Unknown("-3")))) }, test("zero value") { for { result <- ZIO.attempt(CountInput.encode(Count(0L))) - } yield assert(result)(equalTo(respArgs("COUNT", "0"))) + } yield assert(result)(equalTo(RespCommand(Literal("COUNT"), Unknown("0")))) } ), suite("Position")( test("before") { for { result <- ZIO.attempt(PositionInput.encode(Position.Before)) - } yield assert(result)(equalTo(respArgs("BEFORE"))) + } yield assert(result)(equalTo(RespCommand(Literal("BEFORE")))) }, test("after") { for { result <- ZIO.attempt(PositionInput.encode(Position.After)) - } yield assert(result)(equalTo(respArgs("AFTER"))) + } yield assert(result)(equalTo(RespCommand(Literal("AFTER")))) } ), suite("RedisType")( test("string type") { for { result <- ZIO.attempt(RedisTypeInput.encode(RedisType.String)) - } yield assert(result)(equalTo(respArgs("TYPE", "string"))) + } yield assert(result)(equalTo(RespCommand(Literal("TYPE"), Literal("string")))) }, test("list type") { for { result <- ZIO.attempt(RedisTypeInput.encode(RedisType.List)) - } yield assert(result)(equalTo(respArgs("TYPE", "list"))) + } yield assert(result)(equalTo(RespCommand(Literal("TYPE"), Literal("list")))) }, test("set type") { for { result <- ZIO.attempt(RedisTypeInput.encode(RedisType.Set)) - } yield assert(result)(equalTo(respArgs("TYPE", "set"))) + } yield assert(result)(equalTo(RespCommand(Literal("TYPE"), Literal("set")))) }, test("sorted set type") { for { result <- ZIO.attempt(RedisTypeInput.encode(RedisType.SortedSet)) - } yield assert(result)(equalTo(respArgs("TYPE", "zset"))) + } yield assert(result)(equalTo(RespCommand(Literal("TYPE"), Literal("zset")))) }, test("hash type") { for { result <- ZIO.attempt(RedisTypeInput.encode(RedisType.Hash)) - } yield assert(result)(equalTo(respArgs("TYPE", "hash"))) + } yield assert(result)(equalTo(RespCommand(Literal("TYPE"), Literal("hash")))) }, test("stream type") { for { result <- ZIO.attempt(RedisTypeInput.encode(RedisType.Stream)) - } yield assert(result)(equalTo(respArgs("TYPE", "stream"))) + } yield assert(result)(equalTo(RespCommand(Literal("TYPE"), Literal("stream")))) } ), suite("Double")( test("positive value") { for { result <- ZIO.attempt(DoubleInput.encode(4.2d)) - } yield assert(result)(equalTo(respArgs("4.2"))) + } yield assert(result)(equalTo(RespCommand(Unknown("4.2")))) }, test("negative value") { for { result <- ZIO.attempt(DoubleInput.encode(-4.2d)) - } yield assert(result)(equalTo(respArgs("-4.2"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-4.2")))) }, test("zero value") { for { result <- ZIO.attempt(DoubleInput.encode(0d)) - } yield assert(result)(equalTo(respArgs("0.0"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0.0")))) } ), suite("DurationMilliseconds")( test("1 second") { for { result <- ZIO.attempt(DurationMillisecondsInput.encode(1.second)) - } yield assert(result)(equalTo(respArgs("1000"))) + } yield assert(result)(equalTo(RespCommand(Unknown("1000")))) }, test("100 milliseconds") { for { result <- ZIO.attempt(DurationMillisecondsInput.encode(100.millis)) - } yield assert(result)(equalTo(respArgs("100"))) + } yield assert(result)(equalTo(RespCommand(Unknown("100")))) } ), suite("DurationSeconds")( test("1 minute") { for { result <- ZIO.attempt(DurationSecondsInput.encode(1.minute)) - } yield assert(result)(equalTo(respArgs("60"))) + } yield assert(result)(equalTo(RespCommand(Unknown("60")))) }, test("1 second") { for { result <- ZIO.attempt(DurationSecondsInput.encode(1.second)) - } yield assert(result)(equalTo(respArgs("1"))) + } yield assert(result)(equalTo(RespCommand(Unknown("1")))) }, test("100 milliseconds") { for { result <- ZIO.attempt(DurationSecondsInput.encode(100.millis)) - } yield assert(result)(equalTo(respArgs("0"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0")))) } ), suite("DurationTtl")( test("1 second") { for { result <- ZIO.attempt(DurationTtlInput.encode(1.second)) - } yield assert(result)(equalTo(respArgs("PX", "1000"))) + } yield assert(result)(equalTo(RespCommand(Literal("PX"), Unknown("1000")))) }, test("100 milliseconds") { for { result <- ZIO.attempt(DurationTtlInput.encode(100.millis)) - } yield assert(result)(equalTo(respArgs("PX", "100"))) + } yield assert(result)(equalTo(RespCommand(Literal("PX"), Unknown("100")))) } ), suite("Freq")( test("empty string") { for { result <- ZIO.attempt(FreqInput.encode(Freq(""))) - } yield assert(result)(equalTo(respArgs("FREQ", ""))) + } yield assert(result)(equalTo(RespCommand(Literal("FREQ"), Unknown("")))) }, test("non-empty string") { for { result <- ZIO.attempt(FreqInput.encode(Freq("frequency"))) - } yield assert(result)(equalTo(respArgs("FREQ", "frequency"))) + } yield assert(result)(equalTo(RespCommand(Literal("FREQ"), Unknown("frequency")))) } ), suite("Get")( test("with a pattern") { for { result <- ZIO.attempt(GetInput.encode("mypattern_*")) - } yield assert(result)(equalTo(respArgs("GET", "mypattern_*"))) + } yield assert(result)(equalTo(RespCommand(Literal("GET"), Unknown("mypattern_*")))) } ), suite("IdleTime")( test("0 seconds") { for { result <- ZIO.attempt(IdleTimeInput.encode(IdleTime(0))) - } yield assert(result)(equalTo(respArgs("IDLETIME", "0"))) + } yield assert(result)(equalTo(RespCommand(Literal("IDLETIME"), Unknown("0")))) }, test("5 seconds") { for { result <- ZIO.attempt(IdleTimeInput.encode(IdleTime(5))) - } yield assert(result)(equalTo(respArgs("IDLETIME", "5"))) + } yield assert(result)(equalTo(RespCommand(Literal("IDLETIME"), Unknown("5")))) } ), suite("Increment")( test("valid value") { for { result <- ZIO.attempt(IncrementInput.encode(Increment)) - } yield assert(result)(equalTo(respArgs("INCR"))) + } yield assert(result)(equalTo(RespCommand(Literal("INCR")))) } ), suite("KeepTtl")( test("valid value") { for { result <- ZIO.attempt(KeepTtlInput.encode(KeepTtl)) - } yield assert(result)(equalTo(respArgs("KEEPTTL"))) + } yield assert(result)(equalTo(RespCommand(Literal("KEEPTTL")))) } ), suite("LexRange")( test("with unbound min and unbound max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Unbounded.stringify, LexMaximum.Unbounded.stringify)) ) - } yield assert(result)(equalTo(respArgs("-", "+"))) + } yield assert(result)(equalTo(RespCommand(Value("-"), Value("+")))) }, test("with open min and unbound max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Open("a").stringify, LexMaximum.Unbounded.stringify)) ) - } yield assert(result)(equalTo(respArgs("(a", "+"))) + } yield assert(result)(equalTo(RespCommand(Value("(a"), Value("+")))) }, test("with closed min and unbound max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Closed("a").stringify, LexMaximum.Unbounded.stringify)) ) - } yield assert(result)(equalTo(respArgs("[a", "+"))) + } yield assert(result)(equalTo(RespCommand(Value("[a"), Value("+")))) }, test("with unbound min and open max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Unbounded.stringify, LexMaximum.Open("z").stringify)) ) - } yield assert(result)(equalTo(respArgs("-", "(z"))) + } yield assert(result)(equalTo(RespCommand(Value("-"), Value("(z")))) }, test("with open min and open max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Open("a").stringify, LexMaximum.Open("z").stringify)) ) - } yield assert(result)(equalTo(respArgs("(a", "(z"))) + } yield assert(result)(equalTo(RespCommand(Value("(a"), Value("(z")))) }, test("with closed min and open max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Closed("a").stringify, LexMaximum.Open("z").stringify)) ) - } yield assert(result)(equalTo(respArgs("[a", "(z"))) + } yield assert(result)(equalTo(RespCommand(Value("[a"), Value("(z")))) }, test("with unbound min and closed max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Unbounded.stringify, LexMaximum.Closed("z").stringify)) ) - } yield assert(result)(equalTo(respArgs("-", "[z"))) + } yield assert(result)(equalTo(RespCommand(Value("-"), Value("[z")))) }, test("with open min and closed max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Open("a").stringify, LexMaximum.Closed("z").stringify)) ) - } yield assert(result)(equalTo(respArgs("(a", "[z"))) + } yield assert(result)(equalTo(RespCommand(Value("(a"), Value("[z")))) }, test("with closed min and closed max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((LexMinimum.Closed("a").stringify, LexMaximum.Closed("z").stringify)) ) - } yield assert(result)(equalTo(respArgs("[a", "[z"))) + } yield assert(result)(equalTo(RespCommand(Value("[a"), Value("[z")))) } ), suite("Limit")( test("with positive offset and positive count") { for { result <- ZIO.attempt(LimitInput.encode(Limit(4L, 5L))) - } yield assert(result)(equalTo(respArgs("LIMIT", "4", "5"))) + } yield assert(result)(equalTo(RespCommand(Literal("LIMIT"), Unknown("4"), Unknown("5")))) }, test("with negative offset and negative count") { for { result <- ZIO.attempt(LimitInput.encode(Limit(-4L, -5L))) - } yield assert(result)(equalTo(respArgs("LIMIT", "-4", "-5"))) + } yield assert(result)(equalTo(RespCommand(Literal("LIMIT"), Unknown("-4"), Unknown("-5")))) }, test("with zero offset and zero count") { for { result <- ZIO.attempt(LimitInput.encode(Limit(0L, 0L))) - } yield assert(result)(equalTo(respArgs("LIMIT", "0", "0"))) + } yield assert(result)(equalTo(RespCommand(Literal("LIMIT"), Unknown("0"), Unknown("0")))) } ), suite("Long")( test("positive value") { for { result <- ZIO.attempt(LongInput.encode(4L)) - } yield assert(result)(equalTo(respArgs("4"))) + } yield assert(result)(equalTo(RespCommand(Unknown("4")))) }, test("negative value") { for { result <- ZIO.attempt(LongInput.encode(-4L)) - } yield assert(result)(equalTo(respArgs("-4"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-4")))) }, test("zero value") { for { result <- ZIO.attempt(LongInput.encode(0L)) - } yield assert(result)(equalTo(respArgs("0"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0")))) } ), suite("LongLat")( test("positive longitude and latitude") { for { result <- ZIO.attempt(LongLatInput.encode(LongLat(4.2d, 5.2d))) - } yield assert(result)(equalTo(respArgs("4.2", "5.2"))) + } yield assert(result)(equalTo(RespCommand(Unknown("4.2"), Unknown("5.2")))) }, test("negative longitude and latitude") { for { result <- ZIO.attempt(LongLatInput.encode(LongLat(-4.2d, -5.2d))) - } yield assert(result)(equalTo(respArgs("-4.2", "-5.2"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-4.2"), Unknown("-5.2")))) }, test("zero longitude and latitude") { for { result <- ZIO.attempt(LongLatInput.encode(LongLat(0d, 0d))) - } yield assert(result)(equalTo(respArgs("0.0", "0.0"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0.0"), Unknown("0.0")))) } ), suite("MemberScore")( test("with positive score and empty member") { for { result <- ZIO.attempt(MemberScoreInput[String]().encode(MemberScore(4.2d, ""))) - } yield assert(result)(equalTo(respArgs("4.2", ""))) + } yield assert(result)(equalTo(RespCommand(Unknown("4.2"), Value("")))) }, test("with negative score and empty member") { for { result <- ZIO.attempt(MemberScoreInput[String]().encode(MemberScore(-4.2d, ""))) - } yield assert(result)(equalTo(respArgs("-4.2", ""))) + } yield assert(result)(equalTo(RespCommand(Unknown("-4.2"), Value("")))) }, test("with zero score and empty member") { for { result <- ZIO.attempt(MemberScoreInput[String]().encode(MemberScore(0d, ""))) - } yield assert(result)(equalTo(respArgs("0.0", ""))) + } yield assert(result)(equalTo(RespCommand(Unknown("0.0"), Value("")))) }, test("with positive score and non-empty member") { for { result <- ZIO.attempt(MemberScoreInput[String]().encode(MemberScore(4.2d, "member"))) - } yield assert(result)(equalTo(respArgs("4.2", "member"))) + } yield assert(result)(equalTo(RespCommand(Unknown("4.2"), Value("member")))) }, test("with negative score and non-empty member") { for { result <- ZIO.attempt(MemberScoreInput[String]().encode(MemberScore(-4.2d, "member"))) - } yield assert(result)(equalTo(respArgs("-4.2", "member"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-4.2"), Value("member")))) }, test("with zero score and non-empty member") { for { result <- ZIO.attempt(MemberScoreInput[String]().encode(MemberScore(0d, "member"))) - } yield assert(result)(equalTo(respArgs("0.0", "member"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0.0"), Value("member")))) } ), suite("NoInput")( test("valid value") { for { result <- ZIO.attempt(NoInput.encode(())) - } yield assert(result)(isEmpty) + } yield assert(result.args)(isEmpty) } ), suite("NonEmptyList")( test("with multiple elements") { for { result <- ZIO.attempt(NonEmptyList(StringInput).encode(("a", List("b", "c")))) - } yield assert(result)(equalTo(respArgs("a", "b", "c"))) + } yield assert(result)(equalTo(RespCommand(Unknown("a"), Unknown("b"), Unknown("c")))) }, test("with one element") { for { result <- ZIO.attempt(NonEmptyList(StringInput).encode(("a", List.empty))) - } yield assert(result)(equalTo(respArgs("a"))) + } yield assert(result)(equalTo(RespCommand(Unknown("a")))) } ), suite("Order")( test("ascending") { for { result <- ZIO.attempt(OrderInput.encode(Ascending)) - } yield assert(result)(equalTo(respArgs("ASC"))) + } yield assert(result)(equalTo(RespCommand(Unknown("ASC")))) }, test("descending") { for { result <- ZIO.attempt(OrderInput.encode(Descending)) - } yield assert(result)(equalTo(respArgs("DESC"))) + } yield assert(result)(equalTo(RespCommand(Unknown("DESC")))) } ), suite("RadiusUnit")( test("meters") { for { result <- ZIO.attempt(RadiusUnitInput.encode(Meters)) - } yield assert(result)(equalTo(respArgs("m"))) + } yield assert(result)(equalTo(RespCommand(Unknown("m")))) }, test("kilometers") { for { result <- ZIO.attempt(RadiusUnitInput.encode(Kilometers)) - } yield assert(result)(equalTo(respArgs("km"))) + } yield assert(result)(equalTo(RespCommand(Unknown("km")))) }, test("feet") { for { result <- ZIO.attempt(RadiusUnitInput.encode(Feet)) - } yield assert(result)(equalTo(respArgs("ft"))) + } yield assert(result)(equalTo(RespCommand(Unknown("ft")))) }, test("miles") { for { result <- ZIO.attempt(RadiusUnitInput.encode(Miles)) - } yield assert(result)(equalTo(respArgs("mi"))) + } yield assert(result)(equalTo(RespCommand(Unknown("mi")))) } ), suite("Range")( test("with positive start and positive end") { for { result <- ZIO.attempt(RangeInput.encode(Range(1, 5))) - } yield assert(result)(equalTo(respArgs("1", "5"))) + } yield assert(result)(equalTo(RespCommand(Unknown("1"), Unknown("5")))) }, test("with negative start and positive end") { for { result <- ZIO.attempt(RangeInput.encode(Range(-1, 5))) - } yield assert(result)(equalTo(respArgs("-1", "5"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-1"), Unknown("5")))) }, test("with positive start and negative end") { for { result <- ZIO.attempt(RangeInput.encode(Range(1, -5))) - } yield assert(result)(equalTo(respArgs("1", "-5"))) + } yield assert(result)(equalTo(RespCommand(Unknown("1"), Unknown("-5")))) }, test("with negative start and negative end") { for { result <- ZIO.attempt(RangeInput.encode(Range(-1, -5))) - } yield assert(result)(equalTo(respArgs("-1", "-5"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-1"), Unknown("-5")))) } ), suite("Pattern")( test("with valid pattern") { for { result <- ZIO.attempt(PatternInput.encode(Pattern("*[ab]-*"))) - } yield assert(result)(equalTo(respArgs("MATCH", "*[ab]-*"))) + } yield assert(result)(equalTo(RespCommand(Literal("MATCH"), Unknown("*[ab]-*")))) }, test("with empty pattern") { for { result <- ZIO.attempt(PatternInput.encode(Pattern(""))) - } yield assert(result)(equalTo(respArgs("MATCH", ""))) + } yield assert(result)(equalTo(RespCommand(Literal("MATCH"), Unknown("")))) } ), suite("Replace")( test("valid value") { for { result <- ZIO.attempt(ReplaceInput.encode(Replace)) - } yield assert(result)(equalTo(respArgs("REPLACE"))) + } yield assert(result)(equalTo(RespCommand(Literal("REPLACE")))) } ), suite("StoreDist")( test("with non-empty string") { for { result <- ZIO.attempt(StoreDistInput.encode(StoreDist("key"))) - } yield assert(result)(equalTo(respArgs("STOREDIST", "key"))) + } yield assert(result)(equalTo(RespCommand(Literal("STOREDIST"), Unknown("key")))) }, test("with empty string") { for { result <- ZIO.attempt(StoreDistInput.encode(StoreDist(""))) - } yield assert(result)(equalTo(respArgs("STOREDIST", ""))) + } yield assert(result)(equalTo(RespCommand(Literal("STOREDIST"), Unknown("")))) } ), suite("Store")( test("with non-empty string") { for { result <- ZIO.attempt(StoreInput.encode(Store("key"))) - } yield assert(result)(equalTo(respArgs("STORE", "key"))) + } yield assert(result)(equalTo(RespCommand(Literal("STORE"), Unknown("key")))) }, test("with empty string") { for { result <- ZIO.attempt(StoreInput.encode(Store(""))) - } yield assert(result)(equalTo(respArgs("STORE", ""))) + } yield assert(result)(equalTo(RespCommand(Literal("STORE"), Unknown("")))) } ), suite("ScoreRange")( test("with infinite min and infinite max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Infinity.stringify, ScoreMaximum.Infinity.stringify)) ) - } yield assert(result)(equalTo(respArgs("-inf", "+inf"))) + } yield assert(result)(equalTo(RespCommand(Value("-inf"), Value("+inf")))) }, test("with open min and infinite max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Open(4.2d).stringify, ScoreMaximum.Infinity.stringify)) ) - } yield assert(result)(equalTo(respArgs("(4.2", "+inf"))) + } yield assert(result)(equalTo(RespCommand(Value("(4.2"), Value("+inf")))) }, test("with closed min and infinite max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Closed(4.2d).stringify, ScoreMaximum.Infinity.stringify)) ) - } yield assert(result)(equalTo(respArgs("4.2", "+inf"))) + } yield assert(result)(equalTo(RespCommand(Value("4.2"), Value("+inf")))) }, test("with infinite min and open max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Infinity.stringify, ScoreMaximum.Open(5.2d).stringify)) ) - } yield assert(result)(equalTo(respArgs("-inf", "(5.2"))) + } yield assert(result)(equalTo(RespCommand(Value("-inf"), Value("(5.2")))) }, test("with open min and open max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Open(4.2d).stringify, ScoreMaximum.Open(5.2d).stringify)) ) - } yield assert(result)(equalTo(respArgs("(4.2", "(5.2"))) + } yield assert(result)(equalTo(RespCommand(Value("(4.2"), Value("(5.2")))) }, test("with closed min and open max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Closed(4.2d).stringify, ScoreMaximum.Open(5.2d).stringify)) ) - } yield assert(result)(equalTo(respArgs("4.2", "(5.2"))) + } yield assert(result)(equalTo(RespCommand(Value("4.2"), Value("(5.2")))) }, test("with infinite min and closed max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Infinity.stringify, ScoreMaximum.Closed(5.2d).stringify)) ) - } yield assert(result)(equalTo(respArgs("-inf", "5.2"))) + } yield assert(result)(equalTo(RespCommand(Value("-inf"), Value("5.2")))) }, test("with open min and closed max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Open(4.2d).stringify, ScoreMaximum.Closed(5.2d).stringify)) ) - } yield assert(result)(equalTo(respArgs("(4.2", "5.2"))) + } yield assert(result)(equalTo(RespCommand(Value("(4.2"), Value("5.2")))) }, test("with closed min and closed max") { for { result <- ZIO.attempt( - Tuple2(ArbitraryInput[String](), ArbitraryInput[String]()) + Tuple2(ArbitraryValueInput[String](), ArbitraryValueInput[String]()) .encode((ScoreMinimum.Closed(4.2d).stringify, ScoreMaximum.Closed(5.2d).stringify)) ) - } yield assert(result)(equalTo(respArgs("4.2", "5.2"))) + } yield assert(result)(equalTo(RespCommand(Value("4.2"), Value("5.2")))) } ), suite("ScriptDebug")( test("yes") { for { result <- ZIO.attempt(ScriptDebugInput.encode(DebugMode.Yes)) - } yield assert(result)(equalTo(respArgs("YES"))) + } yield assert(result)(equalTo(RespCommand(Literal("YES")))) }, test("sync") { for { result <- ZIO.attempt(ScriptDebugInput.encode(DebugMode.Sync)) - } yield assert(result)(equalTo(respArgs("SYNC"))) + } yield assert(result)(equalTo(RespCommand(Literal("SYNC")))) }, test("no") { for { result <- ZIO.attempt(ScriptDebugInput.encode(DebugMode.No)) - } yield assert(result)(equalTo(respArgs("NO"))) + } yield assert(result)(equalTo(RespCommand(Literal("NO")))) } ), suite("ScriptFlush")( test("asynchronous") { for { result <- ZIO.attempt(ScriptFlushInput.encode(FlushMode.Async)) - } yield assert(result)(equalTo(respArgs("ASYNC"))) + } yield assert(result)(equalTo(RespCommand(Literal("ASYNC")))) }, test("synchronous") { for { result <- ZIO.attempt(ScriptFlushInput.encode(FlushMode.Sync)) - } yield assert(result)(equalTo(respArgs("SYNC"))) + } yield assert(result)(equalTo(RespCommand(Literal("SYNC")))) } ), suite("String")( test("non-empty value") { for { result <- ZIO.attempt(StringInput.encode("non-empty")) - } yield assert(result)(equalTo(respArgs("non-empty"))) + } yield assert(result)(equalTo(RespCommand(Unknown("non-empty")))) }, test("empty value") { for { result <- ZIO.attempt(StringInput.encode("")) - } yield assert(result)(equalTo(respArgs(""))) + } yield assert(result)(equalTo(RespCommand(Unknown("")))) } ), suite("Optional")( test("none") { for { result <- ZIO.attempt(OptionalInput(LongInput).encode(None)) - } yield assert(result)(isEmpty) + } yield assert(result.args)(isEmpty) }, test("some") { for { result <- ZIO.attempt(OptionalInput(LongInput).encode(Some(2L))) - } yield assert(result)(equalTo(respArgs("2"))) + } yield assert(result)(equalTo(RespCommand(Unknown("2")))) } ), suite("TimeSeconds")( test("positiv value") { for { result <- ZIO.attempt(TimeSecondsInput.encode(Instant.ofEpochSecond(3L))) - } yield assert(result)(equalTo(respArgs("3"))) + } yield assert(result)(equalTo(RespCommand(Unknown("3")))) }, test("zero value") { for { result <- ZIO.attempt(TimeSecondsInput.encode(Instant.ofEpochSecond(0L))) - } yield assert(result)(equalTo(respArgs("0"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0")))) }, test("negative value") { for { result <- ZIO.attempt(TimeSecondsInput.encode(Instant.ofEpochSecond(-3L))) - } yield assert(result)(equalTo(respArgs("-3"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-3")))) } ), suite("TimeMilliseconds")( test("positiv value") { for { result <- ZIO.attempt(TimeMillisecondsInput.encode(Instant.ofEpochSecond(3L))) - } yield assert(result)(equalTo(respArgs("3000"))) + } yield assert(result)(equalTo(RespCommand(Unknown("3000")))) }, test("zero value") { for { result <- ZIO.attempt(TimeMillisecondsInput.encode(Instant.ofEpochSecond(0L))) - } yield assert(result)(equalTo(respArgs("0"))) + } yield assert(result)(equalTo(RespCommand(Unknown("0")))) }, test("negative value") { for { result <- ZIO.attempt(TimeMillisecondsInput.encode(Instant.ofEpochSecond(-3L))) - } yield assert(result)(equalTo(respArgs("-3000"))) + } yield assert(result)(equalTo(RespCommand(Unknown("-3000")))) } ), suite("Tuple2")( test("valid value") { for { result <- ZIO.attempt(Tuple2(StringInput, LongInput).encode(("one", 2L))) - } yield assert(result)(equalTo(respArgs("one", "2"))) + } yield assert(result)(equalTo(RespCommand(Unknown("one"), Unknown("2")))) } ), suite("Tuple3")( test("valid value") { for { result <- ZIO.attempt(Tuple3(StringInput, LongInput, StringInput).encode(("one", 2, "three"))) - } yield assert(result)(equalTo(respArgs("one", "2", "three"))) + } yield assert(result)(equalTo(RespCommand(Unknown("one"), Unknown("2"), Unknown("three")))) } ), suite("Tuple4")( test("valid value") { for { result <- ZIO.attempt(Tuple4(StringInput, LongInput, StringInput, LongInput).encode(("one", 2, "three", 4))) - } yield assert(result)(equalTo(respArgs("one", "2", "three", "4"))) + } yield assert(result)(equalTo(RespCommand(Unknown("one"), Unknown("2"), Unknown("three"), Unknown("4")))) } ), suite("Tuple5")( @@ -933,7 +935,7 @@ object InputSpec extends BaseSpec { .encode(("one", 2, "three", 4, "five")) ) } yield assert(result)( - equalTo(respArgs("one", "2", "three", "4", "five")) + equalTo(RespCommand(Unknown("one"), Unknown("2"), Unknown("three"), Unknown("4"), Unknown("five"))) ) } ), @@ -946,14 +948,14 @@ object InputSpec extends BaseSpec { ) } yield assert(result)( equalTo( - respArgs( - "one", - "2", - "three", - "4", - "five", - "6", - "seven" + RespCommand( + Unknown("one"), + Unknown("2"), + Unknown("three"), + Unknown("4"), + Unknown("five"), + Unknown("6"), + Unknown("seven") ) ) ) @@ -977,16 +979,16 @@ object InputSpec extends BaseSpec { ) } yield assert(result)( equalTo( - respArgs( - "one", - "2", - "three", - "4", - "five", - "6", - "seven", - "8", - "nine" + RespCommand( + Unknown("one"), + Unknown("2"), + Unknown("three"), + Unknown("4"), + Unknown("five"), + Unknown("6"), + Unknown("seven"), + Unknown("8"), + Unknown("nine") ) ) ) @@ -1012,18 +1014,18 @@ object InputSpec extends BaseSpec { ) } yield assert(result)( equalTo( - respArgs( - "one", - "2", - "three", - "4", - "five", - "6", - "seven", - "8", - "nine", - "10", - "eleven" + RespCommand( + Unknown("one"), + Unknown("2"), + Unknown("three"), + Unknown("4"), + Unknown("five"), + Unknown("6"), + Unknown("seven"), + Unknown("8"), + Unknown("nine"), + Unknown("10"), + Unknown("eleven") ) ) ) @@ -1033,117 +1035,117 @@ object InputSpec extends BaseSpec { test("set existing") { for { result <- ZIO.attempt(UpdateInput.encode(Update.SetExisting)) - } yield assert(result)(equalTo(respArgs("XX"))) + } yield assert(result)(equalTo(RespCommand(Unknown("XX")))) }, test("set new") { for { result <- ZIO.attempt(UpdateInput.encode(Update.SetNew)) - } yield assert(result)(equalTo(respArgs("NX"))) + } yield assert(result)(equalTo(RespCommand(Unknown("NX")))) } ), suite("Id")( test("valid value") { for { result <- ZIO.attempt(IdInput.encode(10)) - } yield assert(result)(equalTo(respArgs("ID", "10"))) + } yield assert(result)(equalTo(RespCommand(Literal("ID"), Unknown("10")))) } ), suite("UnblockBehavior")( test("timeout") { for { result <- ZIO.attempt(UnblockBehaviorInput.encode(UnblockBehavior.Timeout)) - } yield assert(result)(equalTo(respArgs("TIMEOUT"))) + } yield assert(result)(equalTo(RespCommand(Unknown("TIMEOUT")))) }, test("error") { for { result <- ZIO.attempt(UnblockBehaviorInput.encode(UnblockBehavior.Error)) - } yield assert(result)(equalTo(respArgs("ERROR"))) + } yield assert(result)(equalTo(RespCommand(Unknown("ERROR")))) } ), suite("Varargs")( test("with multiple elements") { for { result <- ZIO.attempt(Varargs(LongInput).encode(List(1, 2, 3))) - } yield assert(result)(equalTo(respArgs("1", "2", "3"))) + } yield assert(result)(equalTo(RespCommand(Unknown("1"), Unknown("2"), Unknown("3")))) }, test("with no elements") { for { result <- ZIO.attempt(Varargs(LongInput).encode(List.empty)) - } yield assert(result)(isEmpty) + } yield assert(result.args)(isEmpty) } ), suite("WithScores")( test("valid value") { for { result <- ZIO.attempt(WithScoresInput.encode(WithScores)) - } yield assert(result)(equalTo(respArgs("WITHSCORES"))) + } yield assert(result)(equalTo(RespCommand(Literal("WITHSCORES")))) } ), suite("WithCoord")( test("valid value") { for { result <- ZIO.attempt(WithCoordInput.encode(WithCoord)) - } yield assert(result)(equalTo(respArgs("WITHCOORD"))) + } yield assert(result)(equalTo(RespCommand(Literal("WITHCOORD")))) } ), suite("WithDist")( test("valid value") { for { result <- ZIO.attempt(WithDistInput.encode(WithDist)) - } yield assert(result)(equalTo(respArgs("WITHDIST"))) + } yield assert(result)(equalTo(RespCommand(Literal("WITHDIST")))) } ), suite("WithHash")( test("valid value") { for { result <- ZIO.attempt(WithHashInput.encode(WithHash)) - } yield assert(result)(equalTo(respArgs("WITHHASH"))) + } yield assert(result)(equalTo(RespCommand(Literal("WITHHASH")))) } ), suite("Idle")( test("with 1 second") { ZIO .attempt(IdleInput.encode(1.second)) - .map(assert(_)(equalTo(respArgs("IDLE", "1000")))) + .map(assert(_)(equalTo(RespCommand(Literal("IDLE"), Unknown("1000"))))) }, test("with 100 milliseconds") { ZIO .attempt(IdleInput.encode(100.millis)) - .map(assert(_)(equalTo(respArgs("IDLE", "100")))) + .map(assert(_)(equalTo(RespCommand(Literal("IDLE"), Unknown("100"))))) }, test("with negative duration") { ZIO .attempt(IdleInput.encode((-1).second)) - .map(assert(_)(equalTo(respArgs("IDLE", "-1000")))) + .map(assert(_)(equalTo(RespCommand(Literal("IDLE"), Unknown("-1000"))))) } ), suite("Time")( test("with 1 second") { ZIO .attempt(TimeInput.encode(1.second)) - .map(assert(_)(equalTo(respArgs("TIME", "1000")))) + .map(assert(_)(equalTo(RespCommand(Literal("TIME"), Unknown("1000"))))) }, test("with 100 milliseconds") { ZIO .attempt(TimeInput.encode(100.millis)) - .map(assert(_)(equalTo(respArgs("TIME", "100")))) + .map(assert(_)(equalTo(RespCommand(Literal("TIME"), Unknown("100"))))) }, test("with negative duration") { ZIO .attempt(TimeInput.encode((-1).second)) - .map(assert(_)(equalTo(respArgs("TIME", "-1000")))) + .map(assert(_)(equalTo(RespCommand(Literal("TIME"), Unknown("-1000"))))) } ), suite("RetryCount")( test("with positive count") { ZIO .attempt(RetryCountInput.encode(100)) - .map(assert(_)(equalTo(respArgs("RETRYCOUNT", "100")))) + .map(assert(_)(equalTo(RespCommand(Literal("RETRYCOUNT"), Unknown("100"))))) }, test("with negative count") { ZIO .attempt(RetryCountInput.encode(-100)) - .map(assert(_)(equalTo(respArgs("RETRYCOUNT", "-100")))) + .map(assert(_)(equalTo(RespCommand(Literal("RETRYCOUNT"), Unknown("-100"))))) } ), suite("XGroupCreate")( @@ -1154,7 +1156,7 @@ object InputSpec extends BaseSpec { XGroupCommand.Create("key", "group", "id", mkStream = false) ) ) - .map(assert(_)(equalTo(respArgs("CREATE", "key", "group", "id")))) + .map(assert(_)(equalTo(RespCommand(Literal("CREATE"), Key("key"), Unknown("group"), Unknown("id"))))) }, test("with mkStream") { ZIO @@ -1163,21 +1165,27 @@ object InputSpec extends BaseSpec { XGroupCommand.Create("key", "group", "id", mkStream = true) ) ) - .map(assert(_)(equalTo(respArgs("CREATE", "key", "group", "id", "MKSTREAM")))) + .map( + assert(_)( + equalTo( + RespCommand(Literal("CREATE"), Key("key"), Unknown("group"), Unknown("id"), Literal("MKSTREAM")) + ) + ) + ) } ), suite("XGroupSetId")( test("valid value") { ZIO .attempt(XGroupSetIdInput[String, String, String]().encode(XGroupCommand.SetId("key", "group", "id"))) - .map(assert(_)(equalTo(respArgs("SETID", "key", "group", "id")))) + .map(assert(_)(equalTo(RespCommand(Literal("SETID"), Key("key"), Unknown("group"), Unknown("id"))))) } ), suite("XGroupDestroy")( test("valid value") { ZIO .attempt(XGroupDestroyInput[String, String]().encode(XGroupCommand.Destroy("key", "group"))) - .map(assert(_)(equalTo(respArgs("DESTROY", "key", "group")))) + .map(assert(_)(equalTo(RespCommand(Literal("DESTROY"), Key("key"), Unknown("group"))))) } ), suite("XGroupCreateConsumer")( @@ -1188,7 +1196,11 @@ object InputSpec extends BaseSpec { XGroupCommand.CreateConsumer("key", "group", "consumer") ) ) - .map(assert(_)(equalTo(respArgs("CREATECONSUMER", "key", "group", "consumer")))) + .map( + assert(_)( + equalTo(RespCommand(Literal("CREATECONSUMER"), Key("key"), Unknown("group"), Unknown("consumer"))) + ) + ) } ), suite("XGroupDelConsumer")( @@ -1199,85 +1211,89 @@ object InputSpec extends BaseSpec { XGroupCommand.DelConsumer("key", "group", "consumer") ) ) - .map(assert(_)(equalTo(respArgs("DELCONSUMER", "key", "group", "consumer")))) + .map( + assert(_)(equalTo(RespCommand(Literal("DELCONSUMER"), Key("key"), Unknown("group"), Unknown("consumer")))) + ) } ), suite("Block")( test("with 1 second") { ZIO .attempt(BlockInput.encode(1.second)) - .map(assert(_)(equalTo(respArgs("BLOCK", "1000")))) + .map(assert(_)(equalTo(RespCommand(Literal("BLOCK"), Unknown("1000"))))) }, test("with 100 milliseconds") { ZIO .attempt(BlockInput.encode(100.millis)) - .map(assert(_)(equalTo(respArgs("BLOCK", "100")))) + .map(assert(_)(equalTo(RespCommand(Literal("BLOCK"), Unknown("100"))))) }, test("with negative duration") { ZIO .attempt(BlockInput.encode((-1).second)) - .map(assert(_)(equalTo(respArgs("BLOCK", "-1000")))) + .map(assert(_)(equalTo(RespCommand(Literal("BLOCK"), Unknown("-1000"))))) } ), suite("Streams")( test("with one pair") { ZIO .attempt(StreamsInput[String, String]().encode(("a" -> "b", Chunk.empty))) - .map(assert(_)(equalTo(respArgs("STREAMS", "a", "b")))) + .map(assert(_)(equalTo(RespCommand(Literal("STREAMS"), Key("a"), Value("b"))))) }, test("with multiple pairs") { ZIO .attempt(StreamsInput[String, String]().encode(("a" -> "b", Chunk.single("c" -> "d")))) - .map(assert(_)(equalTo(respArgs("STREAMS", "a", "c", "b", "d")))) + .map(assert(_)(equalTo(RespCommand(Literal("STREAMS"), Key("a"), Key("c"), Value("b"), Value("d"))))) } ), suite("NoAck")( test("valid value") { - ZIO.attempt(NoAckInput.encode(NoAck)).map(assert(_)(equalTo(respArgs("NOACK")))) + ZIO.attempt(NoAckInput.encode(NoAck)).map(assert(_)(equalTo(RespCommand(Unknown("NOACK"))))) } ), suite("MaxLen")( test("with approximate") { ZIO .attempt(StreamMaxLenInput.encode(StreamMaxLen(approximate = true, 10))) - .map(assert(_)(equalTo(respArgs("MAXLEN", "~", "10")))) + .map(assert(_)(equalTo(RespCommand(Literal("MAXLEN"), Literal("~"), Unknown("10"))))) }, test("without approximate") { ZIO .attempt(StreamMaxLenInput.encode(StreamMaxLen(approximate = false, 10))) - .map(assert(_)(equalTo(respArgs("MAXLEN", "10")))) + .map(assert(_)(equalTo(RespCommand(Literal("MAXLEN"), Unknown("10"))))) } ), suite("WithForce")( test("valid value") { - ZIO.attempt(WithForceInput.encode(WithForce)).map(assert(_)(equalTo(respArgs("FORCE")))) + ZIO.attempt(WithForceInput.encode(WithForce)).map(assert(_)(equalTo(RespCommand(Literal("FORCE"))))) } ), suite("WithJustId")( test("valid value") { - ZIO.attempt(WithJustIdInput.encode(WithJustId)).map(assert(_)(equalTo(respArgs("JUSTID")))) + ZIO.attempt(WithJustIdInput.encode(WithJustId)).map(assert(_)(equalTo(RespCommand(Literal("JUSTID"))))) } ), suite("Side")( test("left") { for { result <- ZIO.attempt(SideInput.encode(Side.Left)) - } yield assert(result)(equalTo(respArgs("LEFT"))) + } yield assert(result)(equalTo(RespCommand(Literal("LEFT")))) }, test("right") { for { result <- ZIO.attempt(SideInput.encode(Side.Right)) - } yield assert(result)(equalTo(respArgs("RIGHT"))) + } yield assert(result)(equalTo(RespCommand(Literal("RIGHT")))) } ), suite("ListMaxLen")( test("valid value") { - ZIO.attempt(ListMaxLenInput.encode(ListMaxLen(10L))).map(assert(_)(equalTo(respArgs("MAXLEN", "10")))) + ZIO + .attempt(ListMaxLenInput.encode(ListMaxLen(10L))) + .map(assert(_)(equalTo(RespCommand(Literal("MAXLEN"), Unknown("10"))))) } ), suite("Rank")( test("valid value") { - ZIO.attempt(RankInput.encode(Rank(10L))).map(assert(_)(equalTo(respArgs("RANK", "10")))) + ZIO.attempt(RankInput.encode(Rank(10L))).map(assert(_)(equalTo(RespCommand(Literal("RANK"), Unknown("10"))))) } ), suite("GetEx")( @@ -1287,8 +1303,10 @@ object InputSpec extends BaseSpec { ZIO.attempt(GetExInput[String]().encode(scala.Tuple3.apply("key", Expire.SetExpireSeconds, 1.second))) resultMilliseconds <- ZIO.attempt(GetExInput[String]().encode(scala.Tuple3("key", Expire.SetExpireMilliseconds, 100.millis))) - } yield assert(resultSeconds)(equalTo(respArgs("key", "EX", "1"))) && assert(resultMilliseconds)( - equalTo(respArgs("key", "PX", "100")) + } yield assert(resultSeconds)(equalTo(RespCommand(Key("key"), Literal("EX"), Unknown("1")))) && assert( + resultMilliseconds + )( + equalTo(RespCommand(Key("key"), Literal("PX"), Unknown("100"))) ) }, test("GetExAtInput - valid value") { @@ -1305,31 +1323,31 @@ object InputSpec extends BaseSpec { scala.Tuple3("key", ExpiredAt.SetExpireAtMilliseconds, Instant.parse("2021-04-06T00:00:00Z")) ) ) - } yield assert(resultSeconds)(equalTo(respArgs("key", "EXAT", "1617667200"))) && assert(resultMilliseconds)( - equalTo(respArgs("key", "PXAT", "1617667200000")) + } yield assert(resultSeconds)( + equalTo(RespCommand(Key("key"), Literal("EXAT"), Unknown("1617667200"))) + ) && assert(resultMilliseconds)( + equalTo(RespCommand(Key("key"), Literal("PXAT"), Unknown("1617667200000"))) ) }, test("GetExPersistInput - valid value") { for { result <- ZIO.attempt(GetExPersistInput[String]().encode("key" -> true)) resultWithoutOption <- ZIO.attempt(GetExPersistInput[String]().encode("key" -> false)) - } yield assert(result)(equalTo(respArgs("key", "PERSIST"))) && - assert(resultWithoutOption)(equalTo(respArgs("key"))) + } yield assert(result)(equalTo(RespCommand(Key("key"), Literal("PERSIST")))) && + assert(resultWithoutOption)(equalTo(RespCommand(Key("key")))) } ), suite("YesNo")( test("yes") { for { result <- ZIO.attempt(YesNoInput.encode(true)) - } yield assert(result)(equalTo(respArgs("YES"))) + } yield assert(result)(equalTo(RespCommand(Literal("YES")))) }, test("no") { for { result <- ZIO.attempt(YesNoInput.encode(false)) - } yield assert(result)(equalTo(respArgs("NO"))) + } yield assert(result)(equalTo(RespCommand(Literal("NO")))) } ) ) - - private def respArgs(xs: String*): Chunk[RespValue] = Chunk.fromIterable(xs.map(RespValue.bulkString)) } diff --git a/redis/src/test/scala/zio/redis/KeysSpec.scala b/redis/src/test/scala/zio/redis/KeysSpec.scala index 5ead137..d05915a 100644 --- a/redis/src/test/scala/zio/redis/KeysSpec.scala +++ b/redis/src/test/scala/zio/redis/KeysSpec.scala @@ -44,6 +44,15 @@ trait KeysSpec extends BaseSpec { e2 <- redis.exists("unknown") } yield assert(e1)(equalTo(1L)) && assert(e2)(equalTo(0L)) }, + test("check multiple existence") { + for { + redis <- ZIO.service[Redis] + key <- uuid + value <- uuid + _ <- redis.set(key, value) + e1 <- redis.exists(key, "unknown") + } yield assert(e1)(equalTo(1L)) + } @@ clusterExecutorUnsupported, test("delete existing key") { for { redis <- ZIO.service[Redis] @@ -53,6 +62,17 @@ trait KeysSpec extends BaseSpec { deleted <- redis.del(key) } yield assert(deleted)(equalTo(1L)) }, + test("delete multiple existing key") { + for { + redis <- ZIO.service[Redis] + key1 <- uuid + key2 <- uuid + value <- uuid + _ <- redis.set(key1, value) + _ <- redis.set(key2, value) + deleted <- redis.del(key1, key2) + } yield assert(deleted)(equalTo(2L)) + } @@ clusterExecutorUnsupported, test("find all keys matching pattern") { for { redis <- ZIO.service[Redis] @@ -72,7 +92,7 @@ trait KeysSpec extends BaseSpec { _ <- redis.set(key, value) removed <- redis.unlink(key) } yield assert(removed)(equalTo(1L)) - }, + } @@ clusterExecutorUnsupported, test("touch two existing keys") { for { redis <- ZIO.service[Redis] @@ -96,7 +116,7 @@ trait KeysSpec extends BaseSpec { (next, elements) = scan } yield assert(next)(isGreaterThanEqualTo(0L)) && assert(elements)(isNonEmpty) } - ) @@ flaky, + ) @@ flaky @@ clusterExecutorUnsupported, test("fetch random key") { for { redis <- ZIO.service[Redis] @@ -106,7 +126,7 @@ trait KeysSpec extends BaseSpec { allKeys <- redis.keys("*").returning[String] randomKey <- redis.randomKey.returning[String] } yield assert(allKeys)(contains(randomKey.get)) - } @@ ignore, + } @@ ignore @@ clusterExecutorUnsupported, test("dump followed by restore") { for { redis <- ZIO.service[Redis] diff --git a/redis/src/test/scala/zio/redis/ScriptingSpec.scala b/redis/src/test/scala/zio/redis/ScriptingSpec.scala index 164a29b..3d6f4f2 100644 --- a/redis/src/test/scala/zio/redis/ScriptingSpec.scala +++ b/redis/src/test/scala/zio/redis/ScriptingSpec.scala @@ -1,7 +1,7 @@ package zio.redis import zio._ -import zio.redis.Input.{BoolInput, ByteInput, LongInput, StringInput} +import zio.redis.Input.{BoolInput, LongInput, StringInput, ValueInput} import zio.redis.Output._ import zio.redis.RedisError._ import zio.redis.ScriptingSpec._ @@ -162,7 +162,7 @@ trait ScriptingSpec extends BaseSpec { res <- redis.evalSha(lua, emptyInput, emptyInput).returning[String].either } yield assert(res)(isLeft(isSubtype[NoScript](hasField("message", _.message, equalTo(error))))) } - ), + ) @@ clusterExecutorUnsupported, suite("scriptDebug")( test("enable non-blocking asynchronous debugging") { for { @@ -202,7 +202,7 @@ trait ScriptingSpec extends BaseSpec { res <- redis.scriptExists(lua1, lua2) } yield assertTrue(res == Chunk(false, false)) } - ), + ) @@ clusterExecutorUnsupported, suite("scriptFlush")( test("flush scripts in default mode") { val lua1 = """return "1"""" @@ -237,7 +237,7 @@ trait ScriptingSpec extends BaseSpec { res <- redis.scriptExists(sha1, sha2) } yield assertTrue(res == Chunk(false, false)) } - ), + ) @@ clusterExecutorUnsupported, suite("scriptKill")( test("return NOTBUSY when there is no scripts in execution") { for { @@ -245,7 +245,7 @@ trait ScriptingSpec extends BaseSpec { res <- redis.scriptKill.either } yield assert(res)(isLeft(isSubtype[RedisError.NotBusy](anything))) } - ), + ) @@ clusterExecutorUnsupported, suite("scriptLoad")( test("return OK") { val lua = """return "1"""" @@ -262,7 +262,7 @@ trait ScriptingSpec extends BaseSpec { sha <- redis.scriptLoad(lua).either } yield assert(sha)(isLeft(isSubtype[ProtocolError](hasField("message", _.message, equalTo(error))))) } - ) + ) @@ clusterExecutorUnsupported ) } @@ -301,7 +301,7 @@ object ScriptingSpec { case other => throw ProtocolError(s"$other isn't a string type") } - implicit val bytesEncoder: Input[Chunk[Byte]] = ByteInput + implicit val bytesEncoder: Input[Chunk[Byte]] = ValueInput implicit val booleanInput: Input[Boolean] = BoolInput implicit val stringInput: Input[String] = StringInput implicit val longInput: Input[Long] = LongInput diff --git a/redis/src/test/scala/zio/redis/StreamsSpec.scala b/redis/src/test/scala/zio/redis/StreamsSpec.scala index 5da85fa..405e2f3 100644 --- a/redis/src/test/scala/zio/redis/StreamsSpec.scala +++ b/redis/src/test/scala/zio/redis/StreamsSpec.scala @@ -3,7 +3,7 @@ package zio.redis import zio._ import zio.redis.RedisError._ import zio.test.Assertion._ -import zio.test.TestAspect.ignore +import zio.test.TestAspect.{flaky, ignore} import zio.test._ trait StreamsSpec extends BaseSpec { @@ -926,7 +926,7 @@ trait StreamsSpec extends BaseSpec { assert(result.owner)(equalTo(consumer)) && assert(result.lastDelivered)(isGreaterThan(0.millis)) && assert(result.counter)(equalTo(1L)) - }, + } @@ flaky, test("with multiple message, unlimited start, unlimited end and count with value 10") { for { redis <- ZIO.service[Redis] @@ -950,7 +950,7 @@ trait StreamsSpec extends BaseSpec { assert(secondResult.owner)(equalTo(second)) && assert(secondResult.lastDelivered)(isGreaterThan(0.millis)) && assert(secondResult.counter)(equalTo(1L)) - }, + } @@ flaky, test("with unlimited start, unlimited end, count with value 10, and the specified consumer") { for { redis <- ZIO.service[Redis] @@ -1078,7 +1078,7 @@ trait StreamsSpec extends BaseSpec { ) ) ) - }, + } @@ clusterExecutorUnsupported, test("with the positive count") { for { redis <- ZIO.service[Redis] @@ -1226,7 +1226,7 @@ trait StreamsSpec extends BaseSpec { ) ) ) - }, + } @@ clusterExecutorUnsupported, test("with positive count") { for { redis <- ZIO.service[Redis] -- GitLab