diff --git a/redis/src/main/scala/zio/redis/ClusterExecutor.scala b/redis/src/main/scala/zio/redis/ClusterExecutor.scala index 652b84867..2035ab00d 100644 --- a/redis/src/main/scala/zio/redis/ClusterExecutor.scala +++ b/redis/src/main/scala/zio/redis/ClusterExecutor.scala @@ -18,8 +18,8 @@ package zio.redis import zio._ import zio.redis.ClusterExecutor._ -import zio.redis.api.Cluster.AskingCommand import zio.redis.codecs.StringUtf8Codec +import zio.redis.commands.Cluster.askingCommand import zio.redis.options.Cluster._ import zio.schema.codec.BinaryCodec @@ -42,7 +42,7 @@ final case class ClusterExecutor( def executeAsk(address: RedisUri) = for { executor <- executor(address) - _ <- executor.execute(AskingCommand(StringUtf8Codec, this).resp(())) + _ <- executor.execute(askingCommand(StringUtf8Codec, this).resp(())) res <- executor.execute(command) } yield res diff --git a/redis/src/main/scala/zio/redis/Output.scala b/redis/src/main/scala/zio/redis/Output.scala index 21a29b3a5..e5618b89e 100644 --- a/redis/src/main/scala/zio/redis/Output.scala +++ b/redis/src/main/scala/zio/redis/Output.scala @@ -17,13 +17,12 @@ package zio.redis import zio._ +import zio.redis.Output.TransactionOutput import zio.redis.options.Cluster.{Node, Partition, SlotRange} import zio.schema.Schema import zio.schema.codec.BinaryCodec -sealed trait Output[+A] { - self => - +sealed trait Output[+A] { self => private[redis] final def unsafeDecode(respValue: RespValue)(implicit codec: BinaryCodec): A = respValue match { case error: RespValue.Error => throw error.toRedisError @@ -32,9 +31,17 @@ sealed trait Output[+A] { protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): A - final def map[B](f: A => B): Output[B] = + def map[B](f: A => B): Output[B] = new Output[B] { protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): B = f(self.tryDecode(respValue)) + + override protected def count: Int = self.count + } + + protected def count: Int = + self match { + case value: TransactionOutput[_, _, _] => value.count + case _ => 1 } } @@ -369,7 +376,7 @@ object Output { } case object StreamGroupsInfoOutput extends Output[Chunk[StreamGroupsInfo]] { - override protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): Chunk[StreamGroupsInfo] = + protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): Chunk[StreamGroupsInfo] = respValue match { case RespValue.NullArray => Chunk.empty case RespValue.Array(messages) => @@ -408,7 +415,7 @@ object Output { } case object StreamConsumersInfoOutput extends Output[Chunk[StreamConsumersInfo]] { - override protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): Chunk[StreamConsumersInfo] = + protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): Chunk[StreamConsumersInfo] = respValue match { case RespValue.NullArray => Chunk.empty case RespValue.Array(messages) => @@ -446,7 +453,7 @@ object Output { final case class StreamInfoFullOutput[I: Schema, K: Schema, V: Schema]() extends Output[StreamInfoWithFull.FullStreamInfo[I, K, V]] { - override protected def tryDecode( + protected def tryDecode( respValue: RespValue )(implicit codec: BinaryCodec): StreamInfoWithFull.FullStreamInfo[I, K, V] = { var streamInfoFull: StreamInfoWithFull.FullStreamInfo[I, K, V] = StreamInfoWithFull.FullStreamInfo.empty @@ -827,4 +834,72 @@ object Output { case other => throw ProtocolError(s"$other isn't an array") } } + + case object QueuedOutput extends Output[Unit] { + protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): Unit = + respValue match { + case RespValue.SimpleString("QUEUED") => () + case other => throw ProtocolError(s"$other isn't queued") + } + } + + trait TransactionOutput[A, B, Out] extends Output[Out] { self => + def left: Output[A] + def right: Output[B] + + override final def map[C](f: Out => C): Output[C] = + new TransactionOutput[A, B, C] { + def left: Output[A] = self.left + def right: Output[B] = self.right + + protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): C = f(self.tryDecode(respValue)) + } + + override def count: Int = left.count + right.count + } + + final case class Zip[A, B](left: Output[A], right: Output[B]) extends TransactionOutput[A, B, (A, B)] { + protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): (A, B) = + respValue match { + case RespValue.Array(values) => + (left, right) match { + case (left: TransactionOutput[_, _, _], right: TransactionOutput[_, _, _]) => + ( + left.tryDecode(RespValue.Array(values.take(left.count))), + right.tryDecode(RespValue.Array(values.drop(left.count).take(right.count))) + ) + case (_, right: TransactionOutput[_, _, _]) => + (left.tryDecode(values.head), right.tryDecode(RespValue.Array(values.tail))) + case (left: TransactionOutput[_, _, _], _) => + (left.tryDecode(RespValue.Array(values.init)), right.tryDecode(values.last)) + case _ => + (left.tryDecode(values.head), right.tryDecode(values.last)) + } + case other => throw ProtocolError(s"$other is not an array") + } + } + + final case class ZipLeft[A, B](left: Output[A], right: Output[B]) extends TransactionOutput[A, B, A] { + protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): A = + respValue match { + case RespValue.Array(values) => + left match { + case _: TransactionOutput[_, _, _] => left.tryDecode(RespValue.Array(values.take(left.count))) + case _ => left.tryDecode(values.head) + } + case other => throw ProtocolError(s"$other is not an array") + } + } + + final case class ZipRight[A, B](left: Output[A], right: Output[B]) extends TransactionOutput[A, B, B] { + protected def tryDecode(respValue: RespValue)(implicit codec: BinaryCodec): B = + respValue match { + case RespValue.Array(values) => + left match { + case _: TransactionOutput[_, _, _] => right.tryDecode(RespValue.Array(values.drop(left.count))) + case _ => right.tryDecode(values.last) + } + case other => throw ProtocolError(s"$other is not an array") + } + } } diff --git a/redis/src/main/scala/zio/redis/RedisEnvironment.scala b/redis/src/main/scala/zio/redis/RedisEnvironment.scala index 886ef9a8d..49415baa0 100644 --- a/redis/src/main/scala/zio/redis/RedisEnvironment.scala +++ b/redis/src/main/scala/zio/redis/RedisEnvironment.scala @@ -19,6 +19,6 @@ package zio.redis import zio.schema.codec.BinaryCodec private[redis] trait RedisEnvironment { - protected def codec: BinaryCodec - protected def executor: RedisExecutor + def codec: BinaryCodec + def executor: RedisExecutor } diff --git a/redis/src/main/scala/zio/redis/api/Cluster.scala b/redis/src/main/scala/zio/redis/api/Cluster.scala index 30bc11c43..4d5c10d6f 100644 --- a/redis/src/main/scala/zio/redis/api/Cluster.scala +++ b/redis/src/main/scala/zio/redis/api/Cluster.scala @@ -16,16 +16,12 @@ package zio.redis.api -import zio.redis.Input._ -import zio.redis.Output.{ChunkOutput, ClusterPartitionOutput, UnitOutput} import zio.redis._ -import zio.redis.api.Cluster.{AskingCommand, ClusterSetSlots, ClusterSlots} import zio.redis.options.Cluster.SetSlotSubCommand._ import zio.redis.options.Cluster.{Partition, Slot} -import zio.schema.codec.BinaryCodec import zio.{Chunk, IO} -trait Cluster extends RedisEnvironment { +trait Cluster extends commands.Cluster { /** * When a cluster client receives an -ASK redirect, the ASKING command is sent to the target node followed by the @@ -34,8 +30,7 @@ trait Cluster extends RedisEnvironment { * @return * the Unit value. */ - final def asking: IO[RedisError, Unit] = - AskingCommand(codec, executor).run(()) + final def asking: IO[RedisError, Unit] = _asking.run(()) /** * Returns details about which cluster slots map to which Redis instances. @@ -43,10 +38,7 @@ trait Cluster extends RedisEnvironment { * @return * details about which cluster */ - final def slots: IO[RedisError, Chunk[Partition]] = { - val command = RedisCommand(ClusterSlots, NoInput, ChunkOutput(ClusterPartitionOutput), codec, executor) - command.run(()) - } + final def slots: IO[RedisError, Chunk[Partition]] = _slots.run(()) /** * Clear any importing / migrating state from hash slot. @@ -56,11 +48,8 @@ trait Cluster extends RedisEnvironment { * @return * the Unit value. */ - final def setSlotStable(slot: Slot): IO[RedisError, Unit] = { - val command = - RedisCommand(ClusterSetSlots, Tuple2(LongInput, ArbitraryValueInput[String]()), UnitOutput, codec, executor) - command.run((slot.number, Stable.stringify)) - } + + final def setSlotStable(slot: Slot): IO[RedisError, Unit] = _setSlotStable.run((slot.number, Stable.stringify)) /** * Set a hash slot in migrating state. Command should be executed on the node from which hash slot will be imported @@ -73,16 +62,8 @@ trait Cluster extends RedisEnvironment { * @return * the Unit value. */ - final def setSlotMigrating(slot: Slot, nodeId: String): IO[RedisError, Unit] = { - val command = RedisCommand( - ClusterSetSlots, - Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), - UnitOutput, - codec, - executor - ) - command.run((slot.number, Migrating.stringify, nodeId)) - } + final def setSlotMigrating(slot: Slot, nodeId: String): IO[RedisError, Unit] = + _setSlotMigrating.run((slot.number, Migrating.stringify, nodeId)) /** * Set a hash slot in importing state. Command should be executed on the node where hash slot will be migrated @@ -95,16 +76,9 @@ trait Cluster extends RedisEnvironment { * @return * the Unit value. */ - final def setSlotImporting(slot: Slot, nodeId: String): IO[RedisError, Unit] = { - val command = RedisCommand( - ClusterSetSlots, - Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), - UnitOutput, - codec, - executor - ) - command.run((slot.number, Importing.stringify, nodeId)) - } + + final def setSlotImporting(slot: Slot, nodeId: String): IO[RedisError, Unit] = + _setSlotImporting.run((slot.number, Importing.stringify, nodeId)) /** * Bind the hash slot to a different node. It associates the hash slot with the specified node, however the command @@ -117,23 +91,6 @@ trait Cluster extends RedisEnvironment { * @return * the Unit value. */ - final def setSlotNode(slot: Slot, nodeId: String): IO[RedisError, Unit] = { - val command = RedisCommand( - ClusterSetSlots, - Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), - UnitOutput, - codec, - executor - ) - command.run((slot.number, Node.stringify, nodeId)) - } -} - -private[redis] object Cluster { - final val Asking = "ASKING" - final val ClusterSlots = "CLUSTER SLOTS" - final val ClusterSetSlots = "CLUSTER SETSLOT" - - final val AskingCommand: (BinaryCodec, RedisExecutor) => RedisCommand[Unit, Unit] = - RedisCommand(Asking, NoInput, UnitOutput, _, _) + final def setSlotNode(slot: Slot, nodeId: String): IO[RedisError, Unit] = + _setSlotNode.run((slot.number, Node.stringify, nodeId)) } diff --git a/redis/src/main/scala/zio/redis/api/Connection.scala b/redis/src/main/scala/zio/redis/api/Connection.scala index 4191bee22..b95ca3f0c 100644 --- a/redis/src/main/scala/zio/redis/api/Connection.scala +++ b/redis/src/main/scala/zio/redis/api/Connection.scala @@ -17,12 +17,9 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis._ -trait Connection extends RedisEnvironment { - import Connection.{Auth => _, _} +trait Connection extends commands.Connection { /** * Authenticates the current connection to the server in two cases: @@ -36,11 +33,7 @@ trait Connection extends RedisEnvironment { * if the password provided via AUTH matches the password in the configuration file, the Unit value is returned and * the server starts accepting commands. Otherwise, an error is returned and the client needs to try a new password. */ - final def auth(password: String): IO[RedisError, Unit] = { - val command = RedisCommand(Connection.Auth, AuthInput, UnitOutput, codec, executor) - - command.run(Auth(None, password)) - } + final def auth(password: String): IO[RedisError, Unit] = _auth.run(Auth(None, password)) /** * Authenticates the current connection to the server using username and password. @@ -53,11 +46,7 @@ trait Connection extends RedisEnvironment { * if the password provided via AUTH matches the password in the configuration file, the Unit value is returned and * the server starts accepting commands. Otherwise, an error is returned and the client needs to try a new password. */ - final def auth(username: String, password: String): IO[RedisError, Unit] = { - val command = RedisCommand(Connection.Auth, AuthInput, UnitOutput, codec, executor) - - command.run(Auth(Some(username), password)) - } + final def auth(username: String, password: String): IO[RedisError, Unit] = _auth.run(Auth(Some(username), password)) /** * Controls the tracking of the keys in the next command executed by the connection, when tracking is enabled in Optin @@ -68,11 +57,7 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def clientCaching(track: Boolean): IO[RedisError, Unit] = { - val command = RedisCommand(ClientCaching, YesNoInput, UnitOutput, codec, executor) - - command.run(track) - } + final def clientCaching(track: Boolean): IO[RedisError, Unit] = _clientCaching.run(track) /** * Returns the ID of the current connection. Every connection ID has certain guarantees: @@ -84,11 +69,7 @@ trait Connection extends RedisEnvironment { * @return * the ID of the current connection. */ - final def clientId: IO[RedisError, Long] = { - val command = RedisCommand(ClientId, NoInput, LongOutput, codec, executor) - - command.run(()) - } + final def clientId: IO[RedisError, Long] = _clientId.run(()) /** * Closes a given client connection with the specified address @@ -98,11 +79,7 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def clientKill(address: Address): IO[RedisError, Unit] = { - val command = RedisCommand(ClientKill, AddressInput, UnitOutput, codec, executor) - - command.run(address) - } + final def clientKill(address: Address): IO[RedisError, Unit] = _clientKill.run(address) /** * Closes client connections with the specified filters.The following filters are available: @@ -124,11 +101,7 @@ trait Connection extends RedisEnvironment { * @return * the number of clients killed. */ - final def clientKill(filters: ClientKillFilter*): IO[RedisError, Long] = { - val command = RedisCommand(ClientKill, Varargs(ClientKillInput), LongOutput, codec, executor) - - command.run(filters) - } + final def clientKill(filters: ClientKillFilter*): IO[RedisError, Long] = _clientKillByFilter.run(filters) /** * Returns the name of the current connection as set by clientSetName @@ -136,11 +109,7 @@ trait Connection extends RedisEnvironment { * @return * the connection name, or None if a name wasn't set. */ - final def clientGetName: IO[RedisError, Option[String]] = { - val command = RedisCommand(ClientGetName, NoInput, OptionalOutput(MultiStringOutput), codec, executor) - - command.run(()) - } + final def clientGetName: IO[RedisError, Option[String]] = _clientGetName.run(()) /** * Returns the client ID we are redirecting our tracking notifications to @@ -148,22 +117,14 @@ trait Connection extends RedisEnvironment { * @return * the client ID if the tracking is enabled and the notifications are being redirected */ - final def clientGetRedir: IO[RedisError, ClientTrackingRedirect] = { - val command = RedisCommand(ClientGetRedir, NoInput, ClientTrackingRedirectOutput, codec, executor) - - command.run(()) - } + final def clientGetRedir: IO[RedisError, ClientTrackingRedirect] = _clientGetRedir.run(()) /** * Resumes command processing for all clients that were paused by clientPause * @return * the Unit value. */ - final def clientUnpause: IO[RedisError, Unit] = { - val command = RedisCommand(ClientUnpause, NoInput, UnitOutput, codec, executor) - - command.run(()) - } + final def clientUnpause: IO[RedisError, Unit] = _clientUnpause.run(()) /** * Able to suspend all the Redis clients for the specified amount of time (in milliseconds). Currently supports two @@ -178,20 +139,8 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def clientPause( - timeout: Duration, - mode: Option[ClientPauseMode] = None - ): IO[RedisError, Unit] = { - val command = RedisCommand( - ClientPause, - Tuple2(DurationMillisecondsInput, OptionalInput(ClientPauseModeInput)), - UnitOutput, - codec, - executor - ) - - command.run((timeout, mode)) - } + final def clientPause(timeout: Duration, mode: Option[ClientPauseMode] = None): IO[RedisError, Unit] = + _clientPause.run((timeout, mode)) /** * Assigns a name to the current connection @@ -201,11 +150,7 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def clientSetName(name: String): IO[RedisError, Unit] = { - val command = RedisCommand(ClientSetName, StringInput, UnitOutput, codec, executor) - - command.run(name) - } + final def clientSetName(name: String): IO[RedisError, Unit] = _clientSetName.run(name) /** * Enables the tracking feature of the Redis server, that is used for server assisted client side caching. The feature @@ -227,10 +172,7 @@ trait Connection extends RedisEnvironment { trackingMode: Option[ClientTrackingMode] = None, noLoop: Boolean = false, prefixes: Set[String] = Set.empty - ): IO[RedisError, Unit] = { - val command = RedisCommand(ClientTracking, ClientTrackingInput, UnitOutput, codec, executor) - command.run(Some((redirect, trackingMode, noLoop, Chunk.fromIterable(prefixes)))) - } + ): IO[RedisError, Unit] = _clientTrackingOn.run(Some((redirect, trackingMode, noLoop, Chunk.fromIterable(prefixes)))) /** * Disables the tracking feature of the Redis server, that is used for server assisted client side caching @@ -238,10 +180,7 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def clientTrackingOff: IO[RedisError, Unit] = { - val command = RedisCommand(ClientTracking, ClientTrackingInput, UnitOutput, codec, executor) - command.run(None) - } + final def clientTrackingOff: IO[RedisError, Unit] = _clientTrackingOff.run(None) /** * Returns information about the current client connection's use of the server assisted client side caching feature @@ -249,11 +188,7 @@ trait Connection extends RedisEnvironment { * @return * tracking information. */ - final def clientTrackingInfo: IO[RedisError, ClientTrackingInfo] = { - val command = RedisCommand(ClientTrackingInfo, NoInput, ClientTrackingInfoOutput, codec, executor) - - command.run(()) - } + final def clientTrackingInfo: IO[RedisError, ClientTrackingInfo] = _clientTrackingInfo.run(()) /** * Unblocks, from a different connection, a client blocked in a blocking operation @@ -265,15 +200,8 @@ trait Connection extends RedisEnvironment { * @return * true if the client was unblocked successfully, or false if the client wasn't unblocked. */ - final def clientUnblock( - clientId: Long, - error: Option[UnblockBehavior] = None - ): IO[RedisError, Boolean] = { - val command = - RedisCommand(ClientUnblock, Tuple2(LongInput, OptionalInput(UnblockBehaviorInput)), BoolOutput, codec, executor) - - command.run((clientId, error)) - } + final def clientUnblock(clientId: Long, error: Option[UnblockBehavior] = None): IO[RedisError, Boolean] = + _clientUnblock.run((clientId, error)) /** * Echoes the given string. @@ -283,11 +211,7 @@ trait Connection extends RedisEnvironment { * @return * the message. */ - final def echo(message: String): IO[RedisError, String] = { - val command = RedisCommand(Echo, StringInput, MultiStringOutput, codec, executor) - - command.run(message) - } + final def echo(message: String): IO[RedisError, String] = _echo.run(message) /** * Pings the server. @@ -298,11 +222,7 @@ trait Connection extends RedisEnvironment { * PONG if no argument is provided, otherwise return a copy of the argument as a bulk. This command is often used to * test if a connection is still alive, or to measure latency. */ - final def ping(message: Option[String] = None): IO[RedisError, String] = { - val command = RedisCommand(Ping, OptionalInput(StringInput), SingleOrMultiStringOutput, codec, executor) - - command.run(message) - } + final def ping(message: Option[String] = None): IO[RedisError, String] = _ping.run(message) /** * Ask the server to close the connection. The connection is closed as soon as all pending replies have been written @@ -311,11 +231,7 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def quit: IO[RedisError, Unit] = { - val command = RedisCommand(Quit, NoInput, UnitOutput, codec, executor) - - command.run(()) - } + final def quit: IO[RedisError, Unit] = _quit.run(()) /** * Performs a full reset of the connection's server-side context, mimicking the effects of disconnecting and @@ -324,11 +240,7 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def reset: IO[RedisError, Unit] = { - val command = RedisCommand(Reset, NoInput, ResetOutput, codec, executor) - - command.run(()) - } + final def reset: IO[RedisError, Unit] = _reset.run(()) /** * Changes the database for the current connection to the database having the specified numeric index. The currently @@ -340,29 +252,5 @@ trait Connection extends RedisEnvironment { * @return * the Unit value. */ - final def select(index: Long): IO[RedisError, Unit] = { - val command = RedisCommand(Select, LongInput, UnitOutput, codec, executor) - - command.run(index) - } -} - -private[redis] object Connection { - final val Auth = "AUTH" - final val ClientCaching = "CLIENT CACHING" - final val ClientId = "CLIENT ID" - final val ClientKill = "CLIENT KILL" - final val ClientGetName = "CLIENT GETNAME" - final val ClientGetRedir = "CLIENT GETREDIR" - final val ClientUnpause = "CLIENT UNPAUSE" - final val ClientPause = "CLIENT PAUSE" - final val ClientSetName = "CLIENT SETNAME" - final val ClientTracking = "CLIENT TRACKING" - final val ClientTrackingInfo = "CLIENT TRACKINGINFO" - final val ClientUnblock = "CLIENT UNBLOCK" - final val Echo = "ECHO" - final val Ping = "PING" - final val Quit = "QUIT" - final val Reset = "RESET" - final val Select = "SELECT" + final def select(index: Long): IO[RedisError, Unit] = _select.run(index) } diff --git a/redis/src/main/scala/zio/redis/api/Geo.scala b/redis/src/main/scala/zio/redis/api/Geo.scala index bf3fd5279..8e5cc1dab 100644 --- a/redis/src/main/scala/zio/redis/api/Geo.scala +++ b/redis/src/main/scala/zio/redis/api/Geo.scala @@ -17,13 +17,10 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis._ import zio.schema.Schema -trait Geo extends RedisEnvironment { - import Geo._ +trait Geo extends commands.Geo { /** * Adds the specified geospatial `items` (latitude, longitude, name) to the specified `key`. @@ -37,20 +34,8 @@ trait Geo extends RedisEnvironment { * @return * number of new elements added to the sorted set. */ - final def geoAdd[K: Schema, M: Schema]( - key: K, - item: (LongLat, M), - items: (LongLat, M)* - ): IO[RedisError, Long] = { - val command = RedisCommand( - GeoAdd, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(LongLatInput, ArbitraryValueInput[M]()))), - LongOutput, - codec, - executor - ) - command.run((key, (item, items.toList))) - } + final def geoAdd[K: Schema, M: Schema](key: K, item: (LongLat, M), items: (LongLat, M)*): IO[RedisError, Long] = + _geoAdd[K, M].run((key, (item, items.toList))) /** * Return the distance between two members in the geospatial index represented by the sorted set. @@ -71,21 +56,7 @@ trait Geo extends RedisEnvironment { member1: M, member2: M, radiusUnit: Option[RadiusUnit] = None - ): IO[RedisError, Option[Double]] = { - val command = RedisCommand( - GeoDist, - Tuple4( - ArbitraryKeyInput[K](), - ArbitraryValueInput[M](), - ArbitraryValueInput[M](), - OptionalInput(RadiusUnitInput) - ), - OptionalOutput(DoubleOutput), - codec, - executor - ) - command.run((key, member1, member2, radiusUnit)) - } + ): IO[RedisError, Option[Double]] = _geoDist[K, M].run((key, member1, member2, radiusUnit)) /** * Return valid Geohash strings representing the position of one or more elements in a sorted set value representing a @@ -100,20 +71,8 @@ trait Geo extends RedisEnvironment { * @return * chunk of geohashes, where value is `None` if a member is not in the set. */ - final def geoHash[K: Schema, M: Schema]( - key: K, - member: M, - members: M* - ): IO[RedisError, Chunk[Option[String]]] = { - val command = RedisCommand( - GeoHash, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), - ChunkOutput(OptionalOutput(MultiStringOutput)), - codec, - executor - ) - command.run((key, (member, members.toList))) - } + final def geoHash[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Chunk[Option[String]]] = + _geoHash[K, M].run((key, (member, members.toList))) /** * Return the positions (longitude, latitude) of all the specified members of the geospatial index represented by the @@ -128,21 +87,8 @@ trait Geo extends RedisEnvironment { * @return * chunk of positions, where value is `None` if a member is not in the set. */ - final def geoPos[K: Schema, M: Schema]( - key: K, - member: M, - members: M* - ): IO[RedisError, Chunk[Option[LongLat]]] = { - val command = - RedisCommand( - GeoPos, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), - GeoOutput, - codec, - executor - ) - command.run((key, (member, members.toList))) - } + final def geoPos[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Chunk[Option[LongLat]]] = + _geoPos[K, M].run((key, (member, members.toList))) /** * Return geospatial members of a sorted set which are within the area specified with a *center location* and the @@ -179,26 +125,8 @@ trait Geo extends RedisEnvironment { withHash: Option[WithHash] = None, count: Option[Count] = None, order: Option[Order] = None - ): IO[RedisError, Chunk[GeoView]] = { - val command = RedisCommand( - GeoRadius, - Tuple9( - ArbitraryKeyInput[K](), - LongLatInput, - DoubleInput, - RadiusUnitInput, - OptionalInput(WithCoordInput), - OptionalInput(WithDistInput), - OptionalInput(WithHashInput), - OptionalInput(CountInput), - OptionalInput(OrderInput) - ), - GeoRadiusOutput, - codec, - executor - ) - command.run((key, center, radius, radiusUnit, withCoord, withDist, withHash, count, order)) - } + ): IO[RedisError, Chunk[GeoView]] = + _geoRadius[K].run((key, center, radius, radiusUnit, withCoord, withDist, withHash, count, order)) /** * Similar to geoRadius, but store the results to the argument passed to store and return the number of elements @@ -242,30 +170,10 @@ trait Geo extends RedisEnvironment { withHash: Option[WithHash] = None, count: Option[Count] = None, order: Option[Order] = None - ): IO[RedisError, Long] = { - val command = RedisCommand( - GeoRadius, - Tuple11( - ArbitraryKeyInput[K](), - LongLatInput, - DoubleInput, - RadiusUnitInput, - OptionalInput(WithCoordInput), - OptionalInput(WithDistInput), - OptionalInput(WithHashInput), - OptionalInput(CountInput), - OptionalInput(OrderInput), - OptionalInput(StoreInput), - OptionalInput(StoreDistInput) - ), - LongOutput, - codec, - executor - ) - command.run( + ): IO[RedisError, Long] = + _geoRadiusStore[K].run( (key, center, radius, radiusUnit, withCoord, withDist, withHash, count, order, store.store, store.storeDist) ) - } /** * Return geospatial members of a sorted set which are within the area specified with an *existing member* in the set @@ -302,26 +210,8 @@ trait Geo extends RedisEnvironment { withHash: Option[WithHash] = None, count: Option[Count] = None, order: Option[Order] = None - ): IO[RedisError, Chunk[GeoView]] = { - val command = RedisCommand( - GeoRadiusByMember, - Tuple9( - ArbitraryKeyInput[K](), - ArbitraryValueInput[M](), - DoubleInput, - RadiusUnitInput, - OptionalInput(WithCoordInput), - OptionalInput(WithDistInput), - OptionalInput(WithHashInput), - OptionalInput(CountInput), - OptionalInput(OrderInput) - ), - GeoRadiusOutput, - codec, - executor - ) - command.run((key, member, radius, radiusUnit, withCoord, withDist, withHash, count, order)) - } + ): IO[RedisError, Chunk[GeoView]] = + _geoRadiusByMember[K, M].run((key, member, radius, radiusUnit, withCoord, withDist, withHash, count, order)) /** * Similar to geoRadiusByMember, but store the results to the argument passed to store and return the number of @@ -365,37 +255,8 @@ trait Geo extends RedisEnvironment { withHash: Option[WithHash] = None, count: Option[Count] = None, order: Option[Order] = None - ): IO[RedisError, Long] = { - val command = RedisCommand( - GeoRadiusByMember, - Tuple11( - ArbitraryKeyInput[K](), - ArbitraryValueInput[M](), - DoubleInput, - RadiusUnitInput, - OptionalInput(WithCoordInput), - OptionalInput(WithDistInput), - OptionalInput(WithHashInput), - OptionalInput(CountInput), - OptionalInput(OrderInput), - OptionalInput(StoreInput), - OptionalInput(StoreDistInput) - ), - LongOutput, - codec, - executor - ) - command.run( + ): IO[RedisError, Long] = + _geoRadiusByMemberStore[K, M].run( (key, member, radius, radiusUnit, withCoord, withDist, withHash, count, order, store.store, store.storeDist) ) - } -} - -private[redis] object Geo { - final val GeoAdd = "GEOADD" - final val GeoDist = "GEODIST" - final val GeoHash = "GEOHASH" - final val GeoPos = "GEOPOS" - final val GeoRadius = "GEORADIUS" - final val GeoRadiusByMember = "GEORADIUSBYMEMBER" } diff --git a/redis/src/main/scala/zio/redis/api/Hashes.scala b/redis/src/main/scala/zio/redis/api/Hashes.scala index 202376e8a..c4df3bf20 100644 --- a/redis/src/main/scala/zio/redis/api/Hashes.scala +++ b/redis/src/main/scala/zio/redis/api/Hashes.scala @@ -17,14 +17,11 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder._ import zio.redis._ import zio.schema.Schema -trait Hashes extends RedisEnvironment { - import Hashes._ +trait Hashes extends commands.Hashes { /** * Removes the specified fields from the hash stored at `key`. @@ -38,17 +35,8 @@ trait Hashes extends RedisEnvironment { * @return * number of fields removed from the hash. */ - final def hDel[K: Schema, F: Schema](key: K, field: F, fields: F*): IO[RedisError, Long] = { - val command = - RedisCommand( - HDel, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[F]())), - LongOutput, - codec, - executor - ) - command.run((key, (field, fields.toList))) - } + final def hDel[K: Schema, F: Schema](key: K, field: F, fields: F*): IO[RedisError, Long] = + _hDel[K, F].run((key, (field, fields.toList))) /** * Returns if `field` is an existing field in the hash stored at `key`. @@ -60,11 +48,8 @@ trait Hashes extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), BoolOutput, codec, executor) - command.run((key, field)) - } + final def hExists[K: Schema, F: Schema](key: K, field: F): IO[RedisError, Boolean] = + _hExists[K, F].run((key, field)) /** * Returns the value associated with `field` in the hash stored at `key`. @@ -78,15 +63,7 @@ trait Hashes extends RedisEnvironment { */ final def hGet[K: Schema, F: Schema](key: K, field: F): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[V: Schema]: IO[RedisError, Option[V]] = - RedisCommand( - HGet, - Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), - OptionalOutput(ArbitraryOutput[V]()), - codec, - executor - ) - .run((key, field)) + def returning[V: Schema]: IO[RedisError, Option[V]] = _hGet[K, F, V].run((key, field)) } /** @@ -97,19 +74,10 @@ trait Hashes extends RedisEnvironment { * @return * map of `field -> value` pairs under the key. */ - final def hGetAll[K: Schema](key: K): ResultBuilder2[Map] = new ResultBuilder2[Map] { - def returning[F: Schema, V: Schema]: IO[RedisError, Map[F, V]] = { - val command = - RedisCommand( - HGetAll, - ArbitraryKeyInput[K](), - KeyValueOutput(ArbitraryOutput[F](), ArbitraryOutput[V]()), - codec, - executor - ) - command.run(key) + final def hGetAll[K: Schema](key: K): ResultBuilder2[Map] = + new ResultBuilder2[Map] { + def returning[F: Schema, V: Schema]: IO[RedisError, Map[F, V]] = _hGetAll[K, F, V].run(key) } - } /** * Increments the number stored at `field` in the hash stored at `key` by `increment`. If field does not exist the @@ -124,17 +92,8 @@ trait Hashes extends RedisEnvironment { * @return * integer value after incrementing, or error if the field is not an integer. */ - final def hIncrBy[K: Schema, F: Schema](key: K, field: F, increment: Long): IO[RedisError, Long] = { - val command = - RedisCommand( - HIncrBy, - Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), LongInput), - LongOutput, - codec, - executor - ) - command.run((key, field, increment)) - } + final def hIncrBy[K: Schema, F: Schema](key: K, field: F, increment: Long): IO[RedisError, Long] = + _hIncrBy[K, F].run((key, field, increment)) /** * Increment the specified `field` of a hash stored at `key`, and representing a floating point number by the @@ -149,21 +108,8 @@ trait Hashes extends RedisEnvironment { * @return * float value after incrementing, or error if the field is not a float. */ - final def hIncrByFloat[K: Schema, F: Schema]( - key: K, - field: F, - increment: Double - ): IO[RedisError, Double] = { - val command = - RedisCommand( - HIncrByFloat, - Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), DoubleInput), - DoubleOutput, - codec, - executor - ) - command.run((key, field, increment)) - } + final def hIncrByFloat[K: Schema, F: Schema](key: K, field: F, increment: Double): IO[RedisError, Double] = + _hIncrByFloat[K, F].run((key, field, increment)) /** * Returns all field names in the hash stored at `key`. @@ -175,8 +121,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, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[F]()), codec, executor).run(key) + def returning[F: Schema]: IO[RedisError, Chunk[F]] = _hKeys[K, F].run(key) } /** @@ -187,10 +132,7 @@ trait Hashes extends RedisEnvironment { * @return * number of fields. */ - final def hLen[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(HLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) - command.run(key) - } + final def hLen[K: Schema](key: K): IO[RedisError, Long] = _hLen[K].run(key) /** * Returns the values associated with the specified `fields` in the hash stored at `key`. @@ -210,16 +152,8 @@ trait Hashes extends RedisEnvironment { fields: F* ): ResultBuilder1[({ type lambda[x] = Chunk[Option[x]] })#lambda] = new ResultBuilder1[({ type lambda[x] = Chunk[Option[x]] })#lambda] { - def returning[V: Schema]: IO[RedisError, Chunk[Option[V]]] = { - val command = RedisCommand( - HmGet, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[F]())), - ChunkOutput(OptionalOutput(ArbitraryOutput[V]())), - codec, - executor - ) - command.run((key, (field, fields.toList))) - } + def returning[V: Schema]: IO[RedisError, Chunk[Option[V]]] = + _hmGet[K, F, V].run((key, (field, fields.toList))) } /** @@ -235,20 +169,8 @@ trait Hashes extends RedisEnvironment { * @return * unit if fields are successfully set. */ - final def hmSet[K: Schema, F: Schema, V: Schema]( - key: K, - pair: (F, V), - pairs: (F, V)* - ): IO[RedisError, Unit] = { - val command = RedisCommand( - HmSet, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(ArbitraryValueInput[F](), ArbitraryValueInput[V]()))), - UnitOutput, - codec, - executor - ) - command.run((key, (pair, pairs.toList))) - } + final def hmSet[K: Schema, F: Schema, V: Schema](key: K, pair: (F, V), pairs: (F, V)*): IO[RedisError, Unit] = + _hmSet[K, F, V].run((key, (pair, pairs.toList))) /** * Iterates `fields` of Hash types and their associated values using a cursor-based iterator @@ -271,16 +193,8 @@ trait Hashes extends RedisEnvironment { count: Option[Count] = None ): ResultBuilder2[({ type lambda[x, y] = (Long, Chunk[(x, y)]) })#lambda] = new ResultBuilder2[({ type lambda[x, y] = (Long, Chunk[(x, y)]) })#lambda] { - def returning[F: Schema, V: Schema]: IO[RedisError, (Long, Chunk[(F, V)])] = { - val command = RedisCommand( - HScan, - Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), - Tuple2Output(ArbitraryOutput[Long](), ChunkTuple2Output(ArbitraryOutput[F](), ArbitraryOutput[V]())), - codec, - executor - ) - command.run((key, cursor, pattern.map(Pattern(_)), count)) - } + def returning[F: Schema, V: Schema]: IO[RedisError, (Long, Chunk[(F, V)])] = + _hScan[K, F, V].run((key, cursor, pattern.map(Pattern(_)), count)) } /** @@ -295,20 +209,8 @@ trait Hashes extends RedisEnvironment { * @return * number of fields added. */ - final def hSet[K: Schema, F: Schema, V: Schema]( - key: K, - pair: (F, V), - pairs: (F, V)* - ): IO[RedisError, Long] = { - val command = RedisCommand( - HSet, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(ArbitraryValueInput[F](), ArbitraryValueInput[V]()))), - LongOutput, - codec, - executor - ) - command.run((key, (pair, pairs.toList))) - } + final def hSet[K: Schema, F: Schema, V: Schema](key: K, pair: (F, V), pairs: (F, V)*): IO[RedisError, Long] = + _hSet[K, F, V].run((key, (pair, pairs.toList))) /** * Sets `field` in the hash stored at `key` to `value`, only if `field` does not yet exist @@ -322,21 +224,8 @@ trait Hashes extends RedisEnvironment { * @return * true if `field` is a new field and value was set, otherwise false. */ - final def hSetNx[K: Schema, F: Schema, V: Schema]( - key: K, - field: F, - value: V - ): IO[RedisError, Boolean] = { - val command = - RedisCommand( - HSetNx, - Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), ArbitraryValueInput[V]()), - BoolOutput, - codec, - executor - ) - command.run((key, field, value)) - } + final def hSetNx[K: Schema, F: Schema, V: Schema](key: K, field: F, value: V): IO[RedisError, Boolean] = + _hSetNx[K, F, V].run((key, field, value)) /** * Returns the string length of the value associated with `field` in the hash stored at `key` @@ -348,11 +237,8 @@ trait Hashes extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), LongOutput, codec, executor) - command.run((key, field)) - } + final def hStrLen[K: Schema, F: Schema](key: K, field: F): IO[RedisError, Long] = + _hStrLen[K, F].run((key, field)) /** * Returns all values in the hash stored at `key` @@ -364,8 +250,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, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[V]()), codec, executor).run(key) + def returning[V: Schema]: IO[RedisError, Chunk[V]] = _hVals[K, V].run(key) } /** @@ -378,8 +263,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, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) + def returning[V: Schema]: IO[RedisError, Option[V]] = _hRandField[K, V].run(key) } /** @@ -398,34 +282,7 @@ trait Hashes extends RedisEnvironment { */ final def hRandField[K: Schema](key: K, count: Long, withValues: Boolean = false): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[V: Schema]: IO[RedisError, Chunk[V]] = { - val command = RedisCommand( - HRandField, - Tuple3(ArbitraryKeyInput[K](), LongInput, OptionalInput(StringInput)), - ChunkOutput(ArbitraryOutput[V]()), - codec, - executor - ) - command.run((key, count, if (withValues) Some("WITHVALUES") else None)) - } + def returning[V: Schema]: IO[RedisError, Chunk[V]] = + _hRandFieldWithCount[K, V].run((key, count, if (withValues) Some("WITHVALUES") else None)) } } - -private[redis] object Hashes { - final val HDel = "HDEL" - final val HExists = "HEXISTS" - final val HGet = "HGET" - final val HGetAll = "HGETALL" - final val HIncrBy = "HINCRBY" - final val HIncrByFloat = "HINCRBYFLOAT" - final val HKeys = "HKEYS" - final val HLen = "HLEN" - final val HmGet = "HMGET" - final val HmSet = "HMSET" - final val HScan = "HSCAN" - final val HSet = "HSET" - final val HSetNx = "HSETNX" - final val HStrLen = "HSTRLEN" - final val HVals = "HVALS" - final val HRandField = "HRANDFIELD" -} diff --git a/redis/src/main/scala/zio/redis/api/HyperLogLog.scala b/redis/src/main/scala/zio/redis/api/HyperLogLog.scala index 928973afa..91232150d 100644 --- a/redis/src/main/scala/zio/redis/api/HyperLogLog.scala +++ b/redis/src/main/scala/zio/redis/api/HyperLogLog.scala @@ -17,13 +17,10 @@ package zio.redis.api import zio.IO -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis._ import zio.schema.Schema -trait HyperLogLog extends RedisEnvironment { - import HyperLogLog._ +trait HyperLogLog extends commands.HyperLogLog { /** * Adds the specified elements to the specified HyperLogLog. @@ -37,17 +34,8 @@ trait HyperLogLog extends RedisEnvironment { * @return * boolean indicating if at least 1 HyperLogLog register was altered. */ - final def pfAdd[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Boolean] = { - val command = - RedisCommand( - PfAdd, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), - BoolOutput, - codec, - executor - ) - command.run((key, (element, elements.toList))) - } + final def pfAdd[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Boolean] = + _pfAdd[K, V].run((key, (element, elements.toList))) /** * Return the approximated cardinality of the set(s) observed by the HyperLogLog at key(s). @@ -59,10 +47,7 @@ trait HyperLogLog extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K]()), LongOutput, codec, executor) - command.run((key, keys.toList)) - } + final def pfCount[K: Schema](key: K, keys: K*): IO[RedisError, Long] = _pfCount[K].run((key, keys.toList)) /** * Merge N different HyperLogLogs into a single one. @@ -74,21 +59,6 @@ trait HyperLogLog extends RedisEnvironment { * @param sourceKeys * additional keys to merge */ - final def pfMerge[K: Schema](destKey: K, sourceKey: K, sourceKeys: K*): IO[RedisError, Unit] = { - val command = - RedisCommand( - PfMerge, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryKeyInput[K]())), - UnitOutput, - codec, - executor - ) - command.run((destKey, (sourceKey, sourceKeys.toList))) - } -} - -private[redis] object HyperLogLog { - final val PfAdd = "PFADD" - final val PfCount = "PFCOUNT" - final val PfMerge = "PFMERGE" + final def pfMerge[K: Schema](destKey: K, sourceKey: K, sourceKeys: K*): IO[RedisError, Unit] = + _pfMerge[K].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 bc20959ba..e3efebbb6 100644 --- a/redis/src/main/scala/zio/redis/api/Keys.scala +++ b/redis/src/main/scala/zio/redis/api/Keys.scala @@ -17,16 +17,13 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder._ import zio.redis._ import zio.schema.Schema import java.time.Instant -trait Keys extends RedisEnvironment { - import Keys.{Keys => _, _} +trait Keys extends commands.Keys { /** * Removes the specified keys. A key is ignored if it does not exist. @@ -41,10 +38,7 @@ trait Keys extends RedisEnvironment { * @see * [[unlink]] */ - final def del[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Del, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) - command.run((key, keys.toList)) - } + final def del[K: Schema](key: K, keys: K*): IO[RedisError, Long] = _del[K].run((key, keys.toList)) /** * Serialize the value stored at key in a Redis-specific format and return it to the user. @@ -54,10 +48,7 @@ trait Keys extends RedisEnvironment { * @return * bytes for value stored at key. */ - final def dump[K: Schema](key: K): IO[RedisError, Chunk[Byte]] = { - val command = RedisCommand(Dump, ArbitraryKeyInput[K](), BulkStringOutput, codec, executor) - command.run(key) - } + final def dump[K: Schema](key: K): IO[RedisError, Chunk[Byte]] = _dump[K].run(key) /** * The number of keys existing among the ones specified as arguments. Keys mentioned multiple times and existing are @@ -70,10 +61,7 @@ trait Keys extends RedisEnvironment { * @return * The number of keys existing. */ - final def exists[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Exists, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) - command.run((key, keys.toList)) - } + final def exists[K: Schema](key: K, keys: K*): IO[RedisError, Long] = _exists[K].run((key, keys.toList)) /** * Set a timeout on key. After the timeout has expired, the key will automatically be deleted. @@ -88,11 +76,7 @@ trait Keys extends RedisEnvironment { * @see * [[expireAt]] */ - final def expire[K: Schema](key: K, timeout: Duration): IO[RedisError, Boolean] = { - val command = - RedisCommand(Expire, Tuple2(ArbitraryKeyInput[K](), DurationSecondsInput), BoolOutput, codec, executor) - command.run((key, timeout)) - } + final def expire[K: Schema](key: K, timeout: Duration): IO[RedisError, Boolean] = _expire[K].run((key, timeout)) /** * Deletes the key at the specific timestamp. A timestamp in the past will delete the key immediately. @@ -107,10 +91,8 @@ trait Keys extends RedisEnvironment { * @see * [[expire]] */ - final def expireAt[K: Schema](key: K, timestamp: Instant): IO[RedisError, Boolean] = { - val command = RedisCommand(ExpireAt, Tuple2(ArbitraryKeyInput[K](), TimeSecondsInput), BoolOutput, codec, executor) - command.run((key, timestamp)) - } + final def expireAt[K: Schema](key: K, timestamp: Instant): IO[RedisError, Boolean] = + _expireAt[K].run((key, timestamp)) /** * Returns all keys matching pattern. @@ -122,8 +104,7 @@ trait Keys extends RedisEnvironment { */ final def keys(pattern: String): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[V: Schema]: IO[RedisError, Chunk[V]] = - RedisCommand(Keys.Keys, StringInput, ChunkOutput(ArbitraryOutput[V]()), codec, executor).run(pattern) + def returning[V: Schema]: IO[RedisError, Chunk[V]] = _keys[V].run(pattern) } /** @@ -161,26 +142,8 @@ trait Keys extends RedisEnvironment { copy: Option[Copy] = None, replace: Option[Replace] = None, keys: Option[(K, List[K])] - ): IO[RedisError, String] = { - val command = RedisCommand( - Migrate, - Tuple9( - StringInput, - LongInput, - ArbitraryKeyInput[K](), - LongInput, - LongInput, - OptionalInput(CopyInput), - OptionalInput(ReplaceInput), - OptionalInput(AuthInput), - OptionalInput(NonEmptyList(ArbitraryKeyInput[K]())) - ), - StringOutput, - codec, - executor - ) - command.run((host, port, key, destinationDb, timeout.toMillis, copy, replace, auth, keys)) - } + ): IO[RedisError, String] = + _migrate[K].run((host, port, key, destinationDb, timeout.toMillis, copy, replace, auth, keys)) /** * Move key from the currently selected database to the specified destination database. When key already exists in the @@ -193,10 +156,8 @@ trait Keys extends RedisEnvironment { * @return * true if the key was moved. */ - final def move[K: Schema](key: K, destinationDb: Long): IO[RedisError, Boolean] = { - val command = RedisCommand(Move, Tuple2(ArbitraryKeyInput[K](), LongInput), BoolOutput, codec, executor) - command.run((key, destinationDb)) - } + final def move[K: Schema](key: K, destinationDb: Long): IO[RedisError, Boolean] = + _move[K].run((key, destinationDb)) /** * Remove the existing timeout on key. @@ -206,10 +167,7 @@ trait Keys extends RedisEnvironment { * @return * 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, ArbitraryKeyInput[K](), BoolOutput, codec, executor) - command.run(key) - } + final def persist[K: Schema](key: K): IO[RedisError, Boolean] = _persist[K].run(key) /** * Set a timeout on key. After the timeout has expired, the key will automatically be deleted. @@ -224,11 +182,8 @@ trait Keys extends RedisEnvironment { * @see * [[pExpireAt]] */ - final def pExpire[K: Schema](key: K, timeout: Duration): IO[RedisError, Boolean] = { - val command = - RedisCommand(PExpire, Tuple2(ArbitraryKeyInput[K](), DurationMillisecondsInput), BoolOutput, codec, executor) - command.run((key, timeout)) - } + final def pExpire[K: Schema](key: K, timeout: Duration): IO[RedisError, Boolean] = + _pExpire[K].run((key, timeout)) /** * Deletes the key at the specific timestamp. A timestamp in the past will delete the key immediately. @@ -243,11 +198,8 @@ trait Keys extends RedisEnvironment { * @see * [[pExpire]] */ - final def pExpireAt[K: Schema](key: K, timestamp: Instant): IO[RedisError, Boolean] = { - val command = - RedisCommand(PExpireAt, Tuple2(ArbitraryKeyInput[K](), TimeMillisecondsInput), BoolOutput, codec, executor) - command.run((key, timestamp)) - } + final def pExpireAt[K: Schema](key: K, timestamp: Instant): IO[RedisError, Boolean] = + _pExpireAt[K].run((key, timestamp)) /** * Returns the remaining time to live of a key that has a timeout. @@ -257,10 +209,7 @@ trait Keys extends RedisEnvironment { * @return * 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, ArbitraryKeyInput[K](), DurationMillisecondsOutput, codec, executor) - command.run(key) - } + final def pTtl[K: Schema](key: K): IO[RedisError, Duration] = _pTtl[K].run(key) /** * Return a random key from the currently selected database. @@ -270,8 +219,7 @@ trait Keys extends RedisEnvironment { */ final def randomKey: ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[V: Schema]: IO[RedisError, Option[V]] = - RedisCommand(RandomKey, NoInput, OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(()) + def returning[V: Schema]: IO[RedisError, Option[V]] = _randomKey[V].run(()) } /** @@ -284,11 +232,7 @@ trait Keys extends RedisEnvironment { * @return * unit if successful, error otherwise. */ - final def rename[K: Schema](key: K, newKey: K): IO[RedisError, Unit] = { - val command = - RedisCommand(Rename, Tuple2(ArbitraryKeyInput[K](), ArbitraryKeyInput[K]()), UnitOutput, codec, executor) - command.run((key, newKey)) - } + final def rename[K: Schema](key: K, newKey: K): IO[RedisError, Unit] = _rename[K].run((key, newKey)) /** * Renames key to newKey if newKey does not yet exist. It returns an error when key does not exist. @@ -300,11 +244,7 @@ trait Keys extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), ArbitraryKeyInput[K]()), BoolOutput, codec, executor) - command.run((key, newKey)) - } + final def renameNx[K: Schema](key: K, newKey: K): IO[RedisError, Boolean] = _renameNx[K].run((key, newKey)) /** * Create a key associated with a value that is obtained by deserializing the provided serialized value. Error when @@ -336,24 +276,7 @@ trait Keys extends RedisEnvironment { absTtl: Option[AbsTtl] = None, idleTime: Option[IdleTime] = None, freq: Option[Freq] = None - ): IO[RedisError, Unit] = { - val command = RedisCommand( - Restore, - Tuple7( - ArbitraryKeyInput[K](), - LongInput, - ValueInput, - OptionalInput(ReplaceInput), - OptionalInput(AbsTtlInput), - OptionalInput(IdleTimeInput), - OptionalInput(FreqInput) - ), - UnitOutput, - codec, - executor - ) - command.run((key, ttl, value, replace, absTtl, idleTime, freq)) - } + ): IO[RedisError, Unit] = _restore[K].run((key, ttl, value, replace, absTtl, idleTime, freq)) /** * Iterates the set of keys in the currently selected Redis database. An iteration starts when the cursor is set to 0, @@ -378,16 +301,8 @@ trait Keys extends RedisEnvironment { `type`: Option[RedisType] = None ): ResultBuilder1[({ type lambda[x] = (Long, Chunk[x]) })#lambda] = new ResultBuilder1[({ type lambda[x] = (Long, Chunk[x]) })#lambda] { - def returning[K: Schema]: IO[RedisError, (Long, Chunk[K])] = { - val command = RedisCommand( - Scan, - Tuple4(LongInput, OptionalInput(PatternInput), OptionalInput(CountInput), OptionalInput(RedisTypeInput)), - Tuple2Output(ArbitraryOutput[Long](), ChunkOutput(ArbitraryOutput[K]())), - codec, - executor - ) - command.run((cursor, pattern.map(Pattern(_)), count, `type`)) - } + def returning[K: Schema]: IO[RedisError, (Long, Chunk[K])] = + _scan[K].run((cursor, pattern.map(Pattern(_)), count, `type`)) } /** @@ -417,23 +332,8 @@ trait Keys extends RedisEnvironment { alpha: Option[Alpha] = None ): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[V: Schema]: IO[RedisError, Chunk[V]] = { - val command = RedisCommand( - Sort, - Tuple6( - ArbitraryKeyInput[K](), - OptionalInput(ByInput), - OptionalInput(LimitInput), - OptionalInput(NonEmptyList(GetInput)), - OrderInput, - OptionalInput(AlphaInput) - ), - ChunkOutput(ArbitraryOutput[V]()), - codec, - executor - ) - command.run((key, by, limit, get, order, alpha)) - } + def returning[V: Schema]: IO[RedisError, Chunk[V]] = + _sort[K, V].run((key, by, limit, get, order, alpha)) } /** @@ -468,24 +368,7 @@ trait Keys extends RedisEnvironment { order: Order = Order.Ascending, get: Option[(String, List[String])] = None, alpha: Option[Alpha] = None - ): IO[RedisError, Long] = { - val command = RedisCommand( - SortStore, - Tuple7( - ArbitraryKeyInput[K](), - OptionalInput(ByInput), - OptionalInput(LimitInput), - OptionalInput(NonEmptyList(GetInput)), - OrderInput, - OptionalInput(AlphaInput), - StoreInput - ), - LongOutput, - codec, - executor - ) - command.run((key, by, limit, get, order, alpha, storeAt)) - } + ): IO[RedisError, Long] = _sortStore[K].run((key, by, limit, get, order, alpha, storeAt)) /** * Alters the last access time of a key(s). A key is ignored if it does not exist. @@ -497,10 +380,7 @@ trait Keys extends RedisEnvironment { * @return * The number of keys that were touched. */ - final def touch[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Touch, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) - command.run((key, keys.toList)) - } + final def touch[K: Schema](key: K, keys: K*): IO[RedisError, Long] = _touch[K].run((key, keys.toList)) /** * Returns the remaining time to live of a key that has a timeout. @@ -510,10 +390,7 @@ trait Keys extends RedisEnvironment { * @return * 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, ArbitraryKeyInput[K](), DurationSecondsOutput, codec, executor) - command.run(key) - } + final def ttl[K: Schema](key: K): IO[RedisError, Duration] = _ttl[K].run(key) /** * Returns the string representation of the type of the value stored at key. @@ -523,10 +400,7 @@ trait Keys extends RedisEnvironment { * @return * type of the value stored at key. */ - final def typeOf[K: Schema](key: K): IO[RedisError, RedisType] = { - val command = RedisCommand(TypeOf, ArbitraryKeyInput[K](), TypeOutput, codec, executor) - command.run(key) - } + final def typeOf[K: Schema](key: K): IO[RedisError, RedisType] = _typeOf[K].run(key) /** * Removes the specified keys. A key is ignored if it does not exist. The command performs the actual memory @@ -542,10 +416,7 @@ trait Keys extends RedisEnvironment { * @see * [[del]] */ - final def unlink[K: Schema](key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand(Unlink, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) - command.run((key, keys.toList)) - } + final def unlink[K: Schema](key: K, keys: K*): IO[RedisError, Long] = _unlink[K].run((key, keys.toList)) /** * This command blocks the current client until all the previous write commands are successfully transferred and @@ -558,35 +429,5 @@ trait Keys extends RedisEnvironment { * @return * the number of replicas reached both in case of failure and success. */ - final def wait_(replicas: Long, timeout: Duration): IO[RedisError, Long] = { - val command = RedisCommand(Wait, Tuple2(LongInput, LongInput), LongOutput, codec, executor) - command.run((replicas, timeout.toMillis)) - } -} - -private[redis] object Keys { - final val Del = "DEL" - final val Dump = "DUMP" - final val Exists = "EXISTS" - final val Expire = "EXPIRE" - final val ExpireAt = "EXPIREAT" - final val Keys = "KEYS" - final val Migrate = "MIGRATE" - final val Move = "MOVE" - final val Persist = "PERSIST" - final val PExpire = "PEXPIRE" - final val PExpireAt = "PEXPIREAT" - final val PTtl = "PTTL" - final val RandomKey = "RANDOMKEY" - final val Rename = "RENAME" - final val RenameNx = "RENAMENX" - final val Restore = "RESTORE" - final val Scan = "SCAN" - final val Sort = "SORT" - final val SortStore = "SORT" - final val Touch = "TOUCH" - final val Ttl = "TTL" - final val TypeOf = "TYPE" - final val Unlink = "UNLINK" - final val Wait = "WAIT" + final def wait_(replicas: Long, timeout: Duration): IO[RedisError, Long] = _wait.run((replicas, timeout.toMillis)) } diff --git a/redis/src/main/scala/zio/redis/api/Lists.scala b/redis/src/main/scala/zio/redis/api/Lists.scala index ab9421e2e..9a14871d7 100644 --- a/redis/src/main/scala/zio/redis/api/Lists.scala +++ b/redis/src/main/scala/zio/redis/api/Lists.scala @@ -17,14 +17,11 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder._ import zio.redis._ import zio.schema.Schema -trait Lists extends RedisEnvironment { - import Lists._ +trait Lists extends commands.Lists { /** * Pops an element from the list stored at source, pushes it to the list stored at destination; or block until one is @@ -40,23 +37,10 @@ trait Lists extends RedisEnvironment { * the element being popped from source and pushed to destination. If timeout is reached, an empty reply is * returned. */ - final def brPopLPush[S: Schema, D: Schema]( - source: S, - destination: D, - timeout: Duration - ): ResultBuilder1[Option] = + final def brPopLPush[S: Schema, D: Schema](source: S, destination: D, timeout: Duration): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[V: Schema]: IO[RedisError, Option[V]] = { - val command = RedisCommand( - BrPopLPush, - Tuple3(ArbitraryValueInput[S](), ArbitraryValueInput[D](), DurationSecondsInput), - OptionalOutput(ArbitraryOutput[V]()), - codec, - executor - ) - - command.run((source, destination, timeout)) - } + def returning[V: Schema]: IO[RedisError, Option[V]] = + _brPopLPush[S, D, V].run((source, destination, timeout)) } /** @@ -72,15 +56,7 @@ trait Lists extends RedisEnvironment { */ final def lIndex[K: Schema](key: K, index: Long): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[V: Schema]: IO[RedisError, Option[V]] = - RedisCommand( - LIndex, - Tuple2(ArbitraryKeyInput[K](), LongInput), - OptionalOutput(ArbitraryOutput[V]()), - codec, - executor - ) - .run((key, index)) + def returning[V: Schema]: IO[RedisError, Option[V]] = _lIndex[K, V].run((key, index)) } /** @@ -91,10 +67,7 @@ trait Lists extends RedisEnvironment { * @return * the length of the list at key. */ - final def lLen[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(LLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) - command.run(key) - } + final def lLen[K: Schema](key: K): IO[RedisError, Long] = _lLen[K].run(key) /** * Removes and returns the first element of the list stored at key. @@ -106,8 +79,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, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) + def returning[V: Schema]: IO[RedisError, Option[V]] = _lPop[K, V].run(key) } /** @@ -123,17 +95,8 @@ trait Lists extends RedisEnvironment { * @return * the length of the list after the push operation. */ - final def lPush[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { - val command = - RedisCommand( - LPush, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), - LongOutput, - codec, - executor - ) - command.run((key, (element, elements.toList))) - } + final def lPush[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = + _lPush[K, V].run((key, (element, elements.toList))) /** * Prepends an element to a list, only if the list exists. In contrary to [[zio.redis.api.Lists#lPush]], no operation @@ -148,17 +111,8 @@ trait Lists extends RedisEnvironment { * @return * the length of the list after the push operation. */ - final def lPushX[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { - val command = - RedisCommand( - LPushX, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), - LongOutput, - codec, - executor - ) - command.run((key, (element, elements.toList))) - } + final def lPushX[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = + _lPushX[K, V].run((key, (element, elements.toList))) /** * Gets a range of elements from the list stored at key. @@ -173,15 +127,7 @@ trait Lists extends RedisEnvironment { */ final def lRange[K: Schema](key: K, range: Range): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[V: Schema]: IO[RedisError, Chunk[V]] = - RedisCommand( - LRange, - Tuple2(ArbitraryKeyInput[K](), RangeInput), - ChunkOutput(ArbitraryOutput[V]()), - codec, - executor - ) - .run((key, range)) + def returning[V: Schema]: IO[RedisError, Chunk[V]] = _lRange[K, V].run((key, range)) } /** @@ -201,11 +147,8 @@ trait Lists extends RedisEnvironment { * @return * the number of removed elements. */ - final def lRem[K: Schema](key: K, count: Long, element: String): IO[RedisError, Long] = { - val command = - RedisCommand(LRem, Tuple3(ArbitraryKeyInput[K](), LongInput, StringInput), LongOutput, codec, executor) - command.run((key, count, element)) - } + final def lRem[K: Schema](key: K, count: Long, element: String): IO[RedisError, Long] = + _lRem[K].run((key, count, element)) /** * Sets the list element at index to element. @@ -219,17 +162,8 @@ trait Lists extends RedisEnvironment { * @return * the Unit value. */ - final def lSet[K: Schema, V: Schema](key: K, index: Long, element: V): IO[RedisError, Unit] = { - val command = - RedisCommand( - LSet, - Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[V]()), - UnitOutput, - codec, - executor - ) - command.run((key, index, element)) - } + final def lSet[K: Schema, V: Schema](key: K, index: Long, element: V): IO[RedisError, Unit] = + _lSet[K, V].run((key, index, element)) /** * Trims an existing list so that it will contain only the specified range of elements. @@ -242,10 +176,7 @@ trait Lists extends RedisEnvironment { * @return * the Unit value. */ - final def lTrim[K: Schema](key: K, range: Range): IO[RedisError, Unit] = { - val command = RedisCommand(LTrim, Tuple2(ArbitraryKeyInput[K](), RangeInput), UnitOutput, codec, executor) - command.run((key, range)) - } + final def lTrim[K: Schema](key: K, range: Range): IO[RedisError, Unit] = _lTrim[K].run((key, range)) /** * Removes and returns the last element in the list stored at key. @@ -257,8 +188,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, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor).run(key) + def returning[V: Schema]: IO[RedisError, Option[V]] = _rPop[K, V].run(key) } /** @@ -275,15 +205,7 @@ trait Lists extends RedisEnvironment { */ final def rPopLPush[S: Schema, D: Schema](source: S, destination: D): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[V: Schema]: IO[RedisError, Option[V]] = - RedisCommand( - RPopLPush, - Tuple2(ArbitraryValueInput[S](), ArbitraryValueInput[D]()), - OptionalOutput(ArbitraryOutput[V]()), - codec, - executor - ) - .run((source, destination)) + def returning[V: Schema]: IO[RedisError, Option[V]] = _rPopLPush[S, D, V].run((source, destination)) } /** @@ -299,17 +221,8 @@ trait Lists extends RedisEnvironment { * @return * the length of the list after the push operation. */ - final def rPush[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { - val command = - RedisCommand( - RPush, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), - LongOutput, - codec, - executor - ) - command.run((key, (element, elements.toList))) - } + final def rPush[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = + _rPush[K, V].run((key, (element, elements.toList))) /** * Appends on or multiple elements to the list stored at key, only if the list exists. In contrary to @@ -324,17 +237,8 @@ trait Lists extends RedisEnvironment { * @return * the length of the list after the push operation. */ - final def rPushX[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = { - val command = - RedisCommand( - RPushX, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), - LongOutput, - codec, - executor - ) - command.run((key, (element, elements.toList))) - } + final def rPushX[K: Schema, V: Schema](key: K, element: V, elements: V*): IO[RedisError, Long] = + _rPushX[K, V].run((key, (element, elements.toList))) /** * Removes and gets the first element in a list, or blocks until one is available. An element is popped from the head @@ -355,16 +259,8 @@ trait Lists extends RedisEnvironment { timeout: Duration ): ResultBuilder1[({ type lambda[x] = Option[(K, x)] })#lambda] = new ResultBuilder1[({ type lambda[x] = Option[(K, x)] })#lambda] { - def returning[V: Schema]: IO[RedisError, Option[(K, V)]] = { - val command = RedisCommand( - BlPop, - Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), - OptionalOutput(Tuple2Output(ArbitraryOutput[K](), ArbitraryOutput[V]())), - codec, - executor - ) - command.run(((key, keys.toList), timeout)) - } + def returning[V: Schema]: IO[RedisError, Option[(K, V)]] = + _blPop[K, V].run(((key, keys.toList), timeout)) } /** @@ -386,16 +282,8 @@ trait Lists extends RedisEnvironment { timeout: Duration ): ResultBuilder1[({ type lambda[x] = Option[(K, x)] })#lambda] = new ResultBuilder1[({ type lambda[x] = Option[(K, x)] })#lambda] { - def returning[V: Schema]: IO[RedisError, Option[(K, V)]] = { - val command = RedisCommand( - BrPop, - Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), - OptionalOutput(Tuple2Output(ArbitraryOutput[K](), ArbitraryOutput[V]())), - codec, - executor - ) - command.run(((key, keys.toList), timeout)) - } + def returning[V: Schema]: IO[RedisError, Option[(K, V)]] = + _brPop[K, V].run(((key, keys.toList), timeout)) } /** @@ -412,21 +300,8 @@ trait Lists extends RedisEnvironment { * @return * the length of the list after the insert operation, or -1 when the value pivot was not found. */ - final def lInsert[K: Schema, V: Schema]( - key: K, - position: Position, - pivot: V, - element: V - ): IO[RedisError, Long] = { - val command = RedisCommand( - LInsert, - Tuple4(ArbitraryKeyInput[K](), PositionInput, ArbitraryValueInput[V](), ArbitraryValueInput[V]()), - LongOutput, - codec, - executor - ) - command.run((key, position, pivot, element)) - } + final def lInsert[K: Schema, V: Schema](key: K, position: Position, pivot: V, element: V): IO[RedisError, Long] = + _lInsert[K, V].run((key, position, pivot, element)) /** * Atomically returns and removes the first/last element (head/tail depending on the wherefrom argument) of the list @@ -451,16 +326,8 @@ trait Lists extends RedisEnvironment { destinationSide: Side ): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[V: Schema]: IO[RedisError, Option[V]] = { - val command = RedisCommand( - LMove, - Tuple4(ArbitraryValueInput[S](), ArbitraryValueInput[D](), SideInput, SideInput), - OptionalOutput(ArbitraryOutput[V]()), - codec, - executor - ) - command.run((source, destination, sourceSide, destinationSide)) - } + def returning[V: Schema]: IO[RedisError, Option[V]] = + _lMove[S, D, V].run((source, destination, sourceSide, destinationSide)) } /** @@ -490,17 +357,8 @@ trait Lists extends RedisEnvironment { timeout: Duration ): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[V: Schema]: IO[RedisError, Option[V]] = { - val command = RedisCommand( - BlMove, - Tuple5(ArbitraryValueInput[S](), ArbitraryValueInput[D](), SideInput, SideInput, DurationSecondsInput), - OptionalOutput(ArbitraryOutput[V]()), - codec, - executor - ) - - command.run((source, destination, sourceSide, destinationSide, timeout)) - } + def returning[V: Schema]: IO[RedisError, Option[V]] = + _blMove[S, D, V].run((source, destination, sourceSide, destinationSide, timeout)) } /** @@ -524,22 +382,7 @@ trait Lists extends RedisEnvironment { element: V, rank: Option[Rank] = None, maxLen: Option[ListMaxLen] = None - ): IO[RedisError, Option[Long]] = { - val command = RedisCommand( - LPos, - Tuple4( - ArbitraryKeyInput[K](), - ArbitraryValueInput[V](), - OptionalInput(RankInput), - OptionalInput(ListMaxLenInput) - ), - OptionalOutput(LongOutput), - codec, - executor - ) - - command.run((key, element, rank, maxLen)) - } + ): IO[RedisError, Option[Long]] = _lPos[K, V].run((key, element, rank, maxLen)) /** * The command returns the index of matching elements inside a Redis list. By default, when no options are given, it @@ -565,45 +408,5 @@ trait Lists extends RedisEnvironment { count: Count, rank: Option[Rank] = None, maxLen: Option[ListMaxLen] = None - ): IO[RedisError, Chunk[Long]] = { - val command = RedisCommand( - LPos, - Tuple5( - ArbitraryKeyInput[K](), - ArbitraryValueInput[V](), - CountInput, - OptionalInput(RankInput), - OptionalInput(ListMaxLenInput) - ), - ChunkOutput(LongOutput), - codec, - executor - ) - - command.run((key, element, count, rank, maxLen)) - } -} - -private[redis] object Lists { - final val BrPopLPush = "BRPOPLPUSH" - final val LIndex = "LINDEX" - final val LLen = "LLEN" - final val LPop = "LPOP" - final val LPush = "LPUSH" - final val LPushX = "LPUSHX" - final val LRange = "LRANGE" - final val LRem = "LREM" - final val LSet = "LSET" - final val LTrim = "LTRIM" - final val RPop = "RPOP" - final val RPopLPush = "RPOPLPUSH" - final val RPush = "RPUSH" - final val RPushX = "RPUSHX" - final val BlPop = "BLPOP" - final val BrPop = "BRPOP" - final val LInsert = "LINSERT" - final val LMove = "LMOVE" - final val BlMove = "BLMOVE" - final val LPos = "LPOS" - final val LPosCount = "LPOS" + ): IO[RedisError, Chunk[Long]] = _lPosCount[K, V].run((key, element, count, rank, maxLen)) } diff --git a/redis/src/main/scala/zio/redis/api/Scripting.scala b/redis/src/main/scala/zio/redis/api/Scripting.scala index 4bfcc61ee..45a7860cd 100644 --- a/redis/src/main/scala/zio/redis/api/Scripting.scala +++ b/redis/src/main/scala/zio/redis/api/Scripting.scala @@ -17,13 +17,10 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder.ResultOutputBuilder import zio.redis._ -trait Scripting extends RedisEnvironment { - import Scripting._ +trait Scripting extends commands.Scripting { /** * Evaluates a Lua script. @@ -43,10 +40,7 @@ trait Scripting extends RedisEnvironment { keys: Chunk[K], args: Chunk[A] ): ResultOutputBuilder = new ResultOutputBuilder { - def returning[R: Output]: IO[RedisError, R] = { - val command = RedisCommand(Eval, EvalInput(Input[K], Input[A]), Output[R], codec, executor) - command.run((script, keys, args)) - } + def returning[R: Output]: IO[RedisError, R] = _eval[K, A, R].run((script, keys, args)) } /** @@ -68,10 +62,7 @@ trait Scripting extends RedisEnvironment { keys: Chunk[K], args: Chunk[A] ): ResultOutputBuilder = new ResultOutputBuilder { - def returning[R: Output]: IO[RedisError, R] = { - val command = RedisCommand(EvalSha, EvalInput(Input[K], Input[A]), Output[R], codec, executor) - command.run((sha1, keys, args)) - } + def returning[R: Output]: IO[RedisError, R] = _evalSha[K, A, R].run((sha1, keys, args)) } /** @@ -84,10 +75,7 @@ trait Scripting extends RedisEnvironment { * @return * the Unit value. */ - final def scriptDebug(mode: DebugMode): IO[RedisError, Unit] = { - val command = RedisCommand(ScriptDebug, ScriptDebugInput, UnitOutput, codec, executor) - command.run(mode) - } + final def scriptDebug(mode: DebugMode): IO[RedisError, Unit] = _scriptDebug.run(mode) /** * Checks existence of the scripts in the script cache. @@ -100,10 +88,8 @@ trait Scripting extends RedisEnvironment { * for every corresponding SHA1 digest of a script that actually exists in the script cache, an true is returned, * otherwise false is returned. */ - final def scriptExists(sha1: String, sha1s: String*): IO[RedisError, Chunk[Boolean]] = { - val command = RedisCommand(ScriptExists, NonEmptyList(StringInput), ChunkOutput(BoolOutput), codec, executor) - command.run((sha1, sha1s.toList)) - } + final def scriptExists(sha1: String, sha1s: String*): IO[RedisError, Chunk[Boolean]] = + _scriptExists.run((sha1, sha1s.toList)) /** * Remove all the scripts from the script cache. @@ -118,10 +104,7 @@ trait Scripting extends RedisEnvironment { * @return * the Unit value. */ - final def scriptFlush(mode: Option[FlushMode] = None): IO[RedisError, Unit] = { - val command = RedisCommand(ScriptFlush, OptionalInput(ScriptFlushInput), UnitOutput, codec, executor) - command.run(mode) - } + final def scriptFlush(mode: Option[FlushMode] = None): IO[RedisError, Unit] = _scriptFlush.run(mode) /** * Kill the currently executing [[zio.redis.api.Scripting.eval]] script, assuming no write operation was yet performed @@ -130,10 +113,7 @@ trait Scripting extends RedisEnvironment { * @return * the Unit value. */ - final def scriptKill: IO[RedisError, Unit] = { - val command = RedisCommand(ScriptKill, NoInput, UnitOutput, codec, executor) - command.run(()) - } + final def scriptKill: IO[RedisError, Unit] = _scriptKill.run(()) /** * Loads a script into the scripts cache. After the script is loaded into the script cache it could be evaluated using @@ -144,18 +124,5 @@ trait Scripting extends RedisEnvironment { * @return * the SHA1 digest of the script added into the script cache. */ - final def scriptLoad(script: String): IO[RedisError, String] = { - val command = RedisCommand(ScriptLoad, StringInput, MultiStringOutput, codec, executor) - command.run(script) - } -} - -private[redis] object Scripting { - final val Eval = "EVAL" - final val EvalSha = "EVALSHA" - final val ScriptDebug = "SCRIPT DEBUG" - final val ScriptExists = "SCRIPT EXISTS" - final val ScriptFlush = "SCRIPT FLUSH" - final val ScriptKill = "SCRIPT KILL" - final val ScriptLoad = "SCRIPT LOAD" + final def scriptLoad(script: String): IO[RedisError, String] = _scriptLoad.run(script) } diff --git a/redis/src/main/scala/zio/redis/api/Sets.scala b/redis/src/main/scala/zio/redis/api/Sets.scala index 83b726949..c465ebc52 100644 --- a/redis/src/main/scala/zio/redis/api/Sets.scala +++ b/redis/src/main/scala/zio/redis/api/Sets.scala @@ -17,14 +17,11 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder._ import zio.redis._ import zio.schema.Schema -trait Sets extends RedisEnvironment { - import Sets._ +trait Sets extends commands.Sets { /** * Add one or more members to a set. @@ -39,17 +36,8 @@ trait Sets extends RedisEnvironment { * Returns the number of elements that were added to the set, not including all the elements already present into * the set. */ - final def sAdd[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Long] = { - val command = - RedisCommand( - SAdd, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), - LongOutput, - codec, - executor - ) - command.run((key, (member, members.toList))) - } + final def sAdd[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Long] = + _sAdd[K, M].run((key, (member, members.toList))) /** * Get the number of members in a set. @@ -59,10 +47,7 @@ trait Sets extends RedisEnvironment { * @return * 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, ArbitraryKeyInput[K](), LongOutput, codec, executor) - command.run(key) - } + final def sCard[K: Schema](key: K): IO[RedisError, Long] = _sCard[K].run(key) /** * Subtract multiple sets. @@ -76,9 +61,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(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) - .run((key, keys.toList)) + def returning[R: Schema]: IO[RedisError, Chunk[R]] = _sDiff[K, R].run((key, keys.toList)) } /** @@ -93,16 +76,8 @@ trait Sets extends RedisEnvironment { * @return * Returns the number of elements in the resulting set. */ - final def sDiffStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): IO[RedisError, Long] = { - val command = RedisCommand( - SDiffStore, - Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), - LongOutput, - codec, - executor - ) - command.run((destination, (key, keys.toList))) - } + final def sDiffStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): IO[RedisError, Long] = + _sDiffStore[D, K].run((destination, (key, keys.toList))) /** * Intersect multiple sets and store the resulting set in a key. @@ -116,9 +91,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(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) - .run((destination, keys.toList)) + def returning[R: Schema]: IO[RedisError, Chunk[R]] = _sInter[K, R].run((destination, keys.toList)) } /** @@ -133,20 +106,8 @@ trait Sets extends RedisEnvironment { * @return * Returns the number of elements in the resulting set. */ - final def sInterStore[D: Schema, K: Schema]( - destination: D, - key: K, - keys: K* - ): IO[RedisError, Long] = { - val command = RedisCommand( - SInterStore, - Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), - LongOutput, - codec, - executor - ) - command.run((destination, (key, keys.toList))) - } + final def sInterStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): IO[RedisError, Long] = + _sInterStore[D, K].run((destination, (key, keys.toList))) /** * Determine if a given value is a member of a set. @@ -159,11 +120,8 @@ trait Sets extends RedisEnvironment { * Returns 1 if the element is a member of the set. 0 if the element is not a member of the set, or if key does not * exist. */ - final def sIsMember[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Boolean] = { - val command = - RedisCommand(SIsMember, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), BoolOutput, codec, executor) - command.run((key, member)) - } + final def sIsMember[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Boolean] = + _sIsMember[K, M].run((key, member)) /** * Get all the members in a set. @@ -175,8 +133,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, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[R]()), codec, executor).run(key) + def returning[R: Schema]: IO[RedisError, Chunk[R]] = _sMembers[K, R].run(key) } /** @@ -191,20 +148,8 @@ trait Sets extends RedisEnvironment { * @return * Returns 1 if the element was moved. 0 if it was not found. */ - final def sMove[S: Schema, D: Schema, M: Schema]( - source: S, - destination: D, - member: M - ): IO[RedisError, Boolean] = { - val command = RedisCommand( - SMove, - Tuple3(ArbitraryValueInput[S](), ArbitraryValueInput[D](), ArbitraryValueInput[M]()), - BoolOutput, - codec, - executor - ) - command.run((source, destination, member)) - } + final def sMove[S: Schema, D: Schema, M: Schema](source: S, destination: D, member: M): IO[RedisError, Boolean] = + _sMove[S, D, M].run((source, destination, member)) /** * Remove and return one or multiple random members from a set. @@ -218,16 +163,7 @@ trait Sets extends RedisEnvironment { */ final def sPop[K: Schema](key: K, count: Option[Long] = None): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[R: Schema]: IO[RedisError, Chunk[R]] = { - val command = RedisCommand( - SPop, - Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), - MultiStringChunkOutput(ArbitraryOutput[R]()), - codec, - executor - ) - command.run((key, count)) - } + def returning[R: Schema]: IO[RedisError, Chunk[R]] = _sPop[K, R].run((key, count)) } /** @@ -242,16 +178,7 @@ trait Sets extends RedisEnvironment { */ final def sRandMember[K: Schema](key: K, count: Option[Long] = None): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[R: Schema]: IO[RedisError, Chunk[R]] = { - val command = RedisCommand( - SRandMember, - Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), - MultiStringChunkOutput(ArbitraryOutput[R]()), - codec, - executor - ) - command.run((key, count)) - } + def returning[R: Schema]: IO[RedisError, Chunk[R]] = _sRandMember[K, R].run((key, count)) } /** @@ -266,17 +193,8 @@ trait Sets extends RedisEnvironment { * @return * Returns the number of members that were removed from the set, not including non existing members. */ - final def sRem[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Long] = { - val command = - RedisCommand( - SRem, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), - LongOutput, - codec, - executor - ) - command.run((key, (member, members.toList))) - } + final def sRem[K: Schema, M: Schema](key: K, member: M, members: M*): IO[RedisError, Long] = + _sRem[K, M].run((key, (member, members.toList))) /** * Incrementally iterate Set elements. @@ -302,16 +220,8 @@ trait Sets extends RedisEnvironment { count: Option[Count] = None ): ResultBuilder1[({ type lambda[x] = (Long, Chunk[x]) })#lambda] = new ResultBuilder1[({ type lambda[x] = (Long, Chunk[x]) })#lambda] { - def returning[R: Schema]: IO[RedisError, (Long, Chunk[R])] = { - val command = RedisCommand( - SScan, - Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), - Tuple2Output(MultiStringOutput.map(_.toLong), ChunkOutput(ArbitraryOutput[R]())), - codec, - executor - ) - command.run((key, cursor, pattern.map(Pattern(_)), count)) - } + def returning[R: Schema]: IO[RedisError, (Long, Chunk[R])] = + _sScan[K, R].run((key, cursor, pattern.map(Pattern(_)), count)) } /** @@ -326,9 +236,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(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) - .run((key, keys.toList)) + def returning[R: Schema]: IO[RedisError, Chunk[R]] = _sUnion[K, R].run((key, keys.toList)) } /** @@ -343,36 +251,6 @@ trait Sets extends RedisEnvironment { * @return * Returns the number of elements in the resulting set. */ - final def sUnionStore[D: Schema, K: Schema]( - destination: D, - key: K, - keys: K* - ): IO[RedisError, Long] = { - val command = RedisCommand( - SUnionStore, - Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), - LongOutput, - codec, - executor - ) - command.run((destination, (key, keys.toList))) - } -} - -private[redis] object Sets { - final val SAdd = "SADD" - final val SCard = "SCARD" - final val SDiff = "SDIFF" - final val SDiffStore = "SDIFFSTORE" - final val SInter = "SINTER" - final val SInterStore = "SINTERSTORE" - final val SIsMember = "SISMEMBER" - final val SMembers = "SMEMBERS" - final val SMove = "SMOVE" - final val SPop = "SPOP" - final val SRandMember = "SRANDMEMBER" - final val SRem = "SREM" - final val SScan = "SSCAN" - final val SUnion = "SUNION" - final val SUnionStore = "SUNIONSTORE" + final def sUnionStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): IO[RedisError, Long] = + _sUnionStore[D, K].run((destination, (key, keys.toList))) } diff --git a/redis/src/main/scala/zio/redis/api/SortedSets.scala b/redis/src/main/scala/zio/redis/api/SortedSets.scala index dd8b2b4e9..29b8ffd6f 100644 --- a/redis/src/main/scala/zio/redis/api/SortedSets.scala +++ b/redis/src/main/scala/zio/redis/api/SortedSets.scala @@ -17,14 +17,11 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder._ import zio.redis._ import zio.schema.Schema -trait SortedSets extends RedisEnvironment { - import SortedSets._ +trait SortedSets extends commands.SortedSets { /** * Remove and return the member with the highest score from one or more sorted sets, or block until one is available. @@ -46,20 +43,8 @@ trait SortedSets extends RedisEnvironment { keys: K* ): ResultBuilder1[({ type lambda[x] = Option[(K, MemberScore[x])] })#lambda] = new ResultBuilder1[({ type lambda[x] = Option[(K, MemberScore[x])] })#lambda] { - def returning[M: Schema]: IO[RedisError, Option[(K, MemberScore[M])]] = { - val memberScoreOutput = - Tuple3Output(ArbitraryOutput[K](), ArbitraryOutput[M](), DoubleOutput).map { case (k, m, s) => - (k, MemberScore(s, m)) - } - val command = RedisCommand( - BzPopMax, - Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), - OptionalOutput(memberScoreOutput), - codec, - executor - ) - command.run(((key, keys.toList), timeout)) - } + def returning[M: Schema]: IO[RedisError, Option[(K, MemberScore[M])]] = + _bzPopMax[K, M].run(((key, keys.toList), timeout)) } /** @@ -82,20 +67,8 @@ trait SortedSets extends RedisEnvironment { keys: K* ): ResultBuilder1[({ type lambda[x] = Option[(K, MemberScore[x])] })#lambda] = new ResultBuilder1[({ type lambda[x] = Option[(K, MemberScore[x])] })#lambda] { - def returning[M: Schema]: IO[RedisError, Option[(K, MemberScore[M])]] = { - val memberScoreOutput = - Tuple3Output(ArbitraryOutput[K](), ArbitraryOutput[M](), DoubleOutput).map { case (k, m, s) => - (k, MemberScore(s, m)) - } - val command = RedisCommand( - BzPopMin, - Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), - OptionalOutput(memberScoreOutput), - codec, - executor - ) - command.run(((key, keys.toList), timeout)) - } + def returning[M: Schema]: IO[RedisError, Option[(K, MemberScore[M])]] = + _bzPopMin[K, M].run(((key, keys.toList), timeout)) } /** @@ -118,21 +91,7 @@ trait SortedSets extends RedisEnvironment { final def zAdd[K: Schema, M: Schema](key: K, update: Option[Update] = None, change: Option[Changed] = None)( memberScore: MemberScore[M], memberScores: MemberScore[M]* - ): IO[RedisError, Long] = { - val command = RedisCommand( - ZAdd, - Tuple4( - ArbitraryKeyInput[K](), - OptionalInput(UpdateInput), - OptionalInput(ChangedInput), - NonEmptyList(MemberScoreInput[M]()) - ), - LongOutput, - codec, - executor - ) - command.run((key, update, change, (memberScore, memberScores.toList))) - } + ): IO[RedisError, Long] = _zAdd[K, M].run((key, update, change, (memberScore, memberScores.toList))) /** * Add one or more members to a sorted set, or update its score if it already exists. @@ -157,22 +116,8 @@ trait SortedSets extends RedisEnvironment { increment: Increment, memberScore: MemberScore[M], memberScores: MemberScore[M]* - ): IO[RedisError, Option[Double]] = { - val command = RedisCommand( - ZAdd, - Tuple5( - ArbitraryKeyInput[K](), - OptionalInput(UpdateInput), - OptionalInput(ChangedInput), - IncrementInput, - NonEmptyList(MemberScoreInput[M]()) - ), - OptionalOutput(DoubleOutput), - codec, - executor - ) - command.run((key, update, change, increment, (memberScore, memberScores.toList))) - } + ): IO[RedisError, Option[Double]] = + _zAddWithIncr[K, M].run((key, update, change, increment, (memberScore, memberScores.toList))) /** * Get the number of members in a sorted set. @@ -182,10 +127,7 @@ trait SortedSets extends RedisEnvironment { * @return * 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, ArbitraryKeyInput[K](), LongOutput, codec, executor) - command.run(key) - } + final def zCard[K: Schema](key: K): IO[RedisError, Long] = _zCard[K].run(key) /** * Returns the number of elements in the sorted set at key with a score between min and max. @@ -197,10 +139,7 @@ trait SortedSets extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), RangeInput), LongOutput, codec, executor) - command.run((key, range)) - } + final def zCount[K: Schema](key: K, range: Range): IO[RedisError, Long] = _zCount[K].run((key, range)) /** * Subtract multiple sorted sets and return members. @@ -214,26 +153,10 @@ trait SortedSets extends RedisEnvironment { * @return * Chunk of differences between the first and successive input sorted sets. */ - final def zDiff[K: Schema]( - inputKeysNum: Long, - key: K, - keys: K* - ): ResultBuilder1[Chunk] = + final def zDiff[K: Schema](inputKeysNum: Long, key: K, keys: K*): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = - RedisCommand( - ZDiff, - Tuple2( - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()) - ), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((inputKeysNum, (key, keys.toList))) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = + _zDiff[K, M].run((inputKeysNum, (key, keys.toList))) } /** @@ -254,22 +177,8 @@ trait SortedSets extends RedisEnvironment { keys: K* ): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = - RedisCommand( - ZDiff, - Tuple3( - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()), - ArbitraryValueInput[String]() - ), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((inputKeysNum, (key, keys.toList), WithScores.stringify)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = + _zDiffWithScores[K, M].run((inputKeysNum, (key, keys.toList), WithScores.stringify)) } /** @@ -291,21 +200,8 @@ trait SortedSets extends RedisEnvironment { inputKeysNum: Long, key: K, keys: K* - ): IO[RedisError, Long] = { - val command = - RedisCommand( - ZDiffStore, - Tuple3( - ArbitraryValueInput[DK](), - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()) - ), - LongOutput, - codec, - executor - ) - command.run((destination, inputKeysNum, (key, keys.toList))) - } + ): IO[RedisError, Long] = + _zDiffStore[DK, K].run((destination, inputKeysNum, (key, keys.toList))) /** * Increment the score of a member in a sorted set. @@ -319,21 +215,8 @@ trait SortedSets extends RedisEnvironment { * @return * The new score of member (a double precision floating point number). */ - final def zIncrBy[K: Schema, M: Schema]( - key: K, - increment: Long, - member: M - ): IO[RedisError, Double] = { - val command = - RedisCommand( - ZIncrBy, - Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[M]()), - DoubleOutput, - codec, - executor - ) - command.run((key, increment, member)) - } + final def zIncrBy[K: Schema, M: Schema](key: K, increment: Long, member: M): IO[RedisError, Double] = + _zIncrBy[K, M].run((key, increment, member)) /** * Intersect multiple sorted sets and return members. @@ -358,21 +241,8 @@ trait SortedSets extends RedisEnvironment { weights: Option[::[Double]] = None ): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZInter, - Tuple4( - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()), - OptionalInput(AggregateInput), - OptionalInput(WeightsInput) - ), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((inputKeysNum, (key, keys.toList), aggregate, weights)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = + _zInter[K, M].run((inputKeysNum, (key, keys.toList), aggregate, weights)) } /** @@ -398,23 +268,8 @@ trait SortedSets extends RedisEnvironment { weights: Option[::[Double]] = None ): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZInter, - Tuple5( - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()), - OptionalInput(AggregateInput), - OptionalInput(WeightsInput), - ArbitraryValueInput[String]() - ), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((inputKeysNum, (key, keys.toList), aggregate, weights, WithScores.stringify)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = + _zInterWithScores[K, M].run((inputKeysNum, (key, keys.toList), aggregate, weights, WithScores.stringify)) } /** @@ -440,22 +295,8 @@ trait SortedSets extends RedisEnvironment { final def zInterStore[DK: Schema, K: Schema](destination: DK, inputKeysNum: Long, key: K, keys: K*)( aggregate: Option[Aggregate] = None, weights: Option[::[Double]] = None - ): IO[RedisError, Long] = { - val command = RedisCommand( - ZInterStore, - Tuple5( - ArbitraryValueInput[DK](), - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()), - OptionalInput(AggregateInput), - OptionalInput(WeightsInput) - ), - LongOutput, - codec, - executor - ) - command.run((destination, inputKeysNum, (key, keys.toList), aggregate, weights)) - } + ): IO[RedisError, Long] = + _zInterStore[DK, K].run((destination, inputKeysNum, (key, keys.toList), aggregate, weights)) /** * Count the number of members in a sorted set between a given lexicographical range. @@ -467,16 +308,8 @@ trait SortedSets extends RedisEnvironment { * @return * The number of elements in the specified score range. */ - final def zLexCount[K: Schema](key: K, lexRange: LexRange): IO[RedisError, Long] = { - val command = RedisCommand( - ZLexCount, - Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), - LongOutput, - codec, - executor - ) - command.run((key, lexRange.min.stringify, lexRange.max.stringify)) - } + final def zLexCount[K: Schema](key: K, lexRange: LexRange): IO[RedisError, Long] = + _zLexCount[K].run((key, lexRange.min.stringify, lexRange.max.stringify)) /** * Remove and return members with the highest scores in a sorted set. @@ -490,22 +323,9 @@ trait SortedSets extends RedisEnvironment { * @return * Chunk of popped elements and scores. */ - final def zPopMax[K: Schema]( - key: K, - count: Option[Long] = None - ): ResultBuilder1[MemberScores] = + final def zPopMax[K: Schema](key: K, count: Option[Long] = None): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZPopMax, - Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((key, count)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = _zPopMax[K, M].run((key, count)) } /** @@ -520,22 +340,9 @@ trait SortedSets extends RedisEnvironment { * @return * Chunk of popped elements and scores. */ - final def zPopMin[K: Schema]( - key: K, - count: Option[Long] = None - ): ResultBuilder1[MemberScores] = + final def zPopMin[K: Schema](key: K, count: Option[Long] = None): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZPopMin, - Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((key, count)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = _zPopMin[K, M].run((key, count)) } /** @@ -550,16 +357,7 @@ trait SortedSets extends RedisEnvironment { */ final def zRange[K: Schema](key: K, range: Range): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZRange, - Tuple2(ArbitraryKeyInput[K](), RangeInput), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((key, range)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = _zRange[K, M].run((key, range)) } /** @@ -572,22 +370,10 @@ trait SortedSets extends RedisEnvironment { * @return * Chunk of elements with their scores in the specified range. */ - final def zRangeWithScores[K: Schema]( - key: K, - range: Range - ): ResultBuilder1[MemberScores] = + final def zRangeWithScores[K: Schema](key: K, range: Range): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZRange, - Tuple3(ArbitraryKeyInput[K](), RangeInput, ArbitraryValueInput[String]()), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((key, range, WithScores.stringify)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = + _zRangeWithScores[K, M].run((key, range, WithScores.stringify)) } /** @@ -603,27 +389,10 @@ trait SortedSets extends RedisEnvironment { * @return * Chunk of elements in the specified score range. */ - final def zRangeByLex[K: Schema]( - key: K, - lexRange: LexRange, - limit: Option[Limit] = None - ): ResultBuilder1[Chunk] = + final def zRangeByLex[K: Schema](key: K, lexRange: LexRange, limit: Option[Limit] = None): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZRangeByLex, - Tuple4( - ArbitraryKeyInput[K](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - OptionalInput(LimitInput) - ), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((key, lexRange.min.stringify, lexRange.max.stringify, limit)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = + _zRangeByLex[K, M].run((key, lexRange.min.stringify, lexRange.max.stringify, limit)) } /** @@ -645,21 +414,8 @@ trait SortedSets extends RedisEnvironment { limit: Option[Limit] = None ): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZRangeByScore, - Tuple4( - ArbitraryKeyInput[K](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - OptionalInput(LimitInput) - ), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((key, scoreRange.min.stringify, scoreRange.max.stringify, limit)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = + _zRangeByScore[K, M].run((key, scoreRange.min.stringify, scoreRange.max.stringify, limit)) } /** @@ -681,23 +437,9 @@ trait SortedSets extends RedisEnvironment { limit: Option[Limit] = None ): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZRangeByScore, - Tuple5( - ArbitraryKeyInput[K](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - OptionalInput(LimitInput) - ), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((key, scoreRange.min.stringify, scoreRange.max.stringify, WithScores.stringify, limit)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = _zRangeByScoreWithScores[K, M].run( + (key, scoreRange.min.stringify, scoreRange.max.stringify, WithScores.stringify, limit) + ) } /** @@ -710,17 +452,8 @@ trait SortedSets extends RedisEnvironment { * @return * The rank of member in the sorted set stored at key, with the scores ordered from low to high. */ - final def zRank[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Long]] = { - val command = - RedisCommand( - ZRank, - Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), - OptionalOutput(LongOutput), - codec, - executor - ) - command.run((key, member)) - } + final def zRank[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Long]] = + _zRank[K, M].run((key, member)) /** * Remove one or more members from a sorted set. @@ -734,21 +467,8 @@ trait SortedSets extends RedisEnvironment { * @return * The number of members removed from the sorted set, not including non existing members. */ - final def zRem[K: Schema, M: Schema]( - key: K, - firstMember: M, - restMembers: M* - ): IO[RedisError, Long] = { - val command = - RedisCommand( - ZRem, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), - LongOutput, - codec, - executor - ) - command.run((key, (firstMember, restMembers.toList))) - } + final def zRem[K: Schema, M: Schema](key: K, firstMember: M, restMembers: M*): IO[RedisError, Long] = + _zRem[K, M].run((key, (firstMember, restMembers.toList))) /** * Remove all members in a sorted set between the given lexicographical range. @@ -760,16 +480,8 @@ trait SortedSets extends RedisEnvironment { * @return * The number of elements removed. */ - final def zRemRangeByLex[K: Schema](key: K, lexRange: LexRange): IO[RedisError, Long] = { - val command = RedisCommand( - ZRemRangeByLex, - Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), - LongOutput, - codec, - executor - ) - command.run((key, lexRange.min.stringify, lexRange.max.stringify)) - } + final def zRemRangeByLex[K: Schema](key: K, lexRange: LexRange): IO[RedisError, Long] = + _zRemRangeByLex[K].run((key, lexRange.min.stringify, lexRange.max.stringify)) /** * Remove all members in a sorted set within the given indexes. @@ -781,10 +493,8 @@ trait SortedSets extends RedisEnvironment { * @return * The number of elements removed. */ - final def zRemRangeByRank[K: Schema](key: K, range: Range): IO[RedisError, Long] = { - val command = RedisCommand(ZRemRangeByRank, Tuple2(ArbitraryKeyInput[K](), RangeInput), LongOutput, codec, executor) - command.run((key, range)) - } + final def zRemRangeByRank[K: Schema](key: K, range: Range): IO[RedisError, Long] = + _zRemRangeByRank[K].run((key, range)) /** * Remove all members in a sorted set within the given scores. @@ -796,16 +506,8 @@ trait SortedSets extends RedisEnvironment { * @return * The number of elements removed. */ - final def zRemRangeByScore[K: Schema](key: K, scoreRange: ScoreRange): IO[RedisError, Long] = { - val command = RedisCommand( - ZRemRangeByScore, - Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), - LongOutput, - codec, - executor - ) - command.run((key, scoreRange.min.stringify, scoreRange.max.stringify)) - } + final def zRemRangeByScore[K: Schema](key: K, scoreRange: ScoreRange): IO[RedisError, Long] = + _zRemRangeByScore[K].run((key, scoreRange.min.stringify, scoreRange.max.stringify)) /** * Return a range of members in a sorted set, by index, with scores ordered from high to low. @@ -819,16 +521,7 @@ trait SortedSets extends RedisEnvironment { */ final def zRevRange[K: Schema](key: K, range: Range): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZRevRange, - Tuple2(ArbitraryKeyInput[K](), RangeInput), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((key, range)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = _zRevRange[K, M].run((key, range)) } /** @@ -841,22 +534,10 @@ trait SortedSets extends RedisEnvironment { * @return * Chunk of elements with their scores in the specified range. */ - final def zRevRangeWithScores[K: Schema]( - key: K, - range: Range - ): ResultBuilder1[MemberScores] = + final def zRevRangeWithScores[K: Schema](key: K, range: Range): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZRevRange, - Tuple3(ArbitraryKeyInput[K](), RangeInput, ArbitraryValueInput[String]()), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((key, range, WithScores.stringify)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = + _zRevRangeWithScores[K, M].run((key, range, WithScores.stringify)) } /** @@ -872,27 +553,10 @@ trait SortedSets extends RedisEnvironment { * @return * Chunk of elements in the specified score range. */ - final def zRevRangeByLex[K: Schema]( - key: K, - lexRange: LexRange, - limit: Option[Limit] = None - ): ResultBuilder1[Chunk] = + final def zRevRangeByLex[K: Schema](key: K, lexRange: LexRange, limit: Option[Limit] = None): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZRevRangeByLex, - Tuple4( - ArbitraryKeyInput[K](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - OptionalInput(LimitInput) - ), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((key, lexRange.max.stringify, lexRange.min.stringify, limit)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = + _zRevRangeByLex[K, M].run((key, lexRange.max.stringify, lexRange.min.stringify, limit)) } /** @@ -914,21 +578,8 @@ trait SortedSets extends RedisEnvironment { limit: Option[Limit] = None ): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZRevRangeByScore, - Tuple4( - ArbitraryKeyInput[K](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - OptionalInput(LimitInput) - ), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((key, scoreRange.max.stringify, scoreRange.min.stringify, limit)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = + _zRevRangeByScore[K, M].run((key, scoreRange.max.stringify, scoreRange.min.stringify, limit)) } /** @@ -950,23 +601,9 @@ trait SortedSets extends RedisEnvironment { limit: Option[Limit] = None ): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZRevRangeByScore, - Tuple5( - ArbitraryKeyInput[K](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - ArbitraryValueInput[String](), - OptionalInput(LimitInput) - ), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((key, scoreRange.max.stringify, scoreRange.min.stringify, WithScores.stringify, limit)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = _zRevRangeByScoreWithScores[K, M].run( + (key, scoreRange.max.stringify, scoreRange.min.stringify, WithScores.stringify, limit) + ) } /** @@ -979,16 +616,8 @@ trait SortedSets extends RedisEnvironment { * @return * The rank of member. */ - final def zRevRank[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Long]] = { - val command = RedisCommand( - ZRevRank, - Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), - OptionalOutput(LongOutput), - codec, - executor - ) - command.run((key, member)) - } + final def zRevRank[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Long]] = + _zRevRank[K, M].run((key, member)) /** * Incrementally iterate sorted sets elements and associated scores. @@ -1011,18 +640,8 @@ trait SortedSets extends RedisEnvironment { count: Option[Count] = None ): ResultBuilder1[({ type lambda[x] = (Long, MemberScores[x]) })#lambda] = new ResultBuilder1[({ type lambda[x] = (Long, MemberScores[x]) })#lambda] { - def returning[M: Schema]: IO[RedisError, (Long, Chunk[MemberScore[M]])] = { - val memberScoresOutput = - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput).map(_.map { case (m, s) => MemberScore(s, m) }) - val command = RedisCommand( - ZScan, - Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), - Tuple2Output(MultiStringOutput.map(_.toLong), memberScoresOutput), - codec, - executor - ) - command.run((key, cursor, pattern.map(Pattern(_)), count)) - } + def returning[M: Schema]: IO[RedisError, (Long, Chunk[MemberScore[M]])] = + _zScan[K, M].run((key, cursor, pattern.map(Pattern(_)), count)) } /** @@ -1035,16 +654,8 @@ trait SortedSets extends RedisEnvironment { * @return * The score of member (a double precision floating point number. */ - final def zScore[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Double]] = { - val command = RedisCommand( - ZScore, - Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), - OptionalOutput(DoubleOutput), - codec, - executor - ) - command.run((key, member)) - } + final def zScore[K: Schema, M: Schema](key: K, member: M): IO[RedisError, Option[Double]] = + _zScore[K, M].run((key, member)) /** * Add multiple sorted sets and return each member. @@ -1069,22 +680,8 @@ trait SortedSets extends RedisEnvironment { aggregate: Option[Aggregate] = None ): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = - RedisCommand( - ZUnion, - Tuple4( - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()), - OptionalInput(WeightsInput), - OptionalInput(AggregateInput) - ), - ChunkOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((inputKeysNum, (key, keys.toList), weights, aggregate)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = + _zUnion[K, M].run((inputKeysNum, (key, keys.toList), weights, aggregate)) } /** @@ -1110,24 +707,8 @@ trait SortedSets extends RedisEnvironment { aggregate: Option[Aggregate] = None ): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = - RedisCommand( - ZUnion, - Tuple5( - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()), - OptionalInput(WeightsInput), - OptionalInput(AggregateInput), - ArbitraryValueInput[String]() - ), - ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - command.run((inputKeysNum, (key, keys.toList), weights, aggregate, WithScores.stringify)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = + _zUnionWithScores[K, M].run((inputKeysNum, (key, keys.toList), weights, aggregate, WithScores.stringify)) } /** @@ -1153,22 +734,8 @@ trait SortedSets extends RedisEnvironment { final def zUnionStore[DK: Schema, K: Schema](destination: DK, inputKeysNum: Long, key: K, keys: K*)( weights: Option[::[Double]] = None, aggregate: Option[Aggregate] = None - ): IO[RedisError, Long] = { - val command = RedisCommand( - ZUnionStore, - Tuple5( - ArbitraryValueInput[DK](), - LongInput, - NonEmptyList(ArbitraryKeyInput[K]()), - OptionalInput(WeightsInput), - OptionalInput(AggregateInput) - ), - LongOutput, - codec, - executor - ) - command.run((destination, inputKeysNum, (key, keys.toList), weights, aggregate)) - } + ): IO[RedisError, Long] = + _zUnionStore[DK, K].run((destination, inputKeysNum, (key, keys.toList), weights, aggregate)) /** * Returns the scores associated with the specified members in the sorted set stored at key. @@ -1180,16 +747,8 @@ trait SortedSets extends RedisEnvironment { * @return * List of scores or None associated with the specified member values (a double precision floating point number). */ - final def zMScore[K: Schema](key: K, keys: K*): IO[RedisError, Chunk[Option[Double]]] = { - val command = RedisCommand( - ZMScore, - NonEmptyList(ArbitraryKeyInput[K]()), - ChunkOutput(OptionalOutput(DoubleOutput)), - codec, - executor - ) - command.run((key, keys.toList)) - } + final def zMScore[K: Schema](key: K, keys: K*): IO[RedisError, Chunk[Option[Double]]] = + _zMScore[K].run((key, keys.toList)) /** * Return a random element from the sorted set value stored at key. @@ -1201,9 +760,7 @@ 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, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) - .run(key) + def returning[R: Schema]: IO[RedisError, Option[R]] = _zRandMember[K, R].run(key) } /** @@ -1217,21 +774,9 @@ trait SortedSets extends RedisEnvironment { * @return * Return an array of elements from the sorted set value stored at key. */ - final def zRandMember[K: Schema]( - key: K, - count: Long - ): ResultBuilder1[Chunk] = + final def zRandMember[K: Schema](key: K, count: Long): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { - def returning[M: Schema]: IO[RedisError, Chunk[M]] = { - val command = RedisCommand( - ZRandMember, - Tuple2(ArbitraryKeyInput[K](), LongInput), - ZRandMemberOutput(ArbitraryOutput[M]()), - codec, - executor - ) - command.run((key, count)) - } + def returning[M: Schema]: IO[RedisError, Chunk[M]] = _zRandMemberWithCount[K, M].run((key, count)) } /** @@ -1247,56 +792,9 @@ trait SortedSets extends RedisEnvironment { * key does not exist. If the WITHSCORES modifier is used, the reply is a list elements and their scores from the * sorted set. */ - final def zRandMemberWithScores[K: Schema]( - key: K, - count: Long - ): ResultBuilder1[MemberScores] = + final def zRandMemberWithScores[K: Schema](key: K, count: Long): ResultBuilder1[MemberScores] = new ResultBuilder1[MemberScores] { - def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = { - val command = RedisCommand( - ZRandMember, - Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[String]()), - ZRandMemberTuple2Output(ArbitraryOutput[M](), DoubleOutput) - .map(_.map { case (m, s) => MemberScore(s, m) }), - codec, - executor - ) - - command.run((key, count, WithScores.stringify)) - } + def returning[M: Schema]: IO[RedisError, Chunk[MemberScore[M]]] = + _zRandMemberWithScores[K, M].run((key, count, WithScores.stringify)) } } - -private[redis] object SortedSets { - final val BzPopMax = "BZPOPMAX" - final val BzPopMin = "BZPOPMIN" - final val ZAdd = "ZADD" - final val ZCard = "ZCARD" - final val ZCount = "ZCOUNT" - final val ZDiff = "ZDIFF" - final val ZDiffStore = "ZDIFFSTORE" - final val ZIncrBy = "ZINCRBY" - final val ZInter = "ZINTER" - final val ZInterStore = "ZINTERSTORE" - final val ZLexCount = "ZLEXCOUNT" - final val ZMScore = "ZMSCORE" - final val ZPopMax = "ZPOPMAX" - final val ZPopMin = "ZPOPMIN" - final val ZRange = "ZRANGE" - final val ZRangeByLex = "ZRANGEBYLEX" - final val ZRangeByScore = "ZRANGEBYSCORE" - final val ZRank = "ZRANK" - final val ZRem = "ZREM" - final val ZRemRangeByLex = "ZREMRANGEBYLEX" - final val ZRemRangeByRank = "ZREMRANGEBYRANK" - final val ZRemRangeByScore = "ZREMRANGEBYSCORE" - final val ZRevRange = "ZREVRANGE" - final val ZRevRangeByLex = "ZREVRANGEBYLEX" - final val ZRevRangeByScore = "ZREVRANGEBYSCORE" - final val ZRevRank = "ZREVRANK" - final val ZScan = "ZSCAN" - final val ZScore = "ZSCORE" - final val ZUnion = "ZUNION" - final val ZUnionStore = "ZUNIONSTORE" - final val ZRandMember = "ZRANDMEMBER" -} diff --git a/redis/src/main/scala/zio/redis/api/Streams.scala b/redis/src/main/scala/zio/redis/api/Streams.scala index f9ec1523f..09e81bd29 100644 --- a/redis/src/main/scala/zio/redis/api/Streams.scala +++ b/redis/src/main/scala/zio/redis/api/Streams.scala @@ -17,15 +17,12 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder._ import zio.redis._ import zio.schema.Schema -trait Streams extends RedisEnvironment { +trait Streams extends commands.Streams { import StreamInfoWithFull._ - import Streams._ import XGroupCommand._ /** @@ -42,21 +39,8 @@ trait Streams extends RedisEnvironment { * @return * the number of messages successfully acknowledged. */ - final def xAck[SK: Schema, G: Schema, I: Schema]( - key: SK, - group: G, - id: I, - ids: I* - ): IO[RedisError, Long] = { - val command = RedisCommand( - XAck, - Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[G](), NonEmptyList(ArbitraryValueInput[I]())), - LongOutput, - codec, - executor - ) - command.run((key, group, (id, ids.toList))) - } + final def xAck[SK: Schema, G: Schema, I: Schema](key: SK, group: G, id: I, ids: I*): IO[RedisError, Long] = + _xAck[SK, G, I].run((key, group, (id, ids.toList))) /** * Appends the specified stream entry to the stream at the specified key. @@ -79,21 +63,8 @@ trait Streams extends RedisEnvironment { pairs: (K, V)* ): ResultBuilder1[Id] = new ResultBuilder1[Id] { - def returning[R: Schema]: IO[RedisError, Id[R]] = { - val command = RedisCommand( - XAdd, - Tuple4( - ArbitraryKeyInput[SK](), - OptionalInput(StreamMaxLenInput), - ArbitraryValueInput[I](), - NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())) - ), - ArbitraryOutput[R](), - codec, - executor - ) - command.run((key, None, id, (pair, pairs.toList))) - } + def returning[R: Schema]: IO[RedisError, Id[R]] = + _xAdd[SK, I, K, V, R].run((key, None, id, (pair, pairs.toList))) } /** @@ -104,14 +75,11 @@ trait Streams extends RedisEnvironment { * @return * General information about the stream stored at the specified key. */ - final def xInfoStream[SK: Schema]( - 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, ArbitraryKeyInput[SK](), StreamInfoOutput[RI, RK, RV](), codec, executor) - command.run(key) + final def xInfoStream[SK: Schema](key: SK): ResultBuilder3[StreamInfo] = + new ResultBuilder3[StreamInfo] { + def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, StreamInfo[RI, RK, RV]] = + _xInfoStream[SK, RI, RK, RV].run(key) } - } /** * Returns the entire state of the stream, including entries, groups, consumers and PELs. @@ -121,19 +89,9 @@ trait Streams extends RedisEnvironment { * @return * General information about the stream stored at the specified key. */ - final def xInfoStreamFull[SK: Schema]( - key: SK - ): ResultBuilder3[FullStreamInfo] = new ResultBuilder3[FullStreamInfo] { - def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, FullStreamInfo[RI, RK, RV]] = { - val command = RedisCommand( - XInfoStream, - Tuple2(ArbitraryKeyInput[SK](), ArbitraryValueInput[String]()), - StreamInfoFullOutput[RI, RK, RV](), - codec, - executor - ) - command.run((key, "FULL")) - } + final def xInfoStreamFull[SK: Schema](key: SK): ResultBuilder3[FullStreamInfo] = new ResultBuilder3[FullStreamInfo] { + def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, FullStreamInfo[RI, RK, RV]] = + _xInfoStreamFull[SK, RI, RK, RV].run((key, "FULL")) } /** @@ -146,21 +104,11 @@ trait Streams extends RedisEnvironment { * @return * General information about the stream stored at the specified key. */ - final def xInfoStreamFull[SK: Schema]( - key: SK, - count: Long - ): ResultBuilder3[FullStreamInfo] = new ResultBuilder3[FullStreamInfo] { - def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, FullStreamInfo[RI, RK, RV]] = { - val command = RedisCommand( - XInfoStream, - Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[String](), CountInput), - StreamInfoFullOutput[RI, RK, RV](), - codec, - executor - ) - command.run((key, "FULL", Count(count))) + final def xInfoStreamFull[SK: Schema](key: SK, count: Long): ResultBuilder3[FullStreamInfo] = + new ResultBuilder3[FullStreamInfo] { + def returning[RI: Schema, RK: Schema, RV: Schema]: IO[RedisError, FullStreamInfo[RI, RK, RV]] = + _xInfoStreamFullWithCount[SK, RI, RK, RV].run((key, "FULL", Count(count))) } - } /** * An introspection command used in order to retrieve different information about the group. @@ -170,10 +118,7 @@ trait Streams extends RedisEnvironment { * @return * 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, ArbitraryKeyInput[SK](), StreamGroupsInfoOutput, codec, executor) - command.run(key) - } + final def xInfoGroups[SK: Schema](key: SK): IO[RedisError, Chunk[StreamGroupsInfo]] = _xInfoGroups[SK].run(key) /** * An introspection command used in order to retrieve different information about the consumers. @@ -185,20 +130,8 @@ trait Streams extends RedisEnvironment { * @return * List of every consumer in a specific consumer group. */ - final def xInfoConsumers[SK: Schema, SG: Schema]( - key: SK, - group: SG - ): IO[RedisError, Chunk[StreamConsumersInfo]] = { - val command = - RedisCommand( - XInfoConsumers, - Tuple2(ArbitraryKeyInput[SK](), ArbitraryValueInput[SG]()), - StreamConsumersInfoOutput, - codec, - executor - ) - command.run((key, group)) - } + final def xInfoConsumers[SK: Schema, SG: Schema](key: SK, group: SG): IO[RedisError, Chunk[StreamConsumersInfo]] = + _xInfoConsumers[SK, SG].run((key, group)) /** * Appends the specified stream entry to the stream at the specified key while limiting the size of the stream. @@ -228,21 +161,8 @@ trait Streams extends RedisEnvironment { pairs: (K, V)* ): ResultBuilder1[Id] = new ResultBuilder1[Id] { - def returning[R: Schema]: IO[RedisError, Id[R]] = { - val command = RedisCommand( - XAdd, - Tuple4( - ArbitraryKeyInput[SK](), - OptionalInput(StreamMaxLenInput), - ArbitraryValueInput[I](), - NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())) - ), - ArbitraryOutput[R](), - codec, - executor - ) - command.run((key, Some(StreamMaxLen(approximate, count)), id, (pair, pairs.toList))) - } + def returning[R: Schema]: IO[RedisError, Id[R]] = + _xAddWithMaxLen[SK, I, K, V, R].run((key, Some(StreamMaxLen(approximate, count)), id, (pair, pairs.toList))) } /** @@ -284,25 +204,11 @@ trait Streams extends RedisEnvironment { )(id: I, ids: I*): ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] = new ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] { def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { - val command = RedisCommand( - XClaim, - Tuple9( - ArbitraryKeyInput[SK](), - ArbitraryValueInput[SG](), - ArbitraryValueInput[SC](), - DurationMillisecondsInput, - NonEmptyList(ArbitraryValueInput[I]()), - OptionalInput(IdleInput), - OptionalInput(TimeInput), - OptionalInput(RetryCountInput), - OptionalInput(WithForceInput) - ), - StreamEntriesOutput[I, RK, RV](), - codec, - executor + val withForce = if (force) Some(WithForce) else None + + _xClaim[SK, SG, SC, I, RK, RV].run( + (key, group, consumer, minIdleTime, (id, ids.toList), idle, time, retryCount, withForce) ) - val forceOpt = if (force) Some(WithForce) else None - command.run((key, group, consumer, minIdleTime, (id, ids.toList), idle, time, retryCount, forceOpt)) } } @@ -345,26 +251,22 @@ trait Streams extends RedisEnvironment { )(id: I, ids: I*): ResultBuilder1[Chunk] = new ResultBuilder1[Chunk] { def returning[R: Schema]: IO[RedisError, Chunk[R]] = { - val command = RedisCommand( - XClaim, - Tuple10( - ArbitraryKeyInput[SK](), - ArbitraryValueInput[SG](), - ArbitraryValueInput[SC](), - DurationMillisecondsInput, - NonEmptyList(ArbitraryValueInput[I]()), - OptionalInput(IdleInput), - OptionalInput(TimeInput), - OptionalInput(RetryCountInput), - OptionalInput(WithForceInput), - WithJustIdInput - ), - ChunkOutput(ArbitraryOutput[R]()), - codec, - executor + val withForce = if (force) Some(WithForce) else None + + _xClaimWithJustId[SK, SG, SC, I, R].run( + ( + key, + group, + consumer, + minIdleTime, + (id, ids.toList), + idle, + time, + retryCount, + withForce, + WithJustId + ) ) - val forceOpt = if (force) Some(WithForce) else None - command.run((key, group, consumer, minIdleTime, (id, ids.toList), idle, time, retryCount, forceOpt, WithJustId)) } } @@ -380,17 +282,8 @@ trait Streams extends RedisEnvironment { * @return * the number of entries deleted. */ - final def xDel[SK: Schema, I: Schema](key: SK, id: I, ids: I*): IO[RedisError, Long] = { - val command = - RedisCommand( - XDel, - Tuple2(ArbitraryKeyInput[SK](), NonEmptyList(ArbitraryValueInput[I]())), - LongOutput, - codec, - executor - ) - command.run((key, (id, ids.toList))) - } + final def xDel[SK: Schema, I: Schema](key: SK, id: I, ids: I*): IO[RedisError, Long] = + _xDel[SK, I].run((key, (id, ids.toList))) /** * Create a new consumer group associated with a stream. @@ -409,10 +302,8 @@ trait Streams extends RedisEnvironment { group: SG, id: I, mkStream: Boolean = false - ): IO[RedisError, Unit] = { - val command = RedisCommand(XGroup, XGroupCreateInput[SK, SG, I](), UnitOutput, codec, executor) - command.run(Create(key, group, id, mkStream)) - } + ): IO[RedisError, Unit] = + _xGroupCreate[SK, SG, I].run(Create(key, group, id, mkStream)) /** * Set the consumer group last delivered ID to something else. @@ -424,14 +315,8 @@ trait Streams extends RedisEnvironment { * @param id * last delivered ID to set */ - final def xGroupSetId[SK: Schema, SG: Schema, I: Schema]( - key: SK, - group: SG, - id: I - ): IO[RedisError, Unit] = { - val command = RedisCommand(XGroup, XGroupSetIdInput[SK, SG, I](), UnitOutput, codec, executor) - command.run(SetId(key, group, id)) - } + final def xGroupSetId[SK: Schema, SG: Schema, I: Schema](key: SK, group: SG, id: I): IO[RedisError, Unit] = + _xGroupSetId[SK, SG, I].run(SetId(key, group, id)) /** * Destroy a consumer group. @@ -444,7 +329,7 @@ trait Streams extends RedisEnvironment { * flag that indicates if the deletion was successful. */ final def xGroupDestroy[SK: Schema, SG: Schema](key: SK, group: SG): IO[RedisError, Boolean] = - RedisCommand(XGroup, XGroupDestroyInput[SK, SG](), BoolOutput, codec, executor).run(Destroy(key, group)) + _xGroupDestroy[SK, SG].run(Destroy(key, group)) /** * Create a new consumer associated with a consumer group. @@ -462,10 +347,8 @@ trait Streams extends RedisEnvironment { key: SK, group: SG, consumer: SC - ): IO[RedisError, Boolean] = { - val command = RedisCommand(XGroup, XGroupCreateConsumerInput[SK, SG, SC](), BoolOutput, codec, executor) - command.run(CreateConsumer(key, group, consumer)) - } + ): IO[RedisError, Boolean] = + _xGroupCreateConsumer[SK, SG, SC].run(CreateConsumer(key, group, consumer)) /** * Remove a specific consumer from a consumer group. @@ -483,10 +366,8 @@ trait Streams extends RedisEnvironment { key: SK, group: SG, consumer: SC - ): IO[RedisError, Long] = { - val command = RedisCommand(XGroup, XGroupDelConsumerInput[SK, SG, SC](), LongOutput, codec, executor) - command.run(DelConsumer(key, group, consumer)) - } + ): IO[RedisError, Long] = + _xGroupDelConsumer[SK, SG, SC].run(DelConsumer(key, group, consumer)) /** * Fetches the number of entries inside a stream. @@ -496,10 +377,7 @@ trait Streams extends RedisEnvironment { * @return * the number of entries inside a stream. */ - final def xLen[SK: Schema](key: SK): IO[RedisError, Long] = { - val command = RedisCommand(XLen, ArbitraryKeyInput[SK](), LongOutput, codec, executor) - command.run(key) - } + final def xLen[SK: Schema](key: SK): IO[RedisError, Long] = _xLen[SK].run(key) /** * Inspects the list of pending messages. @@ -511,16 +389,8 @@ trait Streams extends RedisEnvironment { * @return * summary about the pending messages in a given consumer group. */ - final def xPending[SK: Schema, SG: Schema](key: SK, group: SG): IO[RedisError, PendingInfo] = { - val command = RedisCommand( - XPending, - Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[SG](), OptionalInput(IdleInput)), - XPendingOutput, - codec, - executor - ) - command.run((key, group, None)) - } + final def xPending[SK: Schema, SG: Schema](key: SK, group: SG): IO[RedisError, PendingInfo] = + _xPending[SK, SG].run((key, group, None)) /** * Inspects the list of pending messages. @@ -550,24 +420,8 @@ trait Streams extends RedisEnvironment { count: Long, consumer: Option[SC] = None, idle: Option[Duration] = None - ): IO[RedisError, Chunk[PendingMessage]] = { - val command = RedisCommand( - XPending, - Tuple7( - ArbitraryKeyInput[SK](), - ArbitraryValueInput[SG](), - OptionalInput(IdleInput), - ArbitraryValueInput[I](), - ArbitraryValueInput[I](), - LongInput, - OptionalInput(ArbitraryValueInput[SC]()) - ), - PendingMessagesOutput, - codec, - executor - ) - command.run((key, group, idle, start, end, count, consumer)) - } + ): IO[RedisError, Chunk[PendingMessage]] = + _xPendingMessages[SK, SG, I, SC].run((key, group, idle, start, end, count, consumer)) /** * Fetches the stream entries matching a given range of IDs. @@ -587,21 +441,8 @@ trait Streams extends RedisEnvironment { end: I ): ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] = new ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] { - def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { - val command = RedisCommand( - XRange, - Tuple4( - ArbitraryKeyInput[SK](), - ArbitraryValueInput[I](), - ArbitraryValueInput[I](), - OptionalInput(CountInput) - ), - StreamEntriesOutput[I, RK, RV](), - codec, - executor - ) - command.run((key, start, end, None)) - } + def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = + _xRange[SK, I, RK, RV].run((key, start, end, None)) } /** @@ -625,21 +466,8 @@ trait Streams extends RedisEnvironment { count: Long ): ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] = new ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] { - def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { - val command = RedisCommand( - XRange, - Tuple4( - ArbitraryKeyInput[SK](), - ArbitraryValueInput[I](), - ArbitraryValueInput[I](), - OptionalInput(CountInput) - ), - StreamEntriesOutput[I, RK, RV](), - codec, - executor - ) - command.run((key, start, end, Some(Count(count)))) - } + def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = + _xRangeWithCount[SK, I, RK, RV].run((key, start, end, Some(Count(count)))) } /** @@ -656,24 +484,13 @@ trait Streams extends RedisEnvironment { * @return * complete entries with an ID greater than the last received ID per stream. */ - final def xRead[SK: Schema, I: Schema]( - count: Option[Long] = None, - block: Option[Duration] = None - )( + final def xRead[SK: Schema, I: Schema](count: Option[Long] = None, block: Option[Duration] = None)( stream: (SK, I), streams: (SK, I)* ): ResultBuilder2[({ type lambda[x, y] = StreamChunks[SK, I, x, y] })#lambda] = new ResultBuilder2[({ type lambda[x, y] = StreamChunks[SK, I, x, y] })#lambda] { - def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamChunks[SK, I, RK, RV]] = { - val command = RedisCommand( - XRead, - Tuple3(OptionalInput(CountInput), OptionalInput(BlockInput), StreamsInput[SK, I]()), - ChunkOutput(StreamOutput[SK, I, RK, RV]()), - codec, - executor - ) - command.run((count.map(Count(_)), block, (stream, Chunk.fromIterable(streams)))) - } + def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamChunks[SK, I, RK, RV]] = + _xRead[SK, I, RK, RV].run((count.map(Count(_)), block, (stream, Chunk.fromIterable(streams)))) } /** @@ -708,22 +525,10 @@ trait Streams extends RedisEnvironment { ): ResultBuilder2[({ type lambda[x, y] = StreamChunks[SK, I, x, y] })#lambda] = new ResultBuilder2[({ type lambda[x, y] = StreamChunks[SK, I, x, y] })#lambda] { def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamChunks[SK, I, RK, RV]] = { - val command = RedisCommand( - XReadGroup, - Tuple6( - ArbitraryValueInput[SG](), - ArbitraryValueInput[SC](), - OptionalInput(CountInput), - OptionalInput(BlockInput), - OptionalInput(NoAckInput), - StreamsInput[SK, I]() - ), - ChunkOutput(StreamOutput[SK, I, RK, RV]()), - codec, - executor - ) val noAckOpt = if (noAck) Some(NoAck) else None - command.run((group, consumer, count.map(Count(_)), block, noAckOpt, (stream, Chunk.fromIterable(streams)))) + _xReadGroup[SG, SC, SK, I, RK, RV].run( + (group, consumer, count.map(Count(_)), block, noAckOpt, (stream, Chunk.fromIterable(streams))) + ) } } @@ -745,21 +550,8 @@ trait Streams extends RedisEnvironment { start: I ): ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] = new ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] { - def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { - val command = RedisCommand( - XRevRange, - Tuple4( - ArbitraryKeyInput[SK](), - ArbitraryValueInput[I](), - ArbitraryValueInput[I](), - OptionalInput(CountInput) - ), - StreamEntriesOutput[I, RK, RV](), - codec, - executor - ) - command.run((key, end, start, None)) - } + def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = + _xRevRange[SK, I, RK, RV].run((key, end, start, None)) } /** @@ -783,21 +575,8 @@ trait Streams extends RedisEnvironment { count: Long ): ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] = new ResultBuilder2[({ type lambda[x, y] = StreamEntries[I, x, y] })#lambda] { - def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = { - val command = RedisCommand( - XRevRange, - Tuple4( - ArbitraryKeyInput[SK](), - ArbitraryValueInput[I](), - ArbitraryValueInput[I](), - OptionalInput(CountInput) - ), - StreamEntriesOutput[I, RK, RV](), - codec, - executor - ) - command.run((key, end, start, Some(Count(count)))) - } + def returning[RK: Schema, RV: Schema]: IO[RedisError, StreamEntries[I, RK, RV]] = + _xRevRangeWithCount[SK, I, RK, RV].run((key, end, start, Some(Count(count)))) } /** @@ -812,30 +591,6 @@ trait Streams extends RedisEnvironment { * @return * the number of entries deleted from the stream. */ - final def xTrim[SK: Schema]( - key: SK, - count: Long, - approximate: Boolean = false - ): IO[RedisError, Long] = { - val command = RedisCommand(XTrim, Tuple2(ArbitraryKeyInput[SK](), StreamMaxLenInput), LongOutput, codec, executor) - command.run((key, StreamMaxLen(approximate, count))) - } -} - -private object Streams { - final val XAck = "XACK" - final val XAdd = "XADD" - final val XClaim = "XCLAIM" - final val XDel = "XDEL" - final val XGroup = "XGROUP" - final val XInfoStream = "XINFO STREAM" - final val XInfoGroups = "XINFO GROUPS" - final val XInfoConsumers = "XINFO CONSUMERS" - final val XLen = "XLEN" - final val XPending = "XPENDING" - final val XRange = "XRANGE" - final val XRead = "XREAD" - final val XReadGroup = "XREADGROUP GROUP" - final val XRevRange = "XREVRANGE" - final val XTrim = "XTRIM" + final def xTrim[SK: Schema](key: SK, count: Long, approximate: Boolean = false): IO[RedisError, Long] = + _xTrim[SK].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 7976f1ad0..345c450f7 100644 --- a/redis/src/main/scala/zio/redis/api/Strings.scala +++ b/redis/src/main/scala/zio/redis/api/Strings.scala @@ -17,16 +17,13 @@ package zio.redis.api import zio._ -import zio.redis.Input._ -import zio.redis.Output._ import zio.redis.ResultBuilder._ import zio.redis._ import zio.schema.Schema import java.time.Instant -trait Strings extends RedisEnvironment { - import Strings._ +trait Strings extends commands.Strings { /** * Append a value to a key. @@ -38,11 +35,7 @@ trait Strings extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), LongOutput, codec, executor) - command.run((key, value)) - } + final def append[K: Schema, V: Schema](key: K, value: V): IO[RedisError, Long] = _append[K, V].run((key, value)) /** * Count set bits in a string. @@ -54,11 +47,8 @@ trait Strings extends RedisEnvironment { * @return * Returns the number of bits set to 1. */ - final def bitCount[K: Schema](key: K, range: Option[Range] = None): IO[RedisError, Long] = { - val command = - RedisCommand(BitCount, Tuple2(ArbitraryKeyInput[K](), OptionalInput(RangeInput)), LongOutput, codec, executor) - command.run((key, range)) - } + final def bitCount[K: Schema](key: K, range: Option[Range] = None): IO[RedisError, Long] = + _bitCount[K].run((key, range)) /** * Perform arbitrary bitfield integer operations on strings. @@ -76,16 +66,8 @@ trait Strings extends RedisEnvironment { key: K, bitFieldCommand: BitFieldCommand, bitFieldCommands: BitFieldCommand* - ): IO[RedisError, Chunk[Option[Long]]] = { - val command = RedisCommand( - BitField, - Tuple2(ArbitraryKeyInput[K](), NonEmptyList(BitFieldCommandInput)), - ChunkOutput(OptionalOutput(LongOutput)), - codec, - executor - ) - command.run((key, (bitFieldCommand, bitFieldCommands.toList))) - } + ): IO[RedisError, Chunk[Option[Long]]] = + _bitField[K].run((key, (bitFieldCommand, bitFieldCommands.toList))) /** * Perform bitwise operations between strings. @@ -106,17 +88,8 @@ trait Strings extends RedisEnvironment { destKey: D, srcKey: S, srcKeys: S* - ): IO[RedisError, Long] = { - val command = - RedisCommand( - BitOp, - Tuple3(BitOperationInput, ArbitraryValueInput[D](), NonEmptyList(ArbitraryValueInput[S]())), - LongOutput, - codec, - executor - ) - command.run((operation, destKey, (srcKey, srcKeys.toList))) - } + ): IO[RedisError, Long] = + _bitOp[D, S].run((operation, destKey, (srcKey, srcKeys.toList))) /** * Find first bit set or clear in a string. @@ -130,21 +103,8 @@ trait Strings extends RedisEnvironment { * @return * Returns the position of the first bit set to 1 or 0 according to the request. */ - final def bitPos[K: Schema]( - key: K, - bit: Boolean, - range: Option[BitPosRange] = None - ): IO[RedisError, Long] = { - val command = - RedisCommand( - BitPos, - Tuple3(ArbitraryKeyInput[K](), BoolInput, OptionalInput(BitPosRangeInput)), - LongOutput, - codec, - executor - ) - command.run((key, bit, range)) - } + final def bitPos[K: Schema](key: K, bit: Boolean, range: Option[BitPosRange] = None): IO[RedisError, Long] = + _bitPos[K].run((key, bit, range)) /** * Decrement the integer value of a key by one. @@ -154,10 +114,7 @@ trait Strings extends RedisEnvironment { * @return * Returns the value of key after the decrement. */ - final def decr[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(Decr, ArbitraryKeyInput[K](), LongOutput, codec, executor) - command.run(key) - } + final def decr[K: Schema](key: K): IO[RedisError, Long] = _decr[K].run(key) /** * Decrement the integer value of a key by the given number. @@ -169,10 +126,7 @@ trait Strings extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) - command.run((key, decrement)) - } + final def decrBy[K: Schema](key: K, decrement: Long): IO[RedisError, Long] = _decrBy[K].run((key, decrement)) /** * Get the value of a key. @@ -184,8 +138,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, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor).run(key) + def returning[R: Schema]: IO[RedisError, Option[R]] = _get[K, R].run(key) } /** @@ -198,10 +151,7 @@ trait Strings extends RedisEnvironment { * @return * Returns the bit value stored at offset. */ - final def getBit[K: Schema](key: K, offset: Long): IO[RedisError, Long] = { - val command = RedisCommand(GetBit, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) - command.run((key, offset)) - } + final def getBit[K: Schema](key: K, offset: Long): IO[RedisError, Long] = _getBit[K].run((key, offset)) /** * Get a substring of the string stored at key. @@ -215,15 +165,7 @@ trait Strings extends RedisEnvironment { */ final def getRange[K: Schema](key: K, range: Range): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand( - GetRange, - Tuple2(ArbitraryKeyInput[K](), RangeInput), - OptionalOutput(ArbitraryOutput[R]()), - codec, - executor - ) - .run((key, range)) + def returning[R: Schema]: IO[RedisError, Option[R]] = _getRange[K, R].run((key, range)) } /** @@ -238,15 +180,7 @@ trait Strings extends RedisEnvironment { */ final def getSet[K: Schema, V: Schema](key: K, value: V): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand( - GetSet, - Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), - OptionalOutput(ArbitraryOutput[R]()), - codec, - executor - ) - .run((key, value)) + def returning[R: Schema]: IO[RedisError, Option[R]] = _getSet[K, V, R].run((key, value)) } /** @@ -259,8 +193,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, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor).run(key) + def returning[R: Schema]: IO[RedisError, Option[R]] = _getDel[K, R].run(key) } /** @@ -278,9 +211,7 @@ trait Strings extends RedisEnvironment { */ final def getEx[K: Schema](key: K, expire: Expire, expireTime: Duration): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand(GetEx, GetExInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) - .run((key, expire, expireTime)) + def returning[R: Schema]: IO[RedisError, Option[R]] = _getEx[K, R].run((key, expire, expireTime)) } /** @@ -298,9 +229,7 @@ trait Strings extends RedisEnvironment { */ final def getEx[K: Schema](key: K, expiredAt: ExpiredAt, timestamp: Instant): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand(GetEx, GetExAtInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) - .run((key, expiredAt, timestamp)) + def returning[R: Schema]: IO[RedisError, Option[R]] = _getExAt[K, R].run((key, expiredAt, timestamp)) } /** @@ -315,9 +244,7 @@ trait Strings extends RedisEnvironment { */ final def getEx[K: Schema](key: K, persist: Boolean): ResultBuilder1[Option] = new ResultBuilder1[Option] { - def returning[R: Schema]: IO[RedisError, Option[R]] = - RedisCommand(GetEx, GetExPersistInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) - .run((key, persist)) + def returning[R: Schema]: IO[RedisError, Option[R]] = _getExDel[K, R].run((key, persist)) } /** @@ -328,10 +255,7 @@ trait Strings extends RedisEnvironment { * @return * Returns the value of key after the increment. */ - final def incr[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(Incr, ArbitraryKeyInput[K](), LongOutput, codec, executor) - command.run(key) - } + final def incr[K: Schema](key: K): IO[RedisError, Long] = _incr[K].run(key) /** * Increment the integer value of a key by the given amount. @@ -343,11 +267,7 @@ trait Strings extends RedisEnvironment { * @return * Returns the value of key after the increment. */ - final def incrBy[K: Schema](key: K, increment: Long): IO[RedisError, Long] = { - val command = - RedisCommand(IncrBy, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) - command.run((key, increment)) - } + final def incrBy[K: Schema](key: K, increment: Long): IO[RedisError, Long] = _incrBy[K].run((key, increment)) /** * Increment the float value of a key by the given amount. @@ -359,10 +279,8 @@ trait Strings extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), DoubleInput), DoubleOutput, codec, executor) - command.run((key, increment)) - } + final def incrByFloat[K: Schema](key: K, increment: Double): IO[RedisError, Double] = + _incrByFloat[K].run((key, increment)) /** * Get all the values of the given keys. @@ -374,22 +292,9 @@ trait Strings extends RedisEnvironment { * @return * Returns the values of the given keys. */ - final def mGet[K: Schema]( - key: K, - keys: K* - ): ResultBuilder1[({ type lambda[x] = Chunk[Option[x]] })#lambda] = + final def mGet[K: Schema](key: K, keys: K*): ResultBuilder1[({ type lambda[x] = Chunk[Option[x]] })#lambda] = new ResultBuilder1[({ type lambda[x] = Chunk[Option[x]] })#lambda] { - def returning[V: Schema]: IO[RedisError, Chunk[Option[V]]] = { - val command = - RedisCommand( - MGet, - NonEmptyList(ArbitraryKeyInput[K]()), - ChunkOutput(OptionalOutput(ArbitraryOutput[V]())), - codec, - executor - ) - command.run((key, keys.toList)) - } + def returning[V: Schema]: IO[RedisError, Chunk[Option[V]]] = _mGet[K, V].run((key, keys.toList)) } /** @@ -400,17 +305,8 @@ trait Strings extends RedisEnvironment { * @param keyValues * Subsequent tuples of key values */ - final def mSet[K: Schema, V: Schema](keyValue: (K, V), keyValues: (K, V)*): IO[RedisError, Unit] = { - val command = - RedisCommand( - MSet, - NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())), - UnitOutput, - codec, - executor - ) - command.run((keyValue, keyValues.toList)) - } + final def mSet[K: Schema, V: Schema](keyValue: (K, V), keyValues: (K, V)*): IO[RedisError, Unit] = + _mSet[K, V].run((keyValue, keyValues.toList)) /** * Set multiple keys to multiple values only if none of the keys exist. @@ -422,20 +318,8 @@ trait Strings extends RedisEnvironment { * @return * 1 if the all the keys were set. 0 if no key was set (at least one key already existed). */ - final def mSetNx[K: Schema, V: Schema]( - keyValue: (K, V), - keyValues: (K, V)* - ): IO[RedisError, Boolean] = { - val command = - RedisCommand( - MSetNx, - NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())), - BoolOutput, - codec, - executor - ) - command.run((keyValue, keyValues.toList)) - } + final def mSetNx[K: Schema, V: Schema](keyValue: (K, V), keyValues: (K, V)*): IO[RedisError, Boolean] = + _mSetNx[K, V].run((keyValue, keyValues.toList)) /** * Set the value and expiration in milliseconds of a key. @@ -447,21 +331,8 @@ trait Strings extends RedisEnvironment { * @param value * Value to set */ - final def pSetEx[K: Schema, V: Schema]( - key: K, - milliseconds: Duration, - value: V - ): IO[RedisError, Unit] = { - val command = - RedisCommand( - PSetEx, - Tuple3(ArbitraryKeyInput[K](), DurationMillisecondsInput, ArbitraryValueInput[V]()), - UnitOutput, - codec, - executor - ) - command.run((key, milliseconds, value)) - } + final def pSetEx[K: Schema, V: Schema](key: K, milliseconds: Duration, value: V): IO[RedisError, Unit] = + _pSetEx[K, V].run((key, milliseconds, value)) /** * Set the string value of a key. @@ -486,17 +357,7 @@ trait Strings extends RedisEnvironment { expireTime: Option[Duration] = None, update: Option[Update] = None, keepTtl: Option[KeepTtl] = None - ): IO[RedisError, Boolean] = { - val input = Tuple5( - ArbitraryKeyInput[K](), - ArbitraryValueInput[V](), - OptionalInput(DurationTtlInput), - OptionalInput(UpdateInput), - OptionalInput(KeepTtlInput) - ) - val command = RedisCommand(Set, input, SetOutput, codec, executor) - command.run((key, value, expireTime, update, keepTtl)) - } + ): IO[RedisError, Boolean] = _set[K, V].run((key, value, expireTime, update, keepTtl)) /** * Sets or clears the bit at offset in the string value stored at key. @@ -510,11 +371,8 @@ trait Strings extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), LongInput, BoolInput), BoolOutput, codec, executor) - command.run((key, offset, value)) - } + final def setBit[K: Schema](key: K, offset: Long, value: Boolean): IO[RedisError, Boolean] = + _setBit[K].run((key, offset, value)) /** * Set the value and expiration of a key. @@ -526,21 +384,8 @@ trait Strings extends RedisEnvironment { * @param value * New value to set */ - final def setEx[K: Schema, V: Schema]( - key: K, - expiration: Duration, - value: V - ): IO[RedisError, Unit] = { - val command = - RedisCommand( - SetEx, - Tuple3(ArbitraryKeyInput[K](), DurationSecondsInput, ArbitraryValueInput[V]()), - UnitOutput, - codec, - executor - ) - command.run((key, expiration, value)) - } + final def setEx[K: Schema, V: Schema](key: K, expiration: Duration, value: V): IO[RedisError, Unit] = + _setEx[K, V].run((key, expiration, value)) /** * Set the value of a key, only if the key does not exist. @@ -552,11 +397,7 @@ trait Strings extends RedisEnvironment { * @return * 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(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), BoolOutput, codec, executor) - command.run((key, value)) - } + final def setNx[K: Schema, V: Schema](key: K, value: V): IO[RedisError, Boolean] = _setNx[K, V].run((key, value)) /** * Overwrite part of a string at key starting at the specified offset. @@ -570,17 +411,8 @@ trait Strings extends RedisEnvironment { * @return * Returns the length of the string after it was modified by the command. */ - final def setRange[K: Schema, V: Schema](key: K, offset: Long, value: V): IO[RedisError, Long] = { - val command = - RedisCommand( - SetRange, - Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[V]()), - LongOutput, - codec, - executor - ) - command.run((key, offset, value)) - } + final def setRange[K: Schema, V: Schema](key: K, offset: Long, value: V): IO[RedisError, Long] = + _setRange[K, V].run((key, offset, value)) /** * Get the length of a value stored in a key. @@ -590,10 +422,7 @@ trait Strings extends RedisEnvironment { * @return * Returns the length of the string. */ - final def strLen[K: Schema](key: K): IO[RedisError, Long] = { - val command = RedisCommand(StrLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) - command.run(key) - } + final def strLen[K: Schema](key: K): IO[RedisError, Long] = _strLen[K].run(key) /** * Get the longest common subsequence of values stored in the given keys. @@ -612,54 +441,10 @@ trait Strings extends RedisEnvironment { * length and all the ranges in both the strings, start and end offset for each string, where there are matches. * When withMatchLen is given each array representing a match will also have the length of the match (see examples). */ - final def stralgoLcs[K: Schema]( + final def strAlgoLcs[K: Schema]( command: StrAlgoLCS, keyA: K, keyB: K, lcsQueryType: Option[StrAlgoLcsQueryType] = None - ): IO[RedisError, LcsOutput] = { - val redisCommand = RedisCommand( - StrAlgoLcs, - Tuple4( - ArbitraryValueInput[String](), - ArbitraryKeyInput[K](), - ArbitraryKeyInput[K](), - OptionalInput(StralgoLcsQueryTypeInput) - ), - StrAlgoLcsOutput, - codec, - executor - ) - redisCommand.run((command.stringify, keyA, keyB, lcsQueryType)) - } -} - -private[redis] object Strings { - final val Append = "APPEND" - final val BitCount = "BITCOUNT" - final val BitField = "BITFIELD" - final val BitOp = "BITOP" - final val BitPos = "BITPOS" - final val Decr = "DECR" - final val DecrBy = "DECRBY" - final val Get = "GET" - final val GetBit = "GETBIT" - final val GetRange = "GETRANGE" - final val GetSet = "GETSET" - final val Incr = "INCR" - final val IncrBy = "INCRBY" - final val IncrByFloat = "INCRBYFLOAT" - final val MGet = "MGET" - final val MSet = "MSET" - final val MSetNx = "MSETNX" - final val PSetEx = "PSETEX" - final val Set = "SET" - final val SetBit = "SETBIT" - final val SetEx = "SETEX" - final val SetNx = "SETNX" - final val SetRange = "SETRANGE" - final val StrLen = "STRLEN" - final val StrAlgoLcs = "STRALGO LCS" - final val GetDel = "GETDEL" - final val GetEx = "GETEX" + ): IO[RedisError, LcsOutput] = _strAlgoLcs[K].run((command.stringify, keyA, keyB, lcsQueryType)) } diff --git a/redis/src/main/scala/zio/redis/commands/Cluster.scala b/redis/src/main/scala/zio/redis/commands/Cluster.scala new file mode 100644 index 000000000..1468246d0 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Cluster.scala @@ -0,0 +1,68 @@ +/* + * 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.commands + +import zio.Chunk +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.codec.BinaryCodec + +private[redis] trait Cluster extends RedisEnvironment { + import Cluster._ + + final val _asking: RedisCommand[Unit, Unit] = askingCommand(codec, executor) + + final val _slots: RedisCommand[Unit, Chunk[zio.redis.options.Cluster.Partition]] = + RedisCommand(ClusterSlots, NoInput, ChunkOutput(ClusterPartitionOutput), codec, executor) + + final val _setSlotStable: RedisCommand[(Long, String), Unit] = + RedisCommand(ClusterSetSlots, Tuple2(LongInput, ArbitraryValueInput[String]()), UnitOutput, codec, executor) + + final val _setSlotMigrating: RedisCommand[(Long, String, String), Unit] = RedisCommand( + ClusterSetSlots, + Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), + UnitOutput, + codec, + executor + ) + + final val _setSlotImporting: RedisCommand[(Long, String, String), Unit] = RedisCommand( + ClusterSetSlots, + Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), + UnitOutput, + codec, + executor + ) + + final val _setSlotNode: RedisCommand[(Long, String, String), Unit] = RedisCommand( + ClusterSetSlots, + Tuple3(LongInput, ArbitraryValueInput[String](), ArbitraryValueInput[String]()), + UnitOutput, + codec, + executor + ) +} + +private[redis] object Cluster { + private final val Asking = "ASKING" + private final val ClusterSlots = "CLUSTER SLOTS" + private final val ClusterSetSlots = "CLUSTER SETSLOT" + + final val askingCommand: (BinaryCodec, RedisExecutor) => RedisCommand[Unit, Unit] = + RedisCommand(Asking, NoInput, UnitOutput, _, _) +} diff --git a/redis/src/main/scala/zio/redis/commands/Connection.scala b/redis/src/main/scala/zio/redis/commands/Connection.scala new file mode 100644 index 000000000..c6d7a3fc8 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Connection.scala @@ -0,0 +1,115 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.{Chunk, Duration} + +private[redis] trait Connection extends RedisEnvironment { + import Connection.{Auth => _} + + final val _auth: RedisCommand[Auth, Unit] = RedisCommand(Connection.Auth, AuthInput, UnitOutput, codec, executor) + + final val _clientCaching: RedisCommand[Boolean, Unit] = + RedisCommand(Connection.ClientCaching, YesNoInput, UnitOutput, codec, executor) + + final val _clientId: RedisCommand[Unit, Long] = + RedisCommand(Connection.ClientId, NoInput, LongOutput, codec, executor) + + final val _clientKill: RedisCommand[Address, Unit] = + RedisCommand(Connection.ClientKill, AddressInput, UnitOutput, codec, executor) + + final val _clientKillByFilter: RedisCommand[Iterable[ClientKillFilter], Long] = + RedisCommand(Connection.ClientKill, Varargs(ClientKillInput), LongOutput, codec, executor) + + final val _clientGetName: RedisCommand[Unit, Option[String]] = + RedisCommand(Connection.ClientGetName, NoInput, OptionalOutput(MultiStringOutput), codec, executor) + + final val _clientGetRedir: RedisCommand[Unit, ClientTrackingRedirect] = + RedisCommand(Connection.ClientGetRedir, NoInput, ClientTrackingRedirectOutput, codec, executor) + + final val _clientUnpause: RedisCommand[Unit, Unit] = + RedisCommand(Connection.ClientUnpause, NoInput, UnitOutput, codec, executor) + + final val _clientPause: RedisCommand[(Duration, Option[ClientPauseMode]), Unit] = RedisCommand( + Connection.ClientPause, + Tuple2(DurationMillisecondsInput, OptionalInput(ClientPauseModeInput)), + UnitOutput, + codec, + executor + ) + + final val _clientSetName: RedisCommand[String, Unit] = + RedisCommand(Connection.ClientSetName, StringInput, UnitOutput, codec, executor) + + final val _clientTrackingOn: RedisCommand[ + Option[(Option[Long], Option[ClientTrackingMode], Boolean, Chunk[String])], + Unit + ] = + RedisCommand(Connection.ClientTracking, ClientTrackingInput, UnitOutput, codec, executor) + + final val _clientTrackingOff: RedisCommand[ + Option[(Option[Long], Option[zio.redis.ClientTrackingMode], Boolean, Chunk[String])], + Unit + ] = + RedisCommand(Connection.ClientTracking, ClientTrackingInput, UnitOutput, codec, executor) + + final val _clientTrackingInfo: RedisCommand[Unit, zio.redis.ClientTrackingInfo] = + RedisCommand(Connection.ClientTrackingInfo, NoInput, ClientTrackingInfoOutput, codec, executor) + + final val _clientUnblock: RedisCommand[(Long, Option[UnblockBehavior]), Boolean] = RedisCommand( + Connection.ClientUnblock, + Tuple2(LongInput, OptionalInput(UnblockBehaviorInput)), + BoolOutput, + codec, + executor + ) + + final val _echo: RedisCommand[String, String] = + RedisCommand(Connection.Echo, StringInput, MultiStringOutput, codec, executor) + + final val _ping: RedisCommand[Option[String], String] = + RedisCommand(Connection.Ping, OptionalInput(StringInput), SingleOrMultiStringOutput, codec, executor) + + final val _quit: RedisCommand[Unit, Unit] = RedisCommand(Connection.Quit, NoInput, UnitOutput, codec, executor) + + final val _reset: RedisCommand[Unit, Unit] = RedisCommand(Connection.Reset, NoInput, ResetOutput, codec, executor) + + final val _select: RedisCommand[Long, Unit] = RedisCommand(Connection.Select, LongInput, UnitOutput, codec, executor) +} + +private object Connection { + final val Auth = "AUTH" + final val ClientCaching = "CLIENT CACHING" + final val ClientId = "CLIENT ID" + final val ClientKill = "CLIENT KILL" + final val ClientGetName = "CLIENT GETNAME" + final val ClientGetRedir = "CLIENT GETREDIR" + final val ClientUnpause = "CLIENT UNPAUSE" + final val ClientPause = "CLIENT PAUSE" + final val ClientSetName = "CLIENT SETNAME" + final val ClientTracking = "CLIENT TRACKING" + final val ClientTrackingInfo = "CLIENT TRACKINGINFO" + final val ClientUnblock = "CLIENT UNBLOCK" + final val Echo = "ECHO" + final val Ping = "PING" + final val Quit = "QUIT" + final val Reset = "RESET" + final val Select = "SELECT" +} diff --git a/redis/src/main/scala/zio/redis/commands/Geo.scala b/redis/src/main/scala/zio/redis/commands/Geo.scala new file mode 100644 index 000000000..87a79ac6d --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Geo.scala @@ -0,0 +1,201 @@ +/* + * 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.commands + +import zio.Chunk +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema + +private[redis] trait Geo extends RedisEnvironment { + import Geo._ + + final def _geoAdd[K: Schema, M: Schema]: RedisCommand[(K, ((LongLat, M), List[(LongLat, M)])), Long] = RedisCommand( + Geo.GeoAdd, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(LongLatInput, ArbitraryValueInput[M]()))), + LongOutput, + codec, + executor + ) + + final def _geoDist[K: Schema, M: Schema]: RedisCommand[(K, M, M, Option[RadiusUnit]), Option[Double]] = RedisCommand( + GeoDist, + Tuple4(ArbitraryKeyInput[K](), ArbitraryValueInput[M](), ArbitraryValueInput[M](), OptionalInput(RadiusUnitInput)), + OptionalOutput(DoubleOutput), + codec, + executor + ) + + final def _geoHash[K: Schema, M: Schema]: RedisCommand[(K, (M, List[M])), Chunk[Option[String]]] = RedisCommand( + GeoHash, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + ChunkOutput(OptionalOutput(MultiStringOutput)), + codec, + executor + ) + + final def _geoPos[K: Schema, M: Schema]: RedisCommand[(K, (M, List[M])), Chunk[Option[zio.redis.LongLat]]] = + RedisCommand( + GeoPos, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + GeoOutput, + codec, + executor + ) + + final def _geoRadius[K: Schema]: RedisCommand[ + ( + K, + LongLat, + Double, + RadiusUnit, + Option[WithCoord], + Option[WithDist], + Option[WithHash], + Option[Count], + Option[Order] + ), + Chunk[GeoView] + ] = RedisCommand( + GeoRadius, + Tuple9( + ArbitraryKeyInput[K](), + LongLatInput, + DoubleInput, + RadiusUnitInput, + OptionalInput(WithCoordInput), + OptionalInput(WithDistInput), + OptionalInput(WithHashInput), + OptionalInput(CountInput), + OptionalInput(OrderInput) + ), + GeoRadiusOutput, + codec, + executor + ) + + final def _geoRadiusStore[K: Schema]: RedisCommand[ + ( + K, + zio.redis.LongLat, + Double, + zio.redis.RadiusUnit, + Option[WithCoord], + Option[WithDist], + Option[WithHash], + Option[Count], + Option[Order], + Option[Store], + Option[StoreDist] + ), + Long + ] = RedisCommand( + GeoRadius, + Tuple11( + ArbitraryKeyInput[K](), + LongLatInput, + DoubleInput, + RadiusUnitInput, + OptionalInput(WithCoordInput), + OptionalInput(WithDistInput), + OptionalInput(WithHashInput), + OptionalInput(CountInput), + OptionalInput(OrderInput), + OptionalInput(StoreInput), + OptionalInput(StoreDistInput) + ), + LongOutput, + codec, + executor + ) + + final def _geoRadiusByMember[K: Schema, M: Schema]: RedisCommand[ + ( + K, + M, + Double, + zio.redis.RadiusUnit, + Option[WithCoord], + Option[WithDist], + Option[WithHash], + Option[zio.redis.Count], + Option[zio.redis.Order] + ), + Chunk[GeoView] + ] = RedisCommand( + GeoRadiusByMember, + Tuple9( + ArbitraryKeyInput[K](), + ArbitraryValueInput[M](), + DoubleInput, + RadiusUnitInput, + OptionalInput(WithCoordInput), + OptionalInput(WithDistInput), + OptionalInput(WithHashInput), + OptionalInput(CountInput), + OptionalInput(OrderInput) + ), + GeoRadiusOutput, + codec, + executor + ) + + final def _geoRadiusByMemberStore[K: Schema, M: Schema]: RedisCommand[ + ( + K, + M, + Double, + zio.redis.RadiusUnit, + Option[WithCoord], + Option[WithDist], + Option[WithHash], + Option[zio.redis.Count], + Option[zio.redis.Order], + Option[zio.redis.Store], + Option[zio.redis.StoreDist] + ), + Long + ] = RedisCommand( + GeoRadiusByMember, + Tuple11( + ArbitraryKeyInput[K](), + ArbitraryValueInput[M](), + DoubleInput, + RadiusUnitInput, + OptionalInput(WithCoordInput), + OptionalInput(WithDistInput), + OptionalInput(WithHashInput), + OptionalInput(CountInput), + OptionalInput(OrderInput), + OptionalInput(StoreInput), + OptionalInput(StoreDistInput) + ), + LongOutput, + codec, + executor + ) +} + +private object Geo { + final val GeoAdd = "GEOADD" + final val GeoDist = "GEODIST" + final val GeoHash = "GEOHASH" + final val GeoPos = "GEOPOS" + final val GeoRadius = "GEORADIUS" + final val GeoRadiusByMember = "GEORADIUSBYMEMBER" +} diff --git a/redis/src/main/scala/zio/redis/commands/Hashes.scala b/redis/src/main/scala/zio/redis/commands/Hashes.scala new file mode 100644 index 000000000..07285ccca --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Hashes.scala @@ -0,0 +1,156 @@ +/* + * 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.commands + +import zio.Chunk +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema + +private[redis] trait Hashes extends RedisEnvironment { + import Hashes._ + + final def _hDel[K: Schema, F: Schema]: RedisCommand[(K, (F, List[F])), Long] = + RedisCommand( + HDel, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[F]())), + LongOutput, + codec, + executor + ) + + final def _hExists[K: Schema, F: Schema]: RedisCommand[(K, F), Boolean] = + RedisCommand(HExists, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), BoolOutput, codec, executor) + + final def _hGet[K: Schema, F: Schema, V: Schema]: RedisCommand[(K, F), Option[V]] = RedisCommand( + HGet, + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), + OptionalOutput(ArbitraryOutput[V]()), + codec, + executor + ) + + final def _hGetAll[K: Schema, F: Schema, V: Schema]: RedisCommand[K, Map[F, V]] = RedisCommand( + HGetAll, + ArbitraryKeyInput[K](), + KeyValueOutput(ArbitraryOutput[F](), ArbitraryOutput[V]()), + codec, + executor + ) + + final def _hIncrBy[K: Schema, F: Schema]: RedisCommand[(K, F, Long), Long] = + RedisCommand( + HIncrBy, + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), LongInput), + LongOutput, + codec, + executor + ) + + final def _hIncrByFloat[K: Schema, F: Schema]: RedisCommand[(K, F, Double), Double] = RedisCommand( + HIncrByFloat, + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), DoubleInput), + DoubleOutput, + codec, + executor + ) + + final def _hKeys[K: Schema, F: Schema]: RedisCommand[K, Chunk[F]] = + RedisCommand(HKeys, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[F]()), codec, executor) + + final def _hLen[K: Schema]: RedisCommand[K, Long] = + RedisCommand(HLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) + + final def _hmGet[K: Schema, F: Schema, V: Schema]: RedisCommand[(K, (F, List[F])), Chunk[Option[V]]] = RedisCommand( + HmGet, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[F]())), + ChunkOutput(OptionalOutput(ArbitraryOutput[V]())), + codec, + executor + ) + + final def _hmSet[K: Schema, F: Schema, V: Schema]: RedisCommand[(K, ((F, V), List[(F, V)])), Unit] = RedisCommand( + HmSet, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(ArbitraryValueInput[F](), ArbitraryValueInput[V]()))), + UnitOutput, + codec, + executor + ) + + final def _hScan[K: Schema, F: Schema, V: Schema] + : RedisCommand[(K, Long, Option[Pattern], Option[Count]), (Long, Chunk[(F, V)])] = RedisCommand( + HScan, + Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), + Tuple2Output(ArbitraryOutput[Long](), ChunkTuple2Output(ArbitraryOutput[F](), ArbitraryOutput[V]())), + codec, + executor + ) + + final def _hSet[K: Schema, F: Schema, V: Schema]: RedisCommand[(K, ((F, V), List[(F, V)])), Long] = RedisCommand( + HSet, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(Tuple2(ArbitraryValueInput[F](), ArbitraryValueInput[V]()))), + LongOutput, + codec, + executor + ) + + final def _hSetNx[K: Schema, F: Schema, V: Schema]: RedisCommand[(K, F, V), Boolean] = RedisCommand( + HSetNx, + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[F](), ArbitraryValueInput[V]()), + BoolOutput, + codec, + executor + ) + + final def _hStrLen[K: Schema, F: Schema]: RedisCommand[(K, F), Long] = + RedisCommand(HStrLen, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[F]()), LongOutput, codec, executor) + + final def _hVals[K: Schema, V: Schema]: RedisCommand[K, Chunk[V]] = + RedisCommand(HVals, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[V]()), codec, executor) + + final def _hRandField[K: Schema, V: Schema]: RedisCommand[K, Option[V]] = + RedisCommand(HRandField, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor) + + final def _hRandFieldWithCount[K: Schema, V: Schema]: RedisCommand[(K, Long, Option[String]), Chunk[V]] = + RedisCommand( + HRandField, + Tuple3(ArbitraryKeyInput[K](), LongInput, OptionalInput(StringInput)), + ChunkOutput(ArbitraryOutput[V]()), + codec, + executor + ) +} + +private object Hashes { + final val HDel = "HDEL" + final val HExists = "HEXISTS" + final val HGet = "HGET" + final val HGetAll = "HGETALL" + final val HIncrBy = "HINCRBY" + final val HIncrByFloat = "HINCRBYFLOAT" + final val HKeys = "HKEYS" + final val HLen = "HLEN" + final val HmGet = "HMGET" + final val HmSet = "HMSET" + final val HScan = "HSCAN" + final val HSet = "HSET" + final val HSetNx = "HSETNX" + final val HStrLen = "HSTRLEN" + final val HVals = "HVALS" + final val HRandField = "HRANDFIELD" +} diff --git a/redis/src/main/scala/zio/redis/commands/HyperLogLog.scala b/redis/src/main/scala/zio/redis/commands/HyperLogLog.scala new file mode 100644 index 000000000..a5927adaa --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/HyperLogLog.scala @@ -0,0 +1,53 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema + +private[redis] trait HyperLogLog extends RedisEnvironment { + import HyperLogLog._ + + final def _pfAdd[K: Schema, V: Schema]: RedisCommand[(K, (V, List[V])), Boolean] = + RedisCommand( + PfAdd, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + BoolOutput, + codec, + executor + ) + + final def _pfCount[K: Schema]: RedisCommand[(K, List[K]), Long] = + RedisCommand(PfCount, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) + + final def _pfMerge[K: Schema]: RedisCommand[(K, (K, List[K])), Unit] = + RedisCommand( + PfMerge, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryKeyInput[K]())), + UnitOutput, + codec, + executor + ) +} + +private object HyperLogLog { + final val PfAdd = "PFADD" + final val PfCount = "PFCOUNT" + final val PfMerge = "PFMERGE" +} diff --git a/redis/src/main/scala/zio/redis/commands/Keys.scala b/redis/src/main/scala/zio/redis/commands/Keys.scala new file mode 100644 index 000000000..67d1a7498 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Keys.scala @@ -0,0 +1,197 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema +import zio.{Chunk, Duration} + +import java.time.Instant + +private[redis] trait Keys extends RedisEnvironment { + import Keys.{Keys => _, _} + + final def _del[K: Schema]: RedisCommand[(K, List[K]), Long] = + RedisCommand(Del, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) + + final def _dump[K: Schema]: RedisCommand[K, Chunk[Byte]] = + RedisCommand(Dump, ArbitraryKeyInput[K](), BulkStringOutput, codec, executor) + + final def _exists[K: Schema]: RedisCommand[(K, List[K]), Long] = + RedisCommand(Exists, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) + + final def _expire[K: Schema]: RedisCommand[(K, Duration), Boolean] = + RedisCommand(Expire, Tuple2(ArbitraryKeyInput[K](), DurationSecondsInput), BoolOutput, codec, executor) + + final def _expireAt[K: Schema]: RedisCommand[(K, Instant), Boolean] = + RedisCommand(ExpireAt, Tuple2(ArbitraryKeyInput[K](), TimeSecondsInput), BoolOutput, codec, executor) + + final def _keys[V: Schema]: RedisCommand[String, Chunk[V]] = + RedisCommand(Keys.Keys, StringInput, ChunkOutput(ArbitraryOutput[V]()), codec, executor) + + final def _migrate[K: Schema]: RedisCommand[ + (String, Long, K, Long, Long, Option[Copy], Option[Replace], Option[Auth], Option[(K, List[K])]), + String + ] = RedisCommand( + Migrate, + Tuple9( + StringInput, + LongInput, + ArbitraryKeyInput[K](), + LongInput, + LongInput, + OptionalInput(CopyInput), + OptionalInput(ReplaceInput), + OptionalInput(AuthInput), + OptionalInput(NonEmptyList(ArbitraryKeyInput[K]())) + ), + StringOutput, + codec, + executor + ) + + final def _move[K: Schema]: RedisCommand[(K, Long), Boolean] = + RedisCommand(Move, Tuple2(ArbitraryKeyInput[K](), LongInput), BoolOutput, codec, executor) + + final def _persist[K: Schema]: RedisCommand[K, Boolean] = + RedisCommand(Persist, ArbitraryKeyInput[K](), BoolOutput, codec, executor) + + final def _pExpire[K: Schema]: RedisCommand[(K, Duration), Boolean] = + RedisCommand(PExpire, Tuple2(ArbitraryKeyInput[K](), DurationMillisecondsInput), BoolOutput, codec, executor) + + final def _pExpireAt[K: Schema]: RedisCommand[(K, Instant), Boolean] = + RedisCommand(PExpireAt, Tuple2(ArbitraryKeyInput[K](), TimeMillisecondsInput), BoolOutput, codec, executor) + + final def _pTtl[K: Schema]: RedisCommand[K, Duration] = + RedisCommand(PTtl, ArbitraryKeyInput[K](), DurationMillisecondsOutput, codec, executor) + + final def _randomKey[V: Schema]: RedisCommand[Unit, Option[V]] = + RedisCommand(RandomKey, NoInput, OptionalOutput(ArbitraryOutput[V]()), codec, executor) + + final def _rename[K: Schema]: RedisCommand[(K, K), Unit] = + RedisCommand(Rename, Tuple2(ArbitraryKeyInput[K](), ArbitraryKeyInput[K]()), UnitOutput, codec, executor) + + final def _renameNx[K: Schema]: RedisCommand[(K, K), Boolean] = + RedisCommand(RenameNx, Tuple2(ArbitraryKeyInput[K](), ArbitraryKeyInput[K]()), BoolOutput, codec, executor) + + final def _restore[K: Schema] + : RedisCommand[(K, Long, Chunk[Byte], Option[Replace], Option[AbsTtl], Option[IdleTime], Option[Freq]), Unit] = + RedisCommand( + Restore, + Tuple7( + ArbitraryKeyInput[K](), + LongInput, + ValueInput, + OptionalInput(ReplaceInput), + OptionalInput(AbsTtlInput), + OptionalInput(IdleTimeInput), + OptionalInput(FreqInput) + ), + UnitOutput, + codec, + executor + ) + + final def _scan[K: Schema] + : RedisCommand[(Long, Option[Pattern], Option[Count], Option[RedisType]), (Long, Chunk[K])] = RedisCommand( + Scan, + Tuple4(LongInput, OptionalInput(PatternInput), OptionalInput(CountInput), OptionalInput(RedisTypeInput)), + Tuple2Output(ArbitraryOutput[Long](), ChunkOutput(ArbitraryOutput[K]())), + codec, + executor + ) + + final def _sort[K: Schema, V: Schema] + : RedisCommand[(K, Option[String], Option[Limit], Option[(String, List[String])], Order, Option[Alpha]), Chunk[V]] = + RedisCommand( + Sort, + Tuple6( + ArbitraryKeyInput[K](), + OptionalInput(ByInput), + OptionalInput(LimitInput), + OptionalInput(NonEmptyList(GetInput)), + OrderInput, + OptionalInput(AlphaInput) + ), + ChunkOutput(ArbitraryOutput[V]()), + codec, + executor + ) + + final def _sortStore[K: Schema]: RedisCommand[ + (K, Option[String], Option[zio.redis.Limit], Option[(String, List[String])], zio.redis.Order, Option[Alpha], Store), + Long + ] = RedisCommand( + SortStore, + Tuple7( + ArbitraryKeyInput[K](), + OptionalInput(ByInput), + OptionalInput(LimitInput), + OptionalInput(NonEmptyList(GetInput)), + OrderInput, + OptionalInput(AlphaInput), + StoreInput + ), + LongOutput, + codec, + executor + ) + + final def _touch[K: Schema]: RedisCommand[(K, List[K]), Long] = + RedisCommand(Touch, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) + + final def _ttl[K: Schema]: RedisCommand[K, Duration] = + RedisCommand(Ttl, ArbitraryKeyInput[K](), DurationSecondsOutput, codec, executor) + + final def _typeOf[K: Schema]: RedisCommand[K, zio.redis.RedisType] = + RedisCommand(TypeOf, ArbitraryKeyInput[K](), TypeOutput, codec, executor) + + final def _unlink[K: Schema]: RedisCommand[(K, List[K]), Long] = + RedisCommand(Unlink, NonEmptyList(ArbitraryKeyInput[K]()), LongOutput, codec, executor) + + final val _wait: RedisCommand[(Long, Long), Long] = + RedisCommand(Wait, Tuple2(LongInput, LongInput), LongOutput, codec, executor) +} + +private object Keys { + final val Del = "DEL" + final val Dump = "DUMP" + final val Exists = "EXISTS" + final val Expire = "EXPIRE" + final val ExpireAt = "EXPIREAT" + final val Keys = "KEYS" + final val Migrate = "MIGRATE" + final val Move = "MOVE" + final val Persist = "PERSIST" + final val PExpire = "PEXPIRE" + final val PExpireAt = "PEXPIREAT" + final val PTtl = "PTTL" + final val RandomKey = "RANDOMKEY" + final val Rename = "RENAME" + final val RenameNx = "RENAMENX" + final val Restore = "RESTORE" + final val Scan = "SCAN" + final val Sort = "SORT" + final val SortStore = "SORT" + final val Touch = "TOUCH" + final val Ttl = "TTL" + final val TypeOf = "TYPE" + final val Unlink = "UNLINK" + final val Wait = "WAIT" +} diff --git a/redis/src/main/scala/zio/redis/commands/Lists.scala b/redis/src/main/scala/zio/redis/commands/Lists.scala new file mode 100644 index 000000000..997e00760 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Lists.scala @@ -0,0 +1,202 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema +import zio.{Chunk, Duration} + +private[redis] trait Lists extends RedisEnvironment { + import Lists._ + + final def _brPopLPush[S: Schema, D: Schema, V: Schema]: RedisCommand[(S, D, Duration), Option[V]] = RedisCommand( + BrPopLPush, + Tuple3(ArbitraryValueInput[S](), ArbitraryValueInput[D](), DurationSecondsInput), + OptionalOutput(ArbitraryOutput[V]()), + codec, + executor + ) + + final def _lIndex[K: Schema, V: Schema]: RedisCommand[(K, Long), Option[V]] = + RedisCommand( + LIndex, + Tuple2(ArbitraryKeyInput[K](), LongInput), + OptionalOutput(ArbitraryOutput[V]()), + codec, + executor + ) + + final def _lLen[K: Schema]: RedisCommand[K, Long] = + RedisCommand(LLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) + + final def _lPop[K: Schema, V: Schema]: RedisCommand[K, Option[V]] = + RedisCommand(LPop, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor) + + final def _lPush[K: Schema, V: Schema]: RedisCommand[(K, (V, List[V])), Long] = + RedisCommand( + LPush, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) + + final def _lPushX[K: Schema, V: Schema]: RedisCommand[(K, (V, List[V])), Long] = + RedisCommand( + LPushX, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) + + final def _lRange[K: Schema, V: Schema]: RedisCommand[(K, Range), Chunk[V]] = + RedisCommand(LRange, Tuple2(ArbitraryKeyInput[K](), RangeInput), ChunkOutput(ArbitraryOutput[V]()), codec, executor) + + final def _lRem[K: Schema]: RedisCommand[(K, Long, String), Long] = + RedisCommand(LRem, Tuple3(ArbitraryKeyInput[K](), LongInput, StringInput), LongOutput, codec, executor) + + final def _lSet[K: Schema, V: Schema]: RedisCommand[(K, Long, V), Unit] = + RedisCommand(LSet, Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[V]()), UnitOutput, codec, executor) + + final def _lTrim[K: Schema]: RedisCommand[(K, Range), Unit] = + RedisCommand(LTrim, Tuple2(ArbitraryKeyInput[K](), RangeInput), UnitOutput, codec, executor) + + final def _rPop[K: Schema, V: Schema]: RedisCommand[K, Option[V]] = + RedisCommand(RPop, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[V]()), codec, executor) + + final def _rPopLPush[S: Schema, D: Schema, V: Schema]: RedisCommand[(S, D), Option[V]] = RedisCommand( + RPopLPush, + Tuple2(ArbitraryValueInput[S](), ArbitraryValueInput[D]()), + OptionalOutput(ArbitraryOutput[V]()), + codec, + executor + ) + + final def _rPush[K: Schema, V: Schema]: RedisCommand[(K, (V, List[V])), Long] = + RedisCommand( + RPush, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) + + final def _rPushX[K: Schema, V: Schema]: RedisCommand[(K, (V, List[V])), Long] = + RedisCommand( + RPushX, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[V]())), + LongOutput, + codec, + executor + ) + + final def _blPop[K: Schema, V: Schema]: RedisCommand[((K, List[K]), Duration), Option[(K, V)]] = RedisCommand( + BlPop, + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), + OptionalOutput(Tuple2Output(ArbitraryOutput[K](), ArbitraryOutput[V]())), + codec, + executor + ) + + final def _brPop[K: Schema, V: Schema]: RedisCommand[((K, List[K]), Duration), Option[(K, V)]] = RedisCommand( + BrPop, + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), + OptionalOutput(Tuple2Output(ArbitraryOutput[K](), ArbitraryOutput[V]())), + codec, + executor + ) + + final def _lInsert[K: Schema, V: Schema]: RedisCommand[(K, Position, V, V), Long] = RedisCommand( + LInsert, + Tuple4(ArbitraryKeyInput[K](), PositionInput, ArbitraryValueInput[V](), ArbitraryValueInput[V]()), + LongOutput, + codec, + executor + ) + + final def _lMove[S: Schema, D: Schema, V: Schema]: RedisCommand[(S, D, Side, Side), Option[V]] = RedisCommand( + LMove, + Tuple4(ArbitraryValueInput[S](), ArbitraryValueInput[D](), SideInput, SideInput), + OptionalOutput(ArbitraryOutput[V]()), + codec, + executor + ) + + final def _blMove[S: Schema, D: Schema, V: Schema] + : RedisCommand[(S, D, zio.redis.Side, zio.redis.Side, Duration), Option[V]] = RedisCommand( + BlMove, + Tuple5(ArbitraryValueInput[S](), ArbitraryValueInput[D](), SideInput, SideInput, DurationSecondsInput), + OptionalOutput(ArbitraryOutput[V]()), + codec, + executor + ) + + final def _lPos[K: Schema, V: Schema]: RedisCommand[(K, V, Option[Rank], Option[ListMaxLen]), Option[Long]] = + RedisCommand( + LPos, + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[V](), + OptionalInput(RankInput), + OptionalInput(ListMaxLenInput) + ), + OptionalOutput(LongOutput), + codec, + executor + ) + + final def _lPosCount[K: Schema, V: Schema] + : RedisCommand[(K, V, Count, Option[zio.redis.Rank], Option[zio.redis.ListMaxLen]), Chunk[Long]] = RedisCommand( + LPos, + Tuple5( + ArbitraryKeyInput[K](), + ArbitraryValueInput[V](), + CountInput, + OptionalInput(RankInput), + OptionalInput(ListMaxLenInput) + ), + ChunkOutput(LongOutput), + codec, + executor + ) +} + +private object Lists { + final val BrPopLPush = "BRPOPLPUSH" + final val LIndex = "LINDEX" + final val LLen = "LLEN" + final val LPop = "LPOP" + final val LPush = "LPUSH" + final val LPushX = "LPUSHX" + final val LRange = "LRANGE" + final val LRem = "LREM" + final val LSet = "LSET" + final val LTrim = "LTRIM" + final val RPop = "RPOP" + final val RPopLPush = "RPOPLPUSH" + final val RPush = "RPUSH" + final val RPushX = "RPUSHX" + final val BlPop = "BLPOP" + final val BrPop = "BRPOP" + final val LInsert = "LINSERT" + final val LMove = "LMOVE" + final val BlMove = "BLMOVE" + final val LPos = "LPOS" +} diff --git a/redis/src/main/scala/zio/redis/commands/Scripting.scala b/redis/src/main/scala/zio/redis/commands/Scripting.scala new file mode 100644 index 000000000..afd8a5dc0 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Scripting.scala @@ -0,0 +1,57 @@ +/* + * 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.commands + +import zio.Chunk +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ + +private[redis] trait Scripting extends RedisEnvironment { + import Scripting._ + + final def _eval[K: Input, A: Input, R: Output]: RedisCommand[(String, Chunk[K], Chunk[A]), R] = + RedisCommand(Eval, EvalInput(Input[K], Input[A]), Output[R], codec, executor) + + final def _evalSha[K: Input, A: Input, R: Output]: RedisCommand[(String, Chunk[K], Chunk[A]), R] = + RedisCommand(EvalSha, EvalInput(Input[K], Input[A]), Output[R], codec, executor) + + final val _scriptDebug: RedisCommand[DebugMode, Unit] = + RedisCommand(Scripting.ScriptDebug, ScriptDebugInput, UnitOutput, codec, executor) + + final val _scriptExists: RedisCommand[(String, List[String]), Chunk[Boolean]] = + RedisCommand(Scripting.ScriptExists, NonEmptyList(StringInput), ChunkOutput(BoolOutput), codec, executor) + + final val _scriptFlush: RedisCommand[Option[FlushMode], Unit] = + RedisCommand(Scripting.ScriptFlush, OptionalInput(ScriptFlushInput), UnitOutput, codec, executor) + + final val _scriptKill: RedisCommand[Unit, Unit] = + RedisCommand(Scripting.ScriptKill, NoInput, UnitOutput, codec, executor) + + final val _scriptLoad: RedisCommand[String, String] = + RedisCommand(Scripting.ScriptLoad, StringInput, MultiStringOutput, codec, executor) +} + +private object Scripting { + final val Eval = "EVAL" + final val EvalSha = "EVALSHA" + final val ScriptDebug = "SCRIPT DEBUG" + final val ScriptExists = "SCRIPT EXISTS" + final val ScriptFlush = "SCRIPT FLUSH" + final val ScriptKill = "SCRIPT KILL" + final val ScriptLoad = "SCRIPT LOAD" +} diff --git a/redis/src/main/scala/zio/redis/commands/Sets.scala b/redis/src/main/scala/zio/redis/commands/Sets.scala new file mode 100644 index 000000000..e3c54edd6 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Sets.scala @@ -0,0 +1,138 @@ +/* + * 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.commands + +import zio.Chunk +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema + +private[redis] trait Sets extends RedisEnvironment { + import Sets._ + + final def _sAdd[K: Schema, M: Schema]: RedisCommand[(K, (M, List[M])), Long] = + RedisCommand( + SAdd, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + LongOutput, + codec, + executor + ) + + final def _sCard[K: Schema]: RedisCommand[K, Long] = + RedisCommand(SCard, ArbitraryKeyInput[K](), LongOutput, codec, executor) + + final def _sDiff[K: Schema, R: Schema]: RedisCommand[(K, List[K]), Chunk[R]] = + RedisCommand(SDiff, NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) + + final def _sDiffStore[D: Schema, K: Schema]: RedisCommand[(D, (K, List[K])), Long] = RedisCommand( + SDiffStore, + Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), + LongOutput, + codec, + executor + ) + + final def _sInter[K: Schema, R: Schema]: RedisCommand[(K, List[K]), Chunk[R]] = + RedisCommand(SInter, NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) + + final def _sInterStore[D: Schema, K: Schema]: RedisCommand[(D, (K, List[K])), Long] = RedisCommand( + SInterStore, + Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), + LongOutput, + codec, + executor + ) + + final def _sIsMember[K: Schema, M: Schema]: RedisCommand[(K, M), Boolean] = + RedisCommand(SIsMember, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), BoolOutput, codec, executor) + + final def _sMembers[K: Schema, R: Schema]: RedisCommand[K, Chunk[R]] = + RedisCommand(SMembers, ArbitraryKeyInput[K](), ChunkOutput(ArbitraryOutput[R]()), codec, executor) + + final def _sMove[S: Schema, D: Schema, M: Schema]: RedisCommand[(S, D, M), Boolean] = RedisCommand( + SMove, + Tuple3(ArbitraryValueInput[S](), ArbitraryValueInput[D](), ArbitraryValueInput[M]()), + BoolOutput, + codec, + executor + ) + + final def _sPop[K: Schema, R: Schema]: RedisCommand[(K, Option[Long]), Chunk[R]] = RedisCommand( + SPop, + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), + MultiStringChunkOutput(ArbitraryOutput[R]()), + codec, + executor + ) + + final def _sRandMember[K: Schema, R: Schema]: RedisCommand[(K, Option[Long]), Chunk[R]] = RedisCommand( + SRandMember, + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), + MultiStringChunkOutput(ArbitraryOutput[R]()), + codec, + executor + ) + + final def _sRem[K: Schema, M: Schema]: RedisCommand[(K, (M, List[M])), Long] = + RedisCommand( + SRem, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + LongOutput, + codec, + executor + ) + + final def _sScan[K: Schema, R: Schema]: RedisCommand[(K, Long, Option[Pattern], Option[Count]), (Long, Chunk[R])] = + RedisCommand( + SScan, + Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), + Tuple2Output(MultiStringOutput.map(_.toLong), ChunkOutput(ArbitraryOutput[R]())), + codec, + executor + ) + + final def _sUnion[K: Schema, R: Schema]: RedisCommand[(K, List[K]), Chunk[R]] = + RedisCommand(SUnion, NonEmptyList(ArbitraryKeyInput[K]()), ChunkOutput(ArbitraryOutput[R]()), codec, executor) + + final def _sUnionStore[D: Schema, K: Schema]: RedisCommand[(D, (K, List[K])), Long] = RedisCommand( + SUnionStore, + Tuple2(ArbitraryValueInput[D](), NonEmptyList(ArbitraryKeyInput[K]())), + LongOutput, + codec, + executor + ) +} + +private object Sets { + final val SAdd = "SADD" + final val SCard = "SCARD" + final val SDiff = "SDIFF" + final val SDiffStore = "SDIFFSTORE" + final val SInter = "SINTER" + final val SInterStore = "SINTERSTORE" + final val SIsMember = "SISMEMBER" + final val SMembers = "SMEMBERS" + final val SMove = "SMOVE" + final val SPop = "SPOP" + final val SRandMember = "SRANDMEMBER" + final val SRem = "SREM" + final val SScan = "SSCAN" + final val SUnion = "SUNION" + final val SUnionStore = "SUNIONSTORE" +} diff --git a/redis/src/main/scala/zio/redis/commands/SortedSets.scala b/redis/src/main/scala/zio/redis/commands/SortedSets.scala new file mode 100644 index 000000000..dcb317821 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/SortedSets.scala @@ -0,0 +1,525 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema +import zio.{Chunk, Duration} + +private[redis] trait SortedSets extends RedisEnvironment { + import SortedSets._ + + final def _bzPopMax[K: Schema, M: Schema]: RedisCommand[((K, List[K]), Duration), Option[(K, MemberScore[M])]] = { + val memberScoreOutput = + Tuple3Output(ArbitraryOutput[K](), ArbitraryOutput[M](), DoubleOutput).map { case (k, m, s) => + (k, MemberScore(s, m)) + } + + RedisCommand( + BzPopMax, + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), + OptionalOutput(memberScoreOutput), + codec, + executor + ) + } + + final def _bzPopMin[K: Schema, M: Schema]: RedisCommand[((K, List[K]), Duration), Option[(K, MemberScore[M])]] = { + val memberScoreOutput = + Tuple3Output(ArbitraryOutput[K](), ArbitraryOutput[M](), DoubleOutput).map { case (k, m, s) => + (k, MemberScore(s, m)) + } + + RedisCommand( + BzPopMin, + Tuple2(NonEmptyList(ArbitraryKeyInput[K]()), DurationSecondsInput), + OptionalOutput(memberScoreOutput), + codec, + executor + ) + } + + final def _zAdd[K: Schema, M: Schema] + : RedisCommand[(K, Option[Update], Option[Changed], (MemberScore[M], List[MemberScore[M]])), Long] = RedisCommand( + ZAdd, + Tuple4( + ArbitraryKeyInput[K](), + OptionalInput(UpdateInput), + OptionalInput(ChangedInput), + NonEmptyList(MemberScoreInput[M]()) + ), + LongOutput, + codec, + executor + ) + + final def _zAddWithIncr[K: Schema, M: Schema]: RedisCommand[ + ( + K, + Option[zio.redis.Update], + Option[Changed], + Increment, + (zio.redis.MemberScore[M], List[zio.redis.MemberScore[M]]) + ), + Option[Double] + ] = RedisCommand( + ZAdd, + Tuple5( + ArbitraryKeyInput[K](), + OptionalInput(UpdateInput), + OptionalInput(ChangedInput), + IncrementInput, + NonEmptyList(MemberScoreInput[M]()) + ), + OptionalOutput(DoubleOutput), + codec, + executor + ) + + final def _zCard[K: Schema]: RedisCommand[K, Long] = + RedisCommand(ZCard, ArbitraryKeyInput[K](), LongOutput, codec, executor) + + final def _zCount[K: Schema]: RedisCommand[(K, Range), Long] = + RedisCommand(ZCount, Tuple2(ArbitraryKeyInput[K](), RangeInput), LongOutput, codec, executor) + + final def _zDiff[K: Schema, M: Schema]: RedisCommand[(Long, (K, List[K])), Chunk[M]] = RedisCommand( + ZDiff, + Tuple2( + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()) + ), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zDiffWithScores[K: Schema, M: Schema]: RedisCommand[(Long, (K, List[K]), String), Chunk[MemberScore[M]]] = + RedisCommand( + ZDiff, + Tuple3( + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()), + ArbitraryValueInput[String]() + ), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zDiffStore[DK: Schema, K: Schema]: RedisCommand[(DK, Long, (K, List[K])), Long] = RedisCommand( + ZDiffStore, + Tuple3( + ArbitraryValueInput[DK](), + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()) + ), + LongOutput, + codec, + executor + ) + + final def _zIncrBy[K: Schema, M: Schema]: RedisCommand[(K, Long, M), Double] = + RedisCommand( + ZIncrBy, + Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[M]()), + DoubleOutput, + codec, + executor + ) + + final def _zInter[K: Schema, M: Schema] + : RedisCommand[(Long, (K, List[K]), Option[Aggregate], Option[::[Double]]), Chunk[M]] = RedisCommand( + ZInter, + Tuple4( + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()), + OptionalInput(AggregateInput), + OptionalInput(WeightsInput) + ), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zInterWithScores[K: Schema, M: Schema] + : RedisCommand[(Long, (K, List[K]), Option[zio.redis.Aggregate], Option[::[Double]], String), Chunk[ + MemberScore[M] + ]] = + RedisCommand( + ZInter, + Tuple5( + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()), + OptionalInput(AggregateInput), + OptionalInput(WeightsInput), + ArbitraryValueInput[String]() + ), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zInterStore[DK: Schema, K: Schema] + : RedisCommand[(DK, Long, (K, List[K]), Option[zio.redis.Aggregate], Option[::[Double]]), Long] = RedisCommand( + ZInterStore, + Tuple5( + ArbitraryValueInput[DK](), + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()), + OptionalInput(AggregateInput), + OptionalInput(WeightsInput) + ), + LongOutput, + codec, + executor + ) + + final def _zLexCount[K: Schema]: RedisCommand[(K, String, String), Long] = RedisCommand( + ZLexCount, + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), + LongOutput, + codec, + executor + ) + + final def _zPopMax[K: Schema, M: Schema]: RedisCommand[(K, Option[Long]), Chunk[MemberScore[M]]] = RedisCommand( + ZPopMax, + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zPopMin[K: Schema, M: Schema]: RedisCommand[(K, Option[Long]), Chunk[MemberScore[M]]] = RedisCommand( + ZPopMin, + Tuple2(ArbitraryKeyInput[K](), OptionalInput(LongInput)), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zRange[K: Schema, M: Schema]: RedisCommand[(K, Range), Chunk[M]] = RedisCommand( + ZRange, + Tuple2(ArbitraryKeyInput[K](), RangeInput), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zRangeWithScores[K: Schema, M: Schema]: RedisCommand[(K, Range, String), Chunk[MemberScore[M]]] = + RedisCommand( + ZRange, + Tuple3(ArbitraryKeyInput[K](), RangeInput, ArbitraryValueInput[String]()), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zRangeByLex[K: Schema, M: Schema]: RedisCommand[(K, String, String, Option[Limit]), Chunk[M]] = + RedisCommand( + ZRangeByLex, + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zRangeByScore[K: Schema, M: Schema]: RedisCommand[(K, String, String, Option[zio.redis.Limit]), Chunk[M]] = + RedisCommand( + ZRangeByScore, + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zRangeByScoreWithScores[K: Schema, M: Schema] + : RedisCommand[(K, String, String, String, Option[zio.redis.Limit]), Chunk[MemberScore[M]]] = RedisCommand( + ZRangeByScore, + Tuple5( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zRank[K: Schema, M: Schema]: RedisCommand[(K, M), Option[Long]] = + RedisCommand( + ZRank, + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), + OptionalOutput(LongOutput), + codec, + executor + ) + + final def _zRem[K: Schema, M: Schema]: RedisCommand[(K, (M, List[M])), Long] = + RedisCommand( + ZRem, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(ArbitraryValueInput[M]())), + LongOutput, + codec, + executor + ) + + final def _zRemRangeByLex[K: Schema]: RedisCommand[(K, String, String), Long] = RedisCommand( + ZRemRangeByLex, + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), + LongOutput, + codec, + executor + ) + + final def _zRemRangeByRank[K: Schema]: RedisCommand[(K, Range), Long] = + RedisCommand(ZRemRangeByRank, Tuple2(ArbitraryKeyInput[K](), RangeInput), LongOutput, codec, executor) + + final def _zRemRangeByScore[K: Schema]: RedisCommand[(K, String, String), Long] = RedisCommand( + ZRemRangeByScore, + Tuple3(ArbitraryKeyInput[K](), ArbitraryValueInput[String](), ArbitraryValueInput[String]()), + LongOutput, + codec, + executor + ) + + final def _zRevRange[K: Schema, M: Schema]: RedisCommand[(K, Range), Chunk[M]] = RedisCommand( + ZRevRange, + Tuple2(ArbitraryKeyInput[K](), RangeInput), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zRevRangeWithScores[K: Schema, M: Schema]: RedisCommand[(K, Range, String), Chunk[MemberScore[M]]] = + RedisCommand( + ZRevRange, + Tuple3(ArbitraryKeyInput[K](), RangeInput, ArbitraryValueInput[String]()), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zRevRangeByLex[K: Schema, M: Schema] + : RedisCommand[(K, String, String, Option[zio.redis.Limit]), Chunk[M]] = RedisCommand( + ZRevRangeByLex, + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zRevRangeByScore[K: Schema, M: Schema] + : RedisCommand[(K, String, String, Option[zio.redis.Limit]), Chunk[M]] = RedisCommand( + ZRevRangeByScore, + Tuple4( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zRevRangeByScoreWithScores[K: Schema, M: Schema] + : RedisCommand[(K, String, String, String, Option[zio.redis.Limit]), Chunk[MemberScore[M]]] = RedisCommand( + ZRevRangeByScore, + Tuple5( + ArbitraryKeyInput[K](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + ArbitraryValueInput[String](), + OptionalInput(LimitInput) + ), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zRevRank[K: Schema, M: Schema]: RedisCommand[(K, M), Option[Long]] = RedisCommand( + ZRevRank, + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), + OptionalOutput(LongOutput), + codec, + executor + ) + + final def _zScan[K: Schema, M: Schema] + : RedisCommand[(K, Long, Option[Pattern], Option[Count]), (Long, Chunk[MemberScore[M]])] = { + val memberScoresOutput = + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput).map(_.map { case (m, s) => MemberScore(s, m) }) + + RedisCommand( + ZScan, + Tuple4(ArbitraryKeyInput[K](), LongInput, OptionalInput(PatternInput), OptionalInput(CountInput)), + Tuple2Output(MultiStringOutput.map(_.toLong), memberScoresOutput), + codec, + executor + ) + } + + final def _zScore[K: Schema, M: Schema]: RedisCommand[(K, M), Option[Double]] = RedisCommand( + ZScore, + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[M]()), + OptionalOutput(DoubleOutput), + codec, + executor + ) + + final def _zUnion[K: Schema, M: Schema] + : RedisCommand[(Long, (K, List[K]), Option[::[Double]], Option[zio.redis.Aggregate]), Chunk[M]] = RedisCommand( + ZUnion, + Tuple4( + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()), + OptionalInput(WeightsInput), + OptionalInput(AggregateInput) + ), + ChunkOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zUnionWithScores[K: Schema, M: Schema]: RedisCommand[ + (Long, (K, List[K]), Option[::[Double]], Option[zio.redis.Aggregate], String), + Chunk[MemberScore[M]] + ] = + RedisCommand( + ZUnion, + Tuple5( + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()), + OptionalInput(WeightsInput), + OptionalInput(AggregateInput), + ArbitraryValueInput[String]() + ), + ChunkTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) + + final def _zUnionStore[DK: Schema, K: Schema]: RedisCommand[ + (DK, Long, (K, List[K]), Option[::[Double]], Option[zio.redis.Aggregate]), + Long + ] = RedisCommand( + ZUnionStore, + Tuple5( + ArbitraryValueInput[DK](), + LongInput, + NonEmptyList(ArbitraryKeyInput[K]()), + OptionalInput(WeightsInput), + OptionalInput(AggregateInput) + ), + LongOutput, + codec, + executor + ) + + final def _zMScore[K: Schema]: RedisCommand[(K, List[K]), Chunk[Option[Double]]] = + RedisCommand( + ZMScore, + NonEmptyList(ArbitraryKeyInput[K]()), + ChunkOutput(OptionalOutput(DoubleOutput)), + codec, + executor + ) + + final def _zRandMember[K: Schema, R: Schema]: RedisCommand[K, Option[R]] = + RedisCommand(ZRandMember, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) + + final def _zRandMemberWithCount[K: Schema, M: Schema]: RedisCommand[(K, Long), Chunk[M]] = RedisCommand( + ZRandMember, + Tuple2(ArbitraryKeyInput[K](), LongInput), + ZRandMemberOutput(ArbitraryOutput[M]()), + codec, + executor + ) + + final def _zRandMemberWithScores[K: Schema, M: Schema]: RedisCommand[(K, Long, String), Chunk[MemberScore[M]]] = + RedisCommand( + ZRandMember, + Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[String]()), + ZRandMemberTuple2Output(ArbitraryOutput[M](), DoubleOutput) + .map(_.map { case (m, s) => MemberScore(s, m) }), + codec, + executor + ) +} + +private object SortedSets { + final val BzPopMax = "BZPOPMAX" + final val BzPopMin = "BZPOPMIN" + final val ZAdd = "ZADD" + final val ZCard = "ZCARD" + final val ZCount = "ZCOUNT" + final val ZDiff = "ZDIFF" + final val ZDiffStore = "ZDIFFSTORE" + final val ZIncrBy = "ZINCRBY" + final val ZInter = "ZINTER" + final val ZInterStore = "ZINTERSTORE" + final val ZLexCount = "ZLEXCOUNT" + final val ZMScore = "ZMSCORE" + final val ZPopMax = "ZPOPMAX" + final val ZPopMin = "ZPOPMIN" + final val ZRange = "ZRANGE" + final val ZRangeByLex = "ZRANGEBYLEX" + final val ZRangeByScore = "ZRANGEBYSCORE" + final val ZRank = "ZRANK" + final val ZRem = "ZREM" + final val ZRemRangeByLex = "ZREMRANGEBYLEX" + final val ZRemRangeByRank = "ZREMRANGEBYRANK" + final val ZRemRangeByScore = "ZREMRANGEBYSCORE" + final val ZRevRange = "ZREVRANGE" + final val ZRevRangeByLex = "ZREVRANGEBYLEX" + final val ZRevRangeByScore = "ZREVRANGEBYSCORE" + final val ZRevRank = "ZREVRANK" + final val ZScan = "ZSCAN" + final val ZScore = "ZSCORE" + final val ZUnion = "ZUNION" + final val ZUnionStore = "ZUNIONSTORE" + final val ZRandMember = "ZRANDMEMBER" +} diff --git a/redis/src/main/scala/zio/redis/commands/Streams.scala b/redis/src/main/scala/zio/redis/commands/Streams.scala new file mode 100644 index 000000000..5c9481c68 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Streams.scala @@ -0,0 +1,307 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema +import zio.{Chunk, Duration} + +private[redis] trait Streams extends RedisEnvironment { + import Streams._ + + final def _xAck[SK: Schema, G: Schema, I: Schema]: RedisCommand[(SK, G, (I, List[I])), Long] = RedisCommand( + XAck, + Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[G](), NonEmptyList(ArbitraryValueInput[I]())), + LongOutput, + codec, + executor + ) + + final def _xAdd[SK: Schema, I: Schema, K: Schema, V: Schema, R: Schema]: RedisCommand[ + (SK, Option[StreamMaxLen], I, ((K, V), List[(K, V)])), + R + ] = RedisCommand( + XAdd, + Tuple4( + ArbitraryKeyInput[SK](), + OptionalInput(StreamMaxLenInput), + ArbitraryValueInput[I](), + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())) + ), + ArbitraryOutput[R](), + codec, + executor + ) + + final def _xInfoStream[SK: Schema, RI: Schema, RK: Schema, RV: Schema]: RedisCommand[SK, StreamInfo[RI, RK, RV]] = + RedisCommand(XInfoStream, ArbitraryKeyInput[SK](), StreamInfoOutput[RI, RK, RV](), codec, executor) + + final def _xInfoStreamFull[SK: Schema, RI: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (SK, String), + StreamInfoWithFull.FullStreamInfo[RI, RK, RV] + ] = RedisCommand( + XInfoStream, + Tuple2(ArbitraryKeyInput[SK](), ArbitraryValueInput[String]()), + StreamInfoFullOutput[RI, RK, RV](), + codec, + executor + ) + + final def _xInfoStreamFullWithCount[SK: Schema, RI: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (SK, String, Count), + zio.redis.StreamInfoWithFull.FullStreamInfo[RI, RK, RV] + ] = RedisCommand( + XInfoStream, + Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[String](), CountInput), + StreamInfoFullOutput[RI, RK, RV](), + codec, + executor + ) + + final def _xInfoGroups[SK: Schema]: RedisCommand[SK, Chunk[StreamGroupsInfo]] = + RedisCommand(XInfoGroups, ArbitraryKeyInput[SK](), StreamGroupsInfoOutput, codec, executor) + + final def _xInfoConsumers[SK: Schema, SG: Schema]: RedisCommand[(SK, SG), Chunk[StreamConsumersInfo]] = + RedisCommand( + XInfoConsumers, + Tuple2(ArbitraryKeyInput[SK](), ArbitraryValueInput[SG]()), + StreamConsumersInfoOutput, + codec, + executor + ) + + final def _xAddWithMaxLen[SK: Schema, I: Schema, K: Schema, V: Schema, R: Schema]: RedisCommand[ + (SK, Option[zio.redis.StreamMaxLen], I, ((K, V), List[(K, V)])), + R + ] = RedisCommand( + XAdd, + Tuple4( + ArbitraryKeyInput[SK](), + OptionalInput(StreamMaxLenInput), + ArbitraryValueInput[I](), + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())) + ), + ArbitraryOutput[R](), + codec, + executor + ) + + final def _xClaim[SK: Schema, SG: Schema, SC: Schema, I: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (SK, SG, SC, Duration, (I, List[I]), Option[Duration], Option[Duration], Option[Long], Option[WithForce]), + Chunk[StreamEntry[I, RK, RV]] + ] = RedisCommand( + XClaim, + Tuple9( + ArbitraryKeyInput[SK](), + ArbitraryValueInput[SG](), + ArbitraryValueInput[SC](), + DurationMillisecondsInput, + NonEmptyList(ArbitraryValueInput[I]()), + OptionalInput(IdleInput), + OptionalInput(TimeInput), + OptionalInput(RetryCountInput), + OptionalInput(WithForceInput) + ), + StreamEntriesOutput[I, RK, RV](), + codec, + executor + ) + + final def _xClaimWithJustId[SK: Schema, SG: Schema, SC: Schema, I: Schema, R: Schema]: RedisCommand[ + ( + SK, + SG, + SC, + Duration, + (I, List[I]), + Option[Duration], + Option[Duration], + Option[Long], + Option[WithForce], + WithJustId + ), + Chunk[R] + ] = RedisCommand( + XClaim, + Tuple10( + ArbitraryKeyInput[SK](), + ArbitraryValueInput[SG](), + ArbitraryValueInput[SC](), + DurationMillisecondsInput, + NonEmptyList(ArbitraryValueInput[I]()), + OptionalInput(IdleInput), + OptionalInput(TimeInput), + OptionalInput(RetryCountInput), + OptionalInput(WithForceInput), + WithJustIdInput + ), + ChunkOutput(ArbitraryOutput[R]()), + codec, + executor + ) + + final def _xDel[SK: Schema, I: Schema]: RedisCommand[(SK, (I, List[I])), Long] = + RedisCommand( + XDel, + Tuple2(ArbitraryKeyInput[SK](), NonEmptyList(ArbitraryValueInput[I]())), + LongOutput, + codec, + executor + ) + + final def _xGroupCreate[SK: Schema, SG: Schema, I: Schema]: RedisCommand[XGroupCommand.Create[SK, SG, I], Unit] = + RedisCommand(XGroup, XGroupCreateInput[SK, SG, I](), UnitOutput, codec, executor) + + final def _xGroupSetId[SK: Schema, SG: Schema, I: Schema] + : RedisCommand[zio.redis.XGroupCommand.SetId[SK, SG, I], Unit] = + RedisCommand(XGroup, XGroupSetIdInput[SK, SG, I](), UnitOutput, codec, executor) + + final def _xGroupDestroy[SK: Schema, SG: Schema]: RedisCommand[zio.redis.XGroupCommand.Destroy[SK, SG], Boolean] = + RedisCommand(XGroup, XGroupDestroyInput[SK, SG](), BoolOutput, codec, executor) + + final def _xGroupCreateConsumer[SK: Schema, SG: Schema, SC: Schema] + : RedisCommand[zio.redis.XGroupCommand.CreateConsumer[SK, SG, SC], Boolean] = + RedisCommand(XGroup, XGroupCreateConsumerInput[SK, SG, SC](), BoolOutput, codec, executor) + + final def _xGroupDelConsumer[SK: Schema, SG: Schema, SC: Schema] + : RedisCommand[zio.redis.XGroupCommand.DelConsumer[SK, SG, SC], Long] = + RedisCommand(XGroup, XGroupDelConsumerInput[SK, SG, SC](), LongOutput, codec, executor) + + final def _xLen[SK: Schema]: RedisCommand[SK, Long] = + RedisCommand(XLen, ArbitraryKeyInput[SK](), LongOutput, codec, executor) + + final def _xPending[SK: Schema, SG: Schema]: RedisCommand[(SK, SG, Option[Duration]), PendingInfo] = RedisCommand( + XPending, + Tuple3(ArbitraryKeyInput[SK](), ArbitraryValueInput[SG](), OptionalInput(IdleInput)), + XPendingOutput, + codec, + executor + ) + + final def _xPendingMessages[SK: Schema, SG: Schema, I: Schema, SC: Schema]: RedisCommand[ + (SK, SG, Option[Duration], I, I, Long, Option[SC]), + Chunk[PendingMessage] + ] = RedisCommand( + XPending, + Tuple7( + ArbitraryKeyInput[SK](), + ArbitraryValueInput[SG](), + OptionalInput(IdleInput), + ArbitraryValueInput[I](), + ArbitraryValueInput[I](), + LongInput, + OptionalInput(ArbitraryValueInput[SC]()) + ), + PendingMessagesOutput, + codec, + executor + ) + + final def _xRange[SK: Schema, I: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (SK, I, I, Option[zio.redis.Count]), + Chunk[zio.redis.StreamEntry[I, RK, RV]] + ] = RedisCommand( + XRange, + Tuple4(ArbitraryKeyInput[SK](), ArbitraryValueInput[I](), ArbitraryValueInput[I](), OptionalInput(CountInput)), + StreamEntriesOutput[I, RK, RV](), + codec, + executor + ) + + final def _xRangeWithCount[SK: Schema, I: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (SK, I, I, Option[zio.redis.Count]), + Chunk[zio.redis.StreamEntry[I, RK, RV]] + ] = RedisCommand( + XRange, + Tuple4(ArbitraryKeyInput[SK](), ArbitraryValueInput[I](), ArbitraryValueInput[I](), OptionalInput(CountInput)), + StreamEntriesOutput[I, RK, RV](), + codec, + executor + ) + + final def _xRead[SK: Schema, I: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (Option[zio.redis.Count], Option[Duration], ((SK, I), Chunk[(SK, I)])), + Chunk[StreamChunk[SK, I, RK, RV]] + ] = RedisCommand( + XRead, + Tuple3(OptionalInput(CountInput), OptionalInput(BlockInput), StreamsInput[SK, I]()), + ChunkOutput(StreamOutput[SK, I, RK, RV]()), + codec, + executor + ) + + final def _xReadGroup[SG: Schema, SC: Schema, SK: Schema, I: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (SG, SC, Option[zio.redis.Count], Option[Duration], Option[NoAck], ((SK, I), Chunk[(SK, I)])), + Chunk[zio.redis.StreamChunk[SK, I, RK, RV]] + ] = RedisCommand( + XReadGroup, + Tuple6( + ArbitraryValueInput[SG](), + ArbitraryValueInput[SC](), + OptionalInput(CountInput), + OptionalInput(BlockInput), + OptionalInput(NoAckInput), + StreamsInput[SK, I]() + ), + ChunkOutput(StreamOutput[SK, I, RK, RV]()), + codec, + executor + ) + + final def _xRevRange[SK: Schema, I: Schema, RK: Schema, RV: Schema]: RedisCommand[ + (SK, I, I, Option[zio.redis.Count]), + Chunk[zio.redis.StreamEntry[I, RK, RV]] + ] = RedisCommand( + XRevRange, + Tuple4(ArbitraryKeyInput[SK](), ArbitraryValueInput[I](), ArbitraryValueInput[I](), OptionalInput(CountInput)), + StreamEntriesOutput[I, RK, RV](), + codec, + executor + ) + + final def _xRevRangeWithCount[SK: Schema, I: Schema, RK: Schema, RV: Schema] + : RedisCommand[(SK, I, I, Option[zio.redis.Count]), Chunk[zio.redis.StreamEntry[I, RK, RV]]] = RedisCommand( + XRevRange, + Tuple4(ArbitraryKeyInput[SK](), ArbitraryValueInput[I](), ArbitraryValueInput[I](), OptionalInput(CountInput)), + StreamEntriesOutput[I, RK, RV](), + codec, + executor + ) + + final def _xTrim[SK: Schema]: RedisCommand[(SK, zio.redis.StreamMaxLen), Long] = + RedisCommand(XTrim, Tuple2(ArbitraryKeyInput[SK](), StreamMaxLenInput), LongOutput, codec, executor) +} + +private object Streams { + final val XAck = "XACK" + final val XAdd = "XADD" + final val XClaim = "XCLAIM" + final val XDel = "XDEL" + final val XGroup = "XGROUP" + final val XInfoStream = "XINFO STREAM" + final val XInfoGroups = "XINFO GROUPS" + final val XInfoConsumers = "XINFO CONSUMERS" + final val XLen = "XLEN" + final val XPending = "XPENDING" + final val XRange = "XRANGE" + final val XRead = "XREAD" + final val XReadGroup = "XREADGROUP GROUP" + final val XRevRange = "XREVRANGE" + final val XTrim = "XTRIM" +} diff --git a/redis/src/main/scala/zio/redis/commands/Strings.scala b/redis/src/main/scala/zio/redis/commands/Strings.scala new file mode 100644 index 000000000..3c8d1d396 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Strings.scala @@ -0,0 +1,228 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ +import zio.schema.Schema +import zio.{Chunk, Duration} + +import java.time.Instant + +private[redis] trait Strings extends RedisEnvironment { + import Strings._ + + final def _append[K: Schema, V: Schema]: RedisCommand[(K, V), Long] = + RedisCommand(Append, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), LongOutput, codec, executor) + + final def _bitCount[K: Schema]: RedisCommand[(K, Option[Range]), Long] = + RedisCommand(BitCount, Tuple2(ArbitraryKeyInput[K](), OptionalInput(RangeInput)), LongOutput, codec, executor) + + final def _bitField[K: Schema]: RedisCommand[(K, (BitFieldCommand, List[BitFieldCommand])), Chunk[Option[Long]]] = + RedisCommand( + BitField, + Tuple2(ArbitraryKeyInput[K](), NonEmptyList(BitFieldCommandInput)), + ChunkOutput(OptionalOutput(LongOutput)), + codec, + executor + ) + + final def _bitOp[D: Schema, S: Schema]: RedisCommand[(BitOperation, D, (S, List[S])), Long] = + RedisCommand( + BitOp, + Tuple3(BitOperationInput, ArbitraryValueInput[D](), NonEmptyList(ArbitraryValueInput[S]())), + LongOutput, + codec, + executor + ) + + final def _bitPos[K: Schema]: RedisCommand[(K, Boolean, Option[BitPosRange]), Long] = RedisCommand( + BitPos, + Tuple3(ArbitraryKeyInput[K](), BoolInput, OptionalInput(BitPosRangeInput)), + LongOutput, + codec, + executor + ) + + final def _decr[K: Schema]: RedisCommand[K, Long] = + RedisCommand(Decr, ArbitraryKeyInput[K](), LongOutput, codec, executor) + + final def _decrBy[K: Schema]: RedisCommand[(K, Long), Long] = + RedisCommand(DecrBy, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) + + final def _get[K: Schema, R: Schema]: RedisCommand[K, Option[R]] = + RedisCommand(Get, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) + + final def _getBit[K: Schema]: RedisCommand[(K, Long), Long] = + RedisCommand(GetBit, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) + + final def _getRange[K: Schema, R: Schema]: RedisCommand[(K, Range), Option[R]] = RedisCommand( + GetRange, + Tuple2(ArbitraryKeyInput[K](), RangeInput), + OptionalOutput(ArbitraryOutput[R]()), + codec, + executor + ) + + final def _getSet[K: Schema, V: Schema, R: Schema]: RedisCommand[(K, V), Option[R]] = RedisCommand( + GetSet, + Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), + OptionalOutput(ArbitraryOutput[R]()), + codec, + executor + ) + + final def _getDel[K: Schema, R: Schema]: RedisCommand[K, Option[R]] = + RedisCommand(GetDel, ArbitraryKeyInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) + + final def _getEx[K: Schema, R: Schema]: RedisCommand[(K, Expire, Duration), Option[R]] = + RedisCommand(GetEx, GetExInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) + + final def _getExAt[K: Schema, R: Schema]: RedisCommand[(K, ExpiredAt, Instant), Option[R]] = + RedisCommand(GetEx, GetExAtInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) + + final def _getExDel[K: Schema, R: Schema]: RedisCommand[(K, Boolean), Option[R]] = + RedisCommand(GetEx, GetExPersistInput[K](), OptionalOutput(ArbitraryOutput[R]()), codec, executor) + + final def _incr[K: Schema]: RedisCommand[K, Long] = + RedisCommand(Incr, ArbitraryKeyInput[K](), LongOutput, codec, executor) + + final def _incrBy[K: Schema]: RedisCommand[(K, Long), Long] = + RedisCommand(IncrBy, Tuple2(ArbitraryKeyInput[K](), LongInput), LongOutput, codec, executor) + + final def _incrByFloat[K: Schema]: RedisCommand[(K, Double), Double] = + RedisCommand(IncrByFloat, Tuple2(ArbitraryKeyInput[K](), DoubleInput), DoubleOutput, codec, executor) + + final def _mGet[K: Schema, V: Schema]: RedisCommand[(K, List[K]), Chunk[Option[V]]] = RedisCommand( + MGet, + NonEmptyList(ArbitraryKeyInput[K]()), + ChunkOutput(OptionalOutput(ArbitraryOutput[V]())), + codec, + executor + ) + + final def _mSet[K: Schema, V: Schema]: RedisCommand[((K, V), List[(K, V)]), Unit] = + RedisCommand( + MSet, + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())), + UnitOutput, + codec, + executor + ) + + final def _mSetNx[K: Schema, V: Schema]: RedisCommand[((K, V), List[(K, V)]), Boolean] = + RedisCommand( + MSetNx, + NonEmptyList(Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]())), + BoolOutput, + codec, + executor + ) + + final def _pSetEx[K: Schema, V: Schema]: RedisCommand[(K, Duration, V), Unit] = RedisCommand( + PSetEx, + Tuple3(ArbitraryKeyInput[K](), DurationMillisecondsInput, ArbitraryValueInput[V]()), + UnitOutput, + codec, + executor + ) + + final def _set[K: Schema, V: Schema] + : RedisCommand[(K, V, Option[Duration], Option[Update], Option[KeepTtl]), Boolean] = + RedisCommand( + Set, + Tuple5( + ArbitraryKeyInput[K](), + ArbitraryValueInput[V](), + OptionalInput(DurationTtlInput), + OptionalInput(UpdateInput), + OptionalInput(KeepTtlInput) + ), + SetOutput, + codec, + executor + ) + + final def _setBit[K: Schema]: RedisCommand[(K, Long, Boolean), Boolean] = + RedisCommand(SetBit, Tuple3(ArbitraryKeyInput[K](), LongInput, BoolInput), BoolOutput, codec, executor) + + final def _setEx[K: Schema, V: Schema]: RedisCommand[(K, Duration, V), Unit] = RedisCommand( + SetEx, + Tuple3(ArbitraryKeyInput[K](), DurationSecondsInput, ArbitraryValueInput[V]()), + UnitOutput, + codec, + executor + ) + + final def _setNx[K: Schema, V: Schema]: RedisCommand[(K, V), Boolean] = + RedisCommand(SetNx, Tuple2(ArbitraryKeyInput[K](), ArbitraryValueInput[V]()), BoolOutput, codec, executor) + + final def _setRange[K: Schema, V: Schema]: RedisCommand[(K, Long, V), Long] = RedisCommand( + SetRange, + Tuple3(ArbitraryKeyInput[K](), LongInput, ArbitraryValueInput[V]()), + LongOutput, + codec, + executor + ) + + final def _strLen[K: Schema]: RedisCommand[K, Long] = + RedisCommand(StrLen, ArbitraryKeyInput[K](), LongOutput, codec, executor) + + final def _strAlgoLcs[K: Schema]: RedisCommand[(String, K, K, Option[StrAlgoLcsQueryType]), LcsOutput] = RedisCommand( + StrAlgoLcs, + Tuple4( + ArbitraryValueInput[String](), + ArbitraryKeyInput[K](), + ArbitraryKeyInput[K](), + OptionalInput(StralgoLcsQueryTypeInput) + ), + StrAlgoLcsOutput, + codec, + executor + ) +} + +private object Strings { + final val Append = "APPEND" + final val BitCount = "BITCOUNT" + final val BitField = "BITFIELD" + final val BitOp = "BITOP" + final val BitPos = "BITPOS" + final val Decr = "DECR" + final val DecrBy = "DECRBY" + final val Get = "GET" + final val GetBit = "GETBIT" + final val GetRange = "GETRANGE" + final val GetSet = "GETSET" + final val Incr = "INCR" + final val IncrBy = "INCRBY" + final val IncrByFloat = "INCRBYFLOAT" + final val MGet = "MGET" + final val MSet = "MSET" + final val MSetNx = "MSETNX" + final val PSetEx = "PSETEX" + final val Set = "SET" + final val SetBit = "SETBIT" + final val SetEx = "SETEX" + final val SetNx = "SETNX" + final val SetRange = "SETRANGE" + final val StrLen = "STRLEN" + final val StrAlgoLcs = "STRALGO LCS" + final val GetDel = "GETDEL" + final val GetEx = "GETEX" +} diff --git a/redis/src/main/scala/zio/redis/commands/Transactions.scala b/redis/src/main/scala/zio/redis/commands/Transactions.scala new file mode 100644 index 000000000..9b8348c84 --- /dev/null +++ b/redis/src/main/scala/zio/redis/commands/Transactions.scala @@ -0,0 +1,35 @@ +/* + * 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.commands + +import zio.redis.Input._ +import zio.redis.Output._ +import zio.redis._ + +private[redis] trait Transactions extends RedisEnvironment { + import Transactions._ + + final val _multi: RedisCommand[Unit, Unit] = RedisCommand(Multi, NoInput, UnitOutput, codec, executor) + + final def _exec[Out](output: Output[Out]): RedisCommand[Unit, Out] = + RedisCommand(Exec, NoInput, output, codec, executor) +} + +private object Transactions { + final val Multi = "Multi" + final val Exec = "Exec" +} diff --git a/redis/src/main/scala/zio/redis/transactional/Redis.scala b/redis/src/main/scala/zio/redis/transactional/Redis.scala new file mode 100644 index 000000000..d76af5a52 --- /dev/null +++ b/redis/src/main/scala/zio/redis/transactional/Redis.scala @@ -0,0 +1,31 @@ +/* + * 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.transactional + +import zio.redis.RedisExecutor +import zio.redis.commands.Transactions +import zio.schema.codec.BinaryCodec +import zio.{URLayer, ZLayer} + +trait Redis extends api.Sets with Transactions + +object Redis { + lazy val layer: URLayer[RedisExecutor with BinaryCodec, Redis] = + ZLayer.fromFunction(Live.apply _) + + private final case class Live(codec: BinaryCodec, executor: RedisExecutor) extends Redis +} diff --git a/redis/src/main/scala/zio/redis/transactional/RedisTransaction.scala b/redis/src/main/scala/zio/redis/transactional/RedisTransaction.scala new file mode 100644 index 000000000..d7c1f3424 --- /dev/null +++ b/redis/src/main/scala/zio/redis/transactional/RedisTransaction.scala @@ -0,0 +1,101 @@ +/* + * 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.transactional + +import zio.redis.Output.QueuedOutput +import zio.redis.{Output, RedisCommand, RedisError} +import zio.{ZIO, Zippable} + +sealed trait RedisTransaction[+Out] { self => + import RedisTransaction._ + + def commit: ZIO[Redis, RedisError, Out] = + ZIO.serviceWithZIO[Redis] { redis => + self match { + case Single(command, in) => + command.run(in) + case _ => + redis._multi + .run(()) + .zipRight( + run.flatMap(output => redis._exec(output).run(())) + ) + } + } + + def zip[A](that: RedisTransaction[A])(implicit zippable: Zippable[Out, A]): RedisTransaction[zippable.Out] = + Zip(this, that).map { case (left, right) => zippable.zip(left, right) } + + def zipLeft[A](that: RedisTransaction[A]): RedisTransaction[Out] = + ZipLeft(this, that) + + def zipRight[A](that: RedisTransaction[A]): RedisTransaction[A] = + ZipRight(this, that) + + def map[A](f: Out => A): RedisTransaction[A] = Map(self, f) + + private[transactional] def run: ZIO[Redis, RedisError, Output[Out]] +} + +object RedisTransaction { + final def single[In, Out](command: RedisCommand[In, Out], in: In): RedisTransaction[Out] = + Single(command, in) + + private[transactional] final case class Single[In, Out]( + command: RedisCommand[In, Out], + in: In + ) extends RedisTransaction[Out] { + def run: ZIO[Redis, RedisError, Output[Out]] = + command.executor + .execute(command.resp(in)) + .flatMap(out => ZIO.attempt(QueuedOutput.unsafeDecode(out)(command.codec))) + .refineToOrDie[RedisError] + .as(command.output) + } + + private[transactional] final case class Zip[A, B]( + left: RedisTransaction[A], + right: RedisTransaction[B] + ) extends RedisTransaction[(A, B)] { + def run: ZIO[Redis, RedisError, Output[(A, B)]] = + left.run.zip(right.run).map(outputs => Output.Zip(outputs._1, outputs._2)) + } + + private[transactional] final case class ZipLeft[A, B]( + left: RedisTransaction[A], + right: RedisTransaction[B] + ) extends RedisTransaction[A] { + def run: ZIO[Redis, RedisError, Output[A]] = + left.run.zip(right.run).map(outputs => Output.ZipLeft(outputs._1, outputs._2)) + } + + private[transactional] final case class ZipRight[A, B]( + left: RedisTransaction[A], + right: RedisTransaction[B] + ) extends RedisTransaction[B] { + def run: ZIO[Redis, RedisError, Output[B]] = + left.run.zip(right.run).map(outputs => Output.ZipRight(outputs._1, outputs._2)) + } + + private[transactional] final case class Map[A, B]( + transaction: RedisTransaction[A], + f: A => B + ) extends RedisTransaction[B] { + def run: ZIO[Redis, RedisError, Output[B]] = + transaction.run.map(output => output.map(out => f(out))) + } +} diff --git a/redis/src/main/scala/zio/redis/transactional/ResultBuilder.scala b/redis/src/main/scala/zio/redis/transactional/ResultBuilder.scala new file mode 100644 index 000000000..13faa082e --- /dev/null +++ b/redis/src/main/scala/zio/redis/transactional/ResultBuilder.scala @@ -0,0 +1,51 @@ +/* + * 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.transactional + +import zio.ZIO +import zio.redis.transactional.ResultBuilder.NeedsReturnType +import zio.redis.{Output, RedisError} +import zio.schema.Schema + +sealed trait ResultBuilder { + + final def map(f: Nothing => Any)(implicit nrt: NeedsReturnType): RedisTransaction[Nothing] = ??? + + final def flatMap(f: Nothing => Any)(implicit nrt: NeedsReturnType): RedisTransaction[Nothing] = ??? +} + +object ResultBuilder { + + @annotation.implicitNotFound("Use `returning[A]` to specify method's return type") + final abstract class NeedsReturnType + + trait ResultBuilder1[+F[_]] extends ResultBuilder { + def returning[R: Schema]: RedisTransaction[F[R]] + } + + trait ResultBuilder2[+F[_, _]] extends ResultBuilder { + def returning[R1: Schema, R2: Schema]: RedisTransaction[F[R1, R2]] + } + + trait ResultBuilder3[+F[_, _, _]] extends ResultBuilder { + def returning[R1: Schema, R2: Schema, R3: Schema]: RedisTransaction[F[R1, R2, R3]] + } + + trait ResultOutputBuilder extends ResultBuilder { + def returning[R: Output]: ZIO[Redis, RedisError, R] + } +} diff --git a/redis/src/main/scala/zio/redis/transactional/api/Sets.scala b/redis/src/main/scala/zio/redis/transactional/api/Sets.scala new file mode 100644 index 000000000..b13f06b57 --- /dev/null +++ b/redis/src/main/scala/zio/redis/transactional/api/Sets.scala @@ -0,0 +1,259 @@ +/* + * 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.transactional.api + +import zio._ +import zio.redis._ +import zio.redis.transactional.RedisTransaction +import zio.redis.transactional.RedisTransaction.single +import zio.redis.transactional.ResultBuilder._ +import zio.schema.Schema + +trait Sets extends commands.Sets { + + /** + * Add one or more members to a set. + * + * @param key + * Key of set to add to + * @param member + * first member to add + * @param members + * subsequent members to add + * @return + * Returns the number of elements that were added to the set, not including all the elements already present into + * the set. + */ + final def sAdd[K: Schema, M: Schema](key: K, member: M, members: M*): RedisTransaction[Long] = + single(_sAdd[K, M], (key, (member, members.toList))) + + /** + * Get the number of members in a set. + * + * @param key + * Key of set to get the number of members of + * @return + * Returns the cardinality (number of elements) of the set, or 0 if key does not exist. + */ + final def sCard[K: Schema](key: K): RedisTransaction[Long] = single(_sCard[K], key) + + /** + * Subtract multiple sets. + * + * @param key + * Key of the set to subtract from + * @param keys + * Keys of the sets to subtract + * @return + * Returns the members of the set resulting from the difference between the first set and all the successive sets. + */ + final def sDiff[K: Schema](key: K, keys: K*): ResultBuilder1[Chunk] = + new ResultBuilder1[Chunk] { + def returning[R: Schema]: RedisTransaction[Chunk[R]] = single(_sDiff[K, R], (key, keys.toList)) + } + + /** + * Subtract multiple sets and store the resulting set in a key. + * + * @param destination + * Key of set to store the resulting set + * @param key + * Key of set to be subtracted from + * @param keys + * Keys of sets to subtract + * @return + * Returns the number of elements in the resulting set. + */ + final def sDiffStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): RedisTransaction[Long] = + single(_sDiffStore[D, K], (destination, (key, keys.toList))) + + /** + * Intersect multiple sets and store the resulting set in a key. + * + * @param destination + * Key of set to store the resulting set + * @param keys + * Keys of the sets to intersect with each other + * @return + * Returns the members of the set resulting from the intersection of all the given sets. + */ + final def sInter[K: Schema](destination: K, keys: K*): ResultBuilder1[Chunk] = + new ResultBuilder1[Chunk] { + def returning[R: Schema]: RedisTransaction[Chunk[R]] = + single(_sInter[K, R], (destination, keys.toList)) + } + + /** + * Intersect multiple sets and store the resulting set in a key. + * + * @param destination + * Key of set to store the resulting set + * @param key + * Key of first set to intersect + * @param keys + * Keys of subsequent sets to intersect + * @return + * Returns the number of elements in the resulting set. + */ + final def sInterStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): RedisTransaction[Long] = + single(_sInterStore[D, K], (destination, (key, keys.toList))) + + /** + * Determine if a given value is a member of a set. + * + * @param key + * of the set + * @param member + * value which should be searched in the set + * @return + * Returns 1 if the element is a member of the set. 0 if the element is not a member of the set, or if key does not + * exist. + */ + final def sIsMember[K: Schema, M: Schema](key: K, member: M): RedisTransaction[Boolean] = + single(_sIsMember[K, M], (key, member)) + + /** + * Get all the members in a set. + * + * @param key + * Key of the set to get the members of + * @return + * Returns the members of the set. + */ + final def sMembers[K: Schema](key: K): ResultBuilder1[Chunk] = + new ResultBuilder1[Chunk] { + def returning[R: Schema]: RedisTransaction[Chunk[R]] = single(_sMembers[K, R], key) + } + + /** + * Move a member from one set to another. + * + * @param source + * Key of the set to move the member from + * @param destination + * Key of the set to move the member to + * @param member + * Element to move + * @return + * Returns 1 if the element was moved. 0 if it was not found. + */ + final def sMove[S: Schema, D: Schema, M: Schema](source: S, destination: D, member: M): RedisTransaction[Boolean] = + single(_sMove[S, D, M], (source, destination, member)) + + /** + * Remove and return one or multiple random members from a set. + * + * @param key + * Key of the set to remove items from + * @param count + * Number of elements to remove + * @return + * Returns the elements removed. + */ + final def sPop[K: Schema](key: K, count: Option[Long] = None): ResultBuilder1[Chunk] = + new ResultBuilder1[Chunk] { + def returning[R: Schema]: RedisTransaction[Chunk[R]] = single(_sPop[K, R], (key, count)) + } + + /** + * Get one or multiple random members from a set. + * + * @param key + * Key of the set to get members from + * @param count + * Number of elements to randomly get + * @return + * Returns the random members. + */ + final def sRandMember[K: Schema](key: K, count: Option[Long] = None): ResultBuilder1[Chunk] = + new ResultBuilder1[Chunk] { + def returning[R: Schema]: RedisTransaction[Chunk[R]] = single(_sRandMember[K, R], (key, count)) + } + + /** + * Remove one of more members from a set. + * + * @param key + * Key of the set to remove members from + * @param member + * Value of the first element to remove + * @param members + * Subsequent values of elements to remove + * @return + * Returns the number of members that were removed from the set, not including non existing members. + */ + final def sRem[K: Schema, M: Schema](key: K, member: M, members: M*): RedisTransaction[Long] = + single(_sRem[K, M], (key, (member, members.toList))) + + /** + * Incrementally iterate Set elements. + * + * This is a cursor based scan of an entire set. Call initially with cursor set to 0 and on subsequent calls pass the + * return value as the next cursor. + * + * @param key + * Key of the set to scan + * @param cursor + * Cursor to use for this iteration of scan + * @param pattern + * Glob-style pattern that filters which elements are returned + * @param count + * Count of elements. Roughly this number will be returned by Redis if possible + * @return + * Returns the next cursor, and items for this iteration or nothing when you reach the end, as a tuple. + */ + final def sScan[K: Schema]( + key: K, + cursor: Long, + pattern: Option[String] = None, + count: Option[Count] = None + ): ResultBuilder1[({ type lambda[x] = (Long, Chunk[x]) })#lambda] = + new ResultBuilder1[({ type lambda[x] = (Long, Chunk[x]) })#lambda] { + def returning[R: Schema]: RedisTransaction[(Long, Chunk[R])] = + single(_sScan[K, R], (key, cursor, pattern.map(Pattern(_)), count)) + } + + /** + * Add multiple sets. + * + * @param key + * Key of the first set to add + * @param keys + * Keys of the subsequent sets to add + * @return + * Returns a list with members of the resulting set. + */ + final def sUnion[K: Schema](key: K, keys: K*): ResultBuilder1[Chunk] = + new ResultBuilder1[Chunk] { + def returning[R: Schema]: RedisTransaction[Chunk[R]] = single(_sUnion[K, R], (key, keys.toList)) + } + + /** + * Add multiple sets and add the resulting set in a key. + * + * @param destination + * Key of destination to store the result + * @param key + * Key of first set to add + * @param keys + * Subsequent keys of sets to add + * @return + * Returns the number of elements in the resulting set. + */ + final def sUnionStore[D: Schema, K: Schema](destination: D, key: K, keys: K*): RedisTransaction[Long] = + single(_sUnionStore[D, K], (destination, (key, keys.toList))) +} diff --git a/redis/src/test/scala/zio/redis/ApiSpec.scala b/redis/src/test/scala/zio/redis/ApiSpec.scala index 38318e409..144b4fd73 100644 --- a/redis/src/test/scala/zio/redis/ApiSpec.scala +++ b/redis/src/test/scala/zio/redis/ApiSpec.scala @@ -1,6 +1,7 @@ package zio.redis import zio._ +import zio.redis.transactional.RedisTransactionSpec import zio.test.TestAspect._ import zio.test._ @@ -16,7 +17,8 @@ object ApiSpec with HashSpec with StreamsSpec with ScriptingSpec - with ClusterSpec { + with ClusterSpec + with RedisTransactionSpec { def spec: Spec[TestEnvironment, Any] = suite("Redis commands")(clusterSuite, singleNodeSuite) @@ sequential @@ withLiveEnvironment @@ -33,11 +35,13 @@ object ApiSpec hyperLogLogSuite, hashSuite, streamsSuite, - scriptingSpec + scriptingSpec, + transactionsSuite ).provideShared( RedisExecutor.local, Redis.layer, - ZLayer.succeed(codec) + ZLayer.succeed(codec), + transactional.Redis.layer ) private val clusterSuite = diff --git a/redis/src/test/scala/zio/redis/StringsSpec.scala b/redis/src/test/scala/zio/redis/StringsSpec.scala index 4623f5a66..5d98930cb 100644 --- a/redis/src/test/scala/zio/redis/StringsSpec.scala +++ b/redis/src/test/scala/zio/redis/StringsSpec.scala @@ -317,11 +317,11 @@ trait StringsSpec extends BaseSpec { } yield assert(result)(equalTo(Chunk(Some(97L), Some(100L), Some(100L)))) } ), - suite("Stralgo")( + suite("StrAlgo")( test("get LCS from 2 strings") { val str1 = "foo" val str2 = "fao" - assertZIO(ZIO.serviceWithZIO[Redis](_.stralgoLcs(StralgoLCS.Strings, str1, str2)))( + assertZIO(ZIO.serviceWithZIO[Redis](_.strAlgoLcs(StralgoLCS.Strings, str1, str2)))( equalTo(LcsOutput.Lcs("fo")) ) }, @@ -335,7 +335,7 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1, None, None, None) key2 <- uuid _ <- redis.set(key2, str2, None, None, None) - result <- redis.stralgoLcs(StralgoLCS.Keys, key1, key2) + result <- redis.strAlgoLcs(StralgoLCS.Keys, key1, key2) } yield assert(result)(equalTo(LcsOutput.Lcs("fo"))) }, test("get LCS from unknown keys") { @@ -348,14 +348,14 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1, None, None, None) key2 <- uuid _ <- redis.set(key2, str2, None, None, None) - result <- redis.stralgoLcs(StralgoLCS.Keys, "unknown", "unknown") + result <- redis.strAlgoLcs(StralgoLCS.Keys, "unknown", "unknown") } yield assert(result)(equalTo(LcsOutput.Lcs(""))) }, test("Get length of LCS for strings") { val str1 = "foo" val str2 = "fao" assertZIO( - ZIO.serviceWithZIO[Redis](_.stralgoLcs(StralgoLCS.Strings, str1, str2, Some(StrAlgoLcsQueryType.Len))) + ZIO.serviceWithZIO[Redis](_.strAlgoLcs(StralgoLCS.Strings, str1, str2, Some(StrAlgoLcsQueryType.Len))) )( equalTo(LcsOutput.Length(2)) ) @@ -370,7 +370,7 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1, None, None, None) key2 <- uuid _ <- redis.set(key2, str2, None, None, None) - result <- redis.stralgoLcs(StralgoLCS.Keys, key1, key2, Some(StrAlgoLcsQueryType.Len)) + result <- redis.strAlgoLcs(StralgoLCS.Keys, key1, key2, Some(StrAlgoLcsQueryType.Len)) } yield assert(result)(equalTo(LcsOutput.Length(2))) }, test("get length of LCS for unknown keys") { @@ -383,7 +383,7 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1, None, None, None) key2 <- uuid _ <- redis.set(key2, str2, None, None, None) - result <- redis.stralgoLcs( + result <- redis.strAlgoLcs( StralgoLCS.Keys, "unknown", "unknown", @@ -395,7 +395,7 @@ trait StringsSpec extends BaseSpec { val str1 = "ohmytext" val str2 = "mynewtext" assertZIO( - ZIO.serviceWithZIO[Redis](_.stralgoLcs(StralgoLCS.Strings, str1, str2, Some(StrAlgoLcsQueryType.Idx()))) + ZIO.serviceWithZIO[Redis](_.strAlgoLcs(StralgoLCS.Strings, str1, str2, Some(StrAlgoLcsQueryType.Idx()))) )( equalTo( LcsOutput.Matches( @@ -418,7 +418,7 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1) key2 <- uuid _ <- redis.set(key2, str2) - result <- redis.stralgoLcs(StralgoLCS.Keys, key1, key2, Some(StrAlgoLcsQueryType.Idx())) + result <- redis.strAlgoLcs(StralgoLCS.Keys, key1, key2, Some(StrAlgoLcsQueryType.Idx())) } yield { assert(result)( equalTo( @@ -444,7 +444,7 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1) key2 <- uuid _ <- redis.set(key2, str2) - result <- redis.stralgoLcs( + result <- redis.strAlgoLcs( StralgoLCS.Keys, key1, key2, @@ -474,7 +474,7 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1) key2 <- uuid _ <- redis.set(key2, str2) - result <- redis.stralgoLcs( + result <- redis.strAlgoLcs( StralgoLCS.Keys, key1, key2, @@ -505,7 +505,7 @@ trait StringsSpec extends BaseSpec { _ <- redis.set(key1, str1) key2 <- uuid _ <- redis.set(key2, str2) - result <- redis.stralgoLcs( + result <- redis.strAlgoLcs( StralgoLCS.Keys, key1, key2, diff --git a/redis/src/test/scala/zio/redis/transactional/RedisTransactionSpec.scala b/redis/src/test/scala/zio/redis/transactional/RedisTransactionSpec.scala new file mode 100644 index 000000000..a2d9370e2 --- /dev/null +++ b/redis/src/test/scala/zio/redis/transactional/RedisTransactionSpec.scala @@ -0,0 +1,62 @@ +package zio.redis.transactional + +import zio.redis.{BaseSpec, RedisError} +import zio.test.Assertion._ +import zio.test.{Spec, _} +import zio.{Chunk, ZIO} + +trait RedisTransactionSpec extends BaseSpec { + def transactionsSuite: Spec[Redis, RedisError] = + suite("RedisTransaction")( + suite("zip")( + test("nested commands")( + for { + redis <- ZIO.service[Redis] + key <- uuid + result <- + redis + .sAdd(key, "hello") + .zip(redis.sAdd(key, "world")) + .zip(redis.sMembers(key).returning[String]) + .commit + } yield assert(result._1)(equalTo(1L)) && + assert(result._2)(equalTo(1L)) && + assert(result._3)(hasSameElements(Chunk("hello", "world"))) + ) + ), + suite("zipLeft")( + test("nested command")( + for { + redis <- ZIO.service[Redis] + key <- uuid + result <- redis + .sAdd(key, "hello") + .zip(redis.sAdd(key, "world").zipLeft(redis.sMembers(key).returning[String])) + .commit + } yield assert(result)(equalTo((1L, 1L))) + ), + test("ignore nested command")( + for { + redis <- ZIO.service[Redis] + key <- uuid + result <- redis + .sAdd(key, "hello") + .zipLeft(redis.sAdd(key, "world").zipRight(redis.sMembers(key).returning[String])) + .commit + } yield assert(result)(equalTo(1L)) + ) + ), + suite("zipRight")( + test("nested command")( + for { + redis <- ZIO.service[Redis] + key <- uuid + result <- redis + .sAdd(key, "hello") + .zip(redis.sAdd(key, "world").zipRight(redis.sMembers(key).returning[String])) + .commit + } yield assert(result._1)(equalTo(1L)) && assert(result._2)(hasSameElements(Chunk("hello", "world"))) + ) + ) + ) +}