├── .gitignore ├── LICENSE ├── README.md ├── build.sbt ├── project └── build.properties └── src ├── main └── scala │ └── redis │ └── algebra │ ├── connection.scala │ ├── data.scala │ ├── hash.scala │ ├── key.scala │ ├── list.scala │ ├── package.scala │ ├── script.scala │ ├── server.scala │ ├── set.scala │ ├── string.scala │ └── zset.scala └── test └── scala └── redis └── algebra ├── bytestring.scala ├── interpreter.scala └── keyspec.scala /.gitignore: -------------------------------------------------------------------------------- 1 | project/project 2 | project/target 3 | target 4 | tmp 5 | .history 6 | /.idea 7 | /*.iml 8 | /out 9 | /.idea_modules 10 | /.classpath 11 | /.project 12 | /.settings 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Eric Thul 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), in the Software without restriction, including without 6 | limitation the rights to use, copy, modify, merge, publish, distribute, 7 | sublicense, and/or sell copies of the Software, and to permit persons to 8 | whom the Software is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Redis Algebra 2 | 3 | A Redis library for Scala that is built on Scalaz's free monad implementation, designed in the spirit of Swierstra's [Data types a la carte](http://www.staff.science.uu.nl/~swier004/Publications/DataTypesALaCarte.pdf). The library is intended to be used in combination with other free monad based libraries to build rich algebras tailored to the user's needs. 4 | 5 | The functions that this library provides correspond to the list of [Redis commands](http://redis.io/commands). In order to run programs that have been written using this library, an interpreter needs to be implemented to handle each of the commands. There is no interpreter included by default; however, one may be made available in a separate repository. Interpreters may be interchanged freely based on the user's desired behaviour. For instance, a non-blocking interpreter that sends commands to Redis may be used in production, while an interpreter that uses an in-memory representation may be used when running tests. 6 | 7 | # Install 8 | 9 | Releases and snapshots of the Redis Algebra library are published to the [Sonatype OSS Repository Hosting Service](https://oss.sonatype.org). The necessary [SBT Resolvers](http://www.scala-sbt.org/release/docs/Detailed-Topics/Resolvers.html) may be added as follows to your SBT build file. 10 | 11 | ```scala 12 | resolvers += "Sonatype releases" at "http://oss.sonatype.org/content/repositories/releases/" 13 | 14 | resolvers += "Sonatype snapshots" at "http://oss.sonatype.org/content/repositories/snapshots/" 15 | ``` 16 | 17 | # Usage 18 | 19 | ```scala 20 | import scala.language.implicitConversions 21 | import scalaz.{CharSet, NonEmptyList}, NonEmptyList.nels 22 | import scalaz.std.list._ 23 | import scalaz.syntax.{Ops, monad, traverse}, monad._, traverse._ 24 | 25 | import redis.algebra.{F, R} 26 | import redis.algebra.all._ 27 | 28 | val e0 = 29 | set[R]("key".utf8, "value".utf8) >> 30 | get[R]("key".utf8) 31 | 32 | val e1 = 33 | set[R]("counter".utf8, 100L.utf8) >> 34 | incr[R]("counter".utf8) >> 35 | incr[R]("counter".utf8) >> 36 | incrby[R]("counter".utf8, 10L) 37 | 38 | val e2 = 39 | List("first".utf8, "second".utf8, "third".utf8).map(a => rpush[R]("messages".utf8, nels(a))).sequenceU >> 40 | lrange[R]("messages".utf8, 0, 2) 41 | 42 | implicit def StringToStringOps(a: String): StringOps = new StringOps { val self = a } 43 | 44 | implicit def LongToStringOps(a: Long): StringOps = new StringOps { val self = a.toString } 45 | 46 | sealed abstract class StringOps extends Ops[String] { final def utf8 = self.getBytes(CharSet.UTF8).toIndexedSeq } 47 | ``` 48 | -------------------------------------------------------------------------------- /build.sbt: -------------------------------------------------------------------------------- 1 | organization := "com.github.ethul" 2 | 3 | name := "redis-algebra" 4 | 5 | version := "0.1.3" 6 | 7 | scalaVersion := "2.11.2" 8 | 9 | crossScalaVersions := Seq("2.10.4", "2.11.2") 10 | 11 | libraryDependencies += "org.scalaz" %% "scalaz-core" % "7.1.0" 12 | 13 | libraryDependencies += "org.specs2" %% "specs2" % "2.4" % "test" 14 | 15 | resolvers += "Sonatype releases" at "https://oss.sonatype.org/content/repositories/releases/" 16 | 17 | scalacOptions <<= scalaVersion map { a => 18 | if (a.startsWith("2.10.")) { 19 | Seq("-deprecation", 20 | "-feature", 21 | "-language:higherKinds", 22 | "-unchecked", 23 | "-Xlint", 24 | "-Xfatal-warnings", 25 | "-Yno-adapted-args") 26 | } 27 | else { 28 | Seq("-deprecation", 29 | "-encoding", "UTF-8", 30 | "-feature", 31 | "-language:higherKinds", 32 | "-language:implicitConversions", 33 | "-language:postfixOps", 34 | "-unchecked", 35 | "-Xfatal-warnings", 36 | "-Xlint:_", 37 | "-Yno-adapted-args", 38 | "-Ywarn-adapted-args", 39 | "-Ywarn-dead-code", 40 | "-Ywarn-inaccessible", 41 | "-Ywarn-infer-any", 42 | "-Ywarn-nullary-override", 43 | "-Ywarn-nullary-unit", 44 | "-Ywarn-numeric-widen", 45 | "-Ywarn-unused", 46 | "-Ywarn-unused-import", 47 | "-Ywarn-value-discard") 48 | } 49 | } 50 | 51 | publishTo <<= version.apply { v => 52 | val nexus = "https://oss.sonatype.org/" 53 | if (v.trim.endsWith("SNAPSHOT")) 54 | Some("Snapshots" at nexus + "content/repositories/snapshots") 55 | else 56 | Some("Releases" at nexus + "service/local/staging/deploy/maven2") 57 | } 58 | 59 | credentials += Credentials(Path.userHome / ".ivy2" / ".credentials") 60 | 61 | pomIncludeRepository := Function.const(false) 62 | 63 | pomExtra := 64 | https://github.com/ethul/redis-algebra 65 | 66 | 67 | MIT 68 | http://www.opensource.org/licenses/mit-license.php 69 | repo 70 | 71 | 72 | 73 | https://github.com/ethul/redis-algebra 74 | scm:git:git@github.com:ethul/redis-algebra.git 75 | scm:git:git@github.com:ethul/redis-algebra.git 76 | 77 | 78 | 79 | ethul 80 | Eric Thul 81 | https://github.com/ethul 82 | 83 | 84 | -------------------------------------------------------------------------------- /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.5 2 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/connection.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{Free, Functor, Inject, InjectFunctions} 5 | 6 | import data.Status 7 | 8 | sealed abstract class ConnectionAlgebra[A] 9 | 10 | final case class Auth[A](password: ByteString, h: Status => A) extends ConnectionAlgebra[A] 11 | 12 | final case class Echo[A](message: ByteString, h: ByteString => A) extends ConnectionAlgebra[A] 13 | 14 | final case class Ping[A](h: Status => A) extends ConnectionAlgebra[A] 15 | 16 | final case class Quit[A](h: Status => A) extends ConnectionAlgebra[A] 17 | 18 | final case class Select[A](index: Short, h: Status => A) extends ConnectionAlgebra[A] 19 | 20 | trait ConnectionInstances { 21 | implicit val connectionAlgebraFunctor: Functor[ConnectionAlgebra] = 22 | new Functor[ConnectionAlgebra] { 23 | def map[A, B](a: ConnectionAlgebra[A])(f: A => B): ConnectionAlgebra[B] = 24 | a match { 25 | case Auth(p, h) => Auth(p, x => f(h(x))) 26 | case Echo(m, h) => Echo(m, x => f(h(x))) 27 | case Ping(h) => Ping(x => f(h(x))) 28 | case Quit(h) => Quit(x => f(h(x))) 29 | case Select(i, h) => Select(i, x => f(h(x))) 30 | } 31 | } 32 | } 33 | 34 | trait ConnectionFunctions extends InjectFunctions { 35 | def auth[F[_]: Functor](password: ByteString)(implicit I: Inject[ConnectionAlgebra, F]): Free[F, Status] = 36 | inject[F, ConnectionAlgebra, Status](Auth(password, Free.point(_))) 37 | 38 | def echo[F[_]: Functor](message: ByteString)(implicit I: Inject[ConnectionAlgebra, F]): Free[F, ByteString] = 39 | inject[F, ConnectionAlgebra, ByteString](Echo(message, Free.point(_))) 40 | 41 | def ping[F[_]: Functor](implicit I: Inject[ConnectionAlgebra, F]): Free[F, Status] = 42 | inject[F, ConnectionAlgebra, Status](Ping(Free.point(_))) 43 | 44 | def quit[F[_]: Functor](implicit I: Inject[ConnectionAlgebra, F]): Free[F, Status] = 45 | inject[F, ConnectionAlgebra, Status](Quit(Free.point(_))) 46 | 47 | def select[F[_]: Functor](index: Short)(implicit I: Inject[ConnectionAlgebra, F]): Free[F, Status] = 48 | inject[F, ConnectionAlgebra, Status](Select(index, Free.point(_))) 49 | } 50 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/data.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | package data 4 | 5 | import scalaz.NonEmptyList 6 | 7 | sealed abstract class Status 8 | case object Ok extends Status 9 | case object Error extends Status 10 | case object Wrongtype extends Status 11 | 12 | sealed abstract class Type 13 | case object String extends Type 14 | case object List extends Type 15 | case object Set extends Type 16 | case object ZSet extends Type 17 | case object Hash extends Type 18 | 19 | sealed abstract class ObjectSubcommand 20 | final case class Refcount(key: ByteString) extends ObjectSubcommand 21 | final case class Encoding(key: ByteString) extends ObjectSubcommand 22 | final case class Idletime(key: ByteString) extends ObjectSubcommand 23 | 24 | sealed abstract class ObjectResult 25 | final case class RefcountResult(value: Long) extends ObjectResult 26 | final case class EncodingResult(value: ByteString) extends ObjectResult 27 | final case class IdletimeResult(value: Long) extends ObjectResult 28 | 29 | sealed abstract class LuaResult 30 | final case class LuaNumber(value: Long) extends LuaResult 31 | final case class LuaString(value: ByteString) extends LuaResult 32 | final case class LuaTable(value: Seq[ByteString]) extends LuaResult 33 | final case class LuaStatus(value: Status) extends LuaResult 34 | final case class LuaBoolean(value: Boolean) extends LuaResult 35 | 36 | sealed abstract class Master 37 | final case class Host(name: ByteString, port: Int) extends Master 38 | case object Noone extends Master 39 | 40 | sealed abstract class SlowlogSubcommand 41 | final case class Get(limit: Option[Int] = None) extends SlowlogSubcommand 42 | case object Len extends SlowlogSubcommand 43 | case object Reset extends SlowlogSubcommand 44 | 45 | sealed abstract class SlowlogResult 46 | final case class GetResult(value: Seq[ByteString]) extends SlowlogResult 47 | final case class LenResult(value: Int) extends SlowlogResult 48 | case object ResetResult extends SlowlogResult 49 | 50 | sealed abstract class BitOperation 51 | final case class And(dest: ByteString, keys: NonEmptyList[ByteString]) extends BitOperation 52 | final case class Or(dest: ByteString, keys: NonEmptyList[ByteString]) extends BitOperation 53 | final case class Xor(dest: ByteString, keys: NonEmptyList[ByteString]) extends BitOperation 54 | final case class Not(dest: ByteString, key: ByteString) extends BitOperation 55 | 56 | sealed abstract class SetOption 57 | case object Nx extends SetOption 58 | case object Xx extends SetOption 59 | 60 | sealed abstract class Endpoint 61 | final case class Closed(value: Double) extends Endpoint 62 | final case class Open(value: Double) extends Endpoint 63 | case object -∞ extends Endpoint 64 | case object +∞ extends Endpoint 65 | 66 | sealed abstract class Aggregate 67 | case object Sum extends Aggregate 68 | case object Min extends Aggregate 69 | case object Max extends Aggregate 70 | 71 | sealed abstract class Order 72 | case object Asc extends Order 73 | case object Desc extends Order 74 | 75 | sealed abstract class Position 76 | case object Before extends Position 77 | case object After extends Position 78 | 79 | sealed abstract class By 80 | case object Nosort extends By 81 | final case class Pattern(pattern: ByteString) extends By 82 | 83 | final case class Limit(offset: Long, count: Long) 84 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/hash.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{Free, Functor, Inject, InjectFunctions, NonEmptyList} 5 | 6 | import data.Status 7 | 8 | sealed abstract class HashAlgebra[A] 9 | 10 | final case class Hdel[A](key: ByteString, fields: NonEmptyList[ByteString], h: Long => A) extends HashAlgebra[A] 11 | 12 | final case class Hexists[A](key: ByteString, field: ByteString, h: Boolean => A) extends HashAlgebra[A] 13 | 14 | final case class Hget[A](key: ByteString, field: ByteString, h: Option[ByteString] => A) extends HashAlgebra[A] 15 | 16 | final case class Hgetall[A](key: ByteString, h: Seq[(ByteString, ByteString)] => A) extends HashAlgebra[A] 17 | 18 | final case class Hincrby[A](key: ByteString, field: ByteString, increment: Long, h: Long => A) extends HashAlgebra[A] 19 | 20 | final case class Hincrbyfloat[A](key: ByteString, field: ByteString, increment: BigDecimal, h: BigDecimal => A) extends HashAlgebra[A] 21 | 22 | final case class Hkeys[A](key: ByteString, h: Seq[ByteString] => A) extends HashAlgebra[A] 23 | 24 | final case class Hlen[A](key: ByteString, h: Long => A) extends HashAlgebra[A] 25 | 26 | final case class Hmget[A](key: ByteString, fields: NonEmptyList[ByteString], h: Seq[Option[ByteString]] => A) extends HashAlgebra[A] 27 | 28 | final case class Hmset[A](key: ByteString, pairs: NonEmptyList[(ByteString, ByteString)], h: Status => A) extends HashAlgebra[A] 29 | 30 | final case class Hset[A](key: ByteString, field: ByteString, value: ByteString, h: Boolean => A) extends HashAlgebra[A] 31 | 32 | final case class Hsetnx[A](key: ByteString, field: ByteString, value: ByteString, h: Boolean => A) extends HashAlgebra[A] 33 | 34 | final case class Hvals[A](key: ByteString, h: Seq[ByteString] => A) extends HashAlgebra[A] 35 | 36 | trait HashInstances { 37 | implicit val hashAlgebraFunctor: Functor[HashAlgebra] = 38 | new Functor[HashAlgebra] { 39 | def map[A, B](a: HashAlgebra[A])(f: A => B): HashAlgebra[B] = 40 | a match { 41 | case Hdel(k, s, h) => Hdel(k, s, x => f(h(x))) 42 | case Hexists(k, s, h) => Hexists(k, s, x => f(h(x))) 43 | case Hget(k, s, h) => Hget(k, s, x => f(h(x))) 44 | case Hgetall(k, h) => Hgetall(k, x => f(h(x))) 45 | case Hincrby(k, s, i, h) => Hincrby(k, s, i, x => f(h(x))) 46 | case Hincrbyfloat(k, s, i, h) => Hincrbyfloat(k, s, i, x => f(h(x))) 47 | case Hkeys(k, h) => Hkeys(k, x => f(h(x))) 48 | case Hlen(k, h) => Hlen(k, x => f(h(x))) 49 | case Hmget(k, s, h) => Hmget(k, s, x => f(h(x))) 50 | case Hmset(k, p, h) => Hmset(k, p, x => f(h(x))) 51 | case Hset(k, s, v, h) => Hset(k, s, v, x => f(h(x))) 52 | case Hsetnx(k, s, v, h) => Hsetnx(k, s, v, x => f(h(x))) 53 | case Hvals(k, h) => Hvals(k, x => f(h(x))) 54 | } 55 | } 56 | } 57 | 58 | trait HashFunctions extends InjectFunctions { 59 | def hdel[F[_]: Functor](key: ByteString, fields: NonEmptyList[ByteString])(implicit I: Inject[HashAlgebra, F]): Free[F, Long] = 60 | inject[F, HashAlgebra, Long](Hdel(key, fields, Free.point(_))) 61 | 62 | def hexists[F[_]: Functor](key: ByteString, field: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Boolean] = 63 | inject[F, HashAlgebra, Boolean](Hexists(key, field, Free.point(_))) 64 | 65 | def hget[F[_]: Functor](key: ByteString, field: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Option[ByteString]] = 66 | inject[F, HashAlgebra, Option[ByteString]](Hget(key, field, Free.point(_))) 67 | 68 | def hgetall[F[_]: Functor](key: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Seq[(ByteString, ByteString)]] = 69 | inject[F, HashAlgebra, Seq[(ByteString, ByteString)]](Hgetall(key, Free.point(_))) 70 | 71 | def hincrby[F[_]: Functor](key: ByteString, field: ByteString, increment: Long)(implicit I: Inject[HashAlgebra, F]): Free[F, Long] = 72 | inject[F, HashAlgebra, Long](Hincrby(key, field, increment, Free.point(_))) 73 | 74 | def hincrbyfloat[F[_]: Functor](key: ByteString, field: ByteString, increment: BigDecimal)(implicit I: Inject[HashAlgebra, F]): Free[F, BigDecimal] = 75 | inject[F, HashAlgebra, BigDecimal](Hincrbyfloat(key, field, increment, Free.point(_))) 76 | 77 | def hkeys[F[_]: Functor](key: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Seq[ByteString]] = 78 | inject[F, HashAlgebra, Seq[ByteString]](Hkeys(key, Free.point(_))) 79 | 80 | def hlen[F[_]: Functor](key: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Long] = 81 | inject[F, HashAlgebra, Long](Hlen(key, Free.point(_))) 82 | 83 | def hmget[F[_]: Functor](key: ByteString, fields: NonEmptyList[ByteString])(implicit I: Inject[HashAlgebra, F]): Free[F, Seq[Option[ByteString]]] = 84 | inject[F, HashAlgebra, Seq[Option[ByteString]]](Hmget(key, fields, Free.point(_))) 85 | 86 | def hmset[F[_]: Functor](key: ByteString, pairs: NonEmptyList[(ByteString, ByteString)])(implicit I: Inject[HashAlgebra, F]): Free[F, Status] = 87 | inject[F, HashAlgebra, Status](Hmset(key, pairs, Free.point(_))) 88 | 89 | def hset[F[_]: Functor](key: ByteString, field: ByteString, value: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Boolean] = 90 | inject[F, HashAlgebra, Boolean](Hset(key, field, value, Free.point(_))) 91 | 92 | def hsetnx[F[_]: Functor](key: ByteString, field: ByteString, value: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Boolean] = 93 | inject[F, HashAlgebra, Boolean](Hsetnx(key, field, value, Free.point(_))) 94 | 95 | def hvals[F[_]: Functor](key: ByteString)(implicit I: Inject[HashAlgebra, F]): Free[F, Seq[ByteString]] = 96 | inject[F, HashAlgebra, Seq[ByteString]](Hvals(key, Free.point(_))) 97 | } 98 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/key.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{\/, Free, Functor, Inject, InjectFunctions, NonEmptyList} 5 | 6 | import data.{Asc, By, Limit, ObjectSubcommand, ObjectResult, Order, Type => DataType, Status} 7 | 8 | sealed abstract class KeyAlgebra[A] 9 | 10 | final case class Del[A](keys: NonEmptyList[ByteString], h: Long => A) extends KeyAlgebra[A] 11 | 12 | final case class Dump[A](key: ByteString, h: Option[ByteString] => A) extends KeyAlgebra[A] 13 | 14 | final case class Exists[A](key: ByteString, h: Boolean => A) extends KeyAlgebra[A] 15 | 16 | final case class Expire[A](key: ByteString, in: Seconds, h: Boolean => A) extends KeyAlgebra[A] 17 | 18 | final case class Expireat[A](key: ByteString, at: Seconds, h: Boolean => A) extends KeyAlgebra[A] 19 | 20 | final case class Keys[A](pattern: ByteString, h: Seq[ByteString] => A) extends KeyAlgebra[A] 21 | 22 | final case class Migrate[A](host: ByteString, port: Int, key: ByteString, timeout: Milliseconds, destination: Short, copy: Boolean, replace: Boolean, h: Status => A) extends KeyAlgebra[A] 23 | 24 | final case class Move[A](key: ByteString, db: Short, h: Boolean => A) extends KeyAlgebra[A] 25 | 26 | final case class Object[A](subcommand: ObjectSubcommand, h: Option[ObjectResult] => A) extends KeyAlgebra[A] 27 | 28 | final case class Persist[A](key: ByteString, h: Boolean => A) extends KeyAlgebra[A] 29 | 30 | final case class Pexpire[A](key: ByteString, in: Milliseconds, h: Boolean => A) extends KeyAlgebra[A] 31 | 32 | final case class Pexpireat[A](key: ByteString, at: Milliseconds, h: Boolean => A) extends KeyAlgebra[A] 33 | 34 | final case class Pttl[A](key: ByteString, h: Option[Milliseconds] => A) extends KeyAlgebra[A] 35 | 36 | final case class Randomkey[A](h: Option[ByteString] => A) extends KeyAlgebra[A] 37 | 38 | final case class Rename[A](key: ByteString, name: ByteString, h: Status => A) extends KeyAlgebra[A] 39 | 40 | final case class Renamenx[A](key: ByteString, name: ByteString, h: Boolean => A) extends KeyAlgebra[A] 41 | 42 | final case class Restore[A](key: ByteString, ttl: Option[Milliseconds], value: ByteString, h: Status => A) extends KeyAlgebra[A] 43 | 44 | final case class Sort[A](key: ByteString, by: Option[By], limit: Option[Limit], get: Seq[ByteString], order: Order, alpha: Boolean, store: Option[ByteString], h: Seq[ByteString] \/ Long => A) extends KeyAlgebra[A] 45 | 46 | final case class Ttl[A](key: ByteString, h: Option[Seconds] => A) extends KeyAlgebra[A] 47 | 48 | final case class Type[A](key: ByteString, h: Option[DataType] => A) extends KeyAlgebra[A] 49 | 50 | trait KeyInstances { 51 | implicit val keyAlgebraFunctor: Functor[KeyAlgebra] = 52 | new Functor[KeyAlgebra] { 53 | def map[A, B](a: KeyAlgebra[A])(f: A => B): KeyAlgebra[B] = 54 | a match { 55 | case Del(k, h) => Del(k, x => f(h(x))) 56 | case Dump(k, h) => Dump(k, x => f(h(x))) 57 | case Exists(k, h) => Exists(k, x => f(h(x))) 58 | case Expire(k, i, h) => Expire(k, i, x => f(h(x))) 59 | case Expireat(k, t, h) => Expireat(k, t, x => f(h(x))) 60 | case Keys(k, h) => Keys(k, x => f(h(x))) 61 | case Migrate(o, p, k, t, d, c, r, h) => Migrate(o, p, k, t, d, c, r, x => f(h(x))) 62 | case Move(k, d, h) => Move(k, d, x => f(h(x))) 63 | case Object(s, h) => Object(s, x => f(h(x))) 64 | case Persist(k, h) => Persist(k, x => f(h(x))) 65 | case Pexpire(k, i, h) => Pexpire(k, i, x => f(h(x))) 66 | case Pexpireat(k, t, h) => Pexpireat(k, t, x => f(h(x))) 67 | case Pttl(k, h) => Pttl(k, x => f(h(x))) 68 | case Randomkey(h) => Randomkey(x => f(h(x))) 69 | case Rename(k, n, h) => Rename(k, n, x => f(h(x))) 70 | case Renamenx(k, n, h) => Renamenx(k, n, x => f(h(x))) 71 | case Restore(k, t, v, h) => Restore(k, t, v, x => f(h(x))) 72 | case Sort(k, b, l, g, o, a, s, h) => Sort(k, b, l, g, o, a, s, x => f(h(x))) 73 | case Ttl(k, h) => Ttl(k, x => f(h(x))) 74 | case Type(k, h) => Type(k, x => f(h(x))) 75 | } 76 | } 77 | } 78 | 79 | trait KeyFunctions extends InjectFunctions { 80 | def del[F[_]: Functor](keys: NonEmptyList[ByteString])(implicit I: Inject[KeyAlgebra, F]): Free[F, Long] = 81 | inject[F, KeyAlgebra, Long](Del(keys, Free.point(_))) 82 | 83 | def dump[F[_]: Functor](key: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Option[ByteString]] = 84 | inject[F, KeyAlgebra, Option[ByteString]](Dump(key, Free.point(_))) 85 | 86 | def exists[F[_]: Functor](key: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 87 | inject[F, KeyAlgebra, Boolean](Exists(key, Free.point(_))) 88 | 89 | def expire[F[_]: Functor](key: ByteString, in: Seconds)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 90 | inject[F, KeyAlgebra, Boolean](Expire(key, in, Free.point(_))) 91 | 92 | def expireat[F[_]: Functor](key: ByteString, at: Seconds)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 93 | inject[F, KeyAlgebra, Boolean](Expireat(key, at, Free.point(_))) 94 | 95 | def keys[F[_]: Functor](pattern: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Seq[ByteString]] = 96 | inject[F, KeyAlgebra, Seq[ByteString]](Keys(pattern, Free.point(_))) 97 | 98 | def migrate[F[_]: Functor]( 99 | host: ByteString, 100 | port: Int, 101 | key: ByteString, 102 | timeout: Milliseconds, 103 | destination: Short, 104 | copy: Boolean = false, 105 | replace: Boolean = false)(implicit I: Inject[KeyAlgebra, F]): Free[F, Status] = 106 | inject[F, KeyAlgebra, Status](Migrate(host, port, key, timeout, destination, copy, replace, Free.point(_))) 107 | 108 | def move[F[_]: Functor](key: ByteString, db: Short)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 109 | inject[F, KeyAlgebra, Boolean](Move(key, db, Free.point(_))) 110 | 111 | def `object`[F[_]: Functor](subcommand: ObjectSubcommand)(implicit I: Inject[KeyAlgebra, F]): Free[F, Option[ObjectResult]] = 112 | inject[F, KeyAlgebra, Option[ObjectResult]](Object(subcommand, Free.point(_))) 113 | 114 | def persist[F[_]: Functor](key: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 115 | inject[F, KeyAlgebra, Boolean](Persist(key, Free.point(_))) 116 | 117 | def pexpire[F[_]: Functor](key: ByteString, in: Milliseconds)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 118 | inject[F, KeyAlgebra, Boolean](Pexpire(key, in, Free.point(_))) 119 | 120 | def pexpireat[F[_]: Functor](key: ByteString, at: Milliseconds)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 121 | inject[F, KeyAlgebra, Boolean](Pexpireat(key, at, Free.point(_))) 122 | 123 | def pttl[F[_]: Functor](key: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Option[Milliseconds]] = 124 | inject[F, KeyAlgebra, Option[Milliseconds]](Pttl(key, Free.point(_))) 125 | 126 | def randomkey[F[_]: Functor](implicit I: Inject[KeyAlgebra, F]): Free[F, Option[ByteString]] = 127 | inject[F, KeyAlgebra, Option[ByteString]](Randomkey(Free.point(_))) 128 | 129 | def rename[F[_]: Functor](key: ByteString, name: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Status] = 130 | inject[F, KeyAlgebra, Status](Rename(key, name, Free.point(_))) 131 | 132 | def renamenx[F[_]: Functor](key: ByteString, name: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Boolean] = 133 | inject[F, KeyAlgebra, Boolean](Renamenx(key, name, Free.point(_))) 134 | 135 | def restore[F[_]: Functor](key: ByteString, value: ByteString, ttl: Option[Milliseconds] = None)(implicit I: Inject[KeyAlgebra, F]): Free[F, Status] = 136 | inject[F, KeyAlgebra, Status](Restore(key, ttl, value, Free.point(_))) 137 | 138 | def sort[F[_]: Functor]( 139 | key: ByteString, 140 | by: Option[By] = None, 141 | limit: Option[Limit] = None, 142 | get: Seq[ByteString] = Nil, 143 | order: Order = Asc, 144 | alpha: Boolean = false, 145 | store: Option[ByteString] = None)(implicit I: Inject[KeyAlgebra, F]): Free[F, Seq[ByteString] \/ Long] = 146 | inject[F, KeyAlgebra, Seq[ByteString] \/ Long](Sort(key, by, limit, get, order, alpha, store, Free.point(_))) 147 | 148 | def ttl[F[_]: Functor](key: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Option[Seconds]] = 149 | inject[F, KeyAlgebra, Option[Seconds]](Ttl(key, Free.point(_))) 150 | 151 | def `type`[F[_]: Functor](key: ByteString)(implicit I: Inject[KeyAlgebra, F]): Free[F, Option[DataType]] = 152 | inject[F, KeyAlgebra, Option[DataType]](Type(key, Free.point(_))) 153 | } 154 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/list.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{Free, Functor, Inject, InjectFunctions, NonEmptyList} 5 | 6 | import data.{Asc, Position, Status} 7 | 8 | sealed abstract class ListAlgebra[A] 9 | 10 | final case class Blpop[A](keys: NonEmptyList[ByteString], timeout: Seconds, h: Option[(ByteString, ByteString)] => A) extends ListAlgebra[A] 11 | 12 | final case class Brpop[A](keys: NonEmptyList[ByteString], timeout: Seconds, h: Option[(ByteString, ByteString)] => A) extends ListAlgebra[A] 13 | 14 | final case class Brpoplpush[A](source: ByteString, destination: ByteString, timeout: Seconds, h: Option[ByteString] => A) extends ListAlgebra[A] 15 | 16 | final case class Lindex[A](key: ByteString, index: Long, h: Option[ByteString] => A) extends ListAlgebra[A] 17 | 18 | final case class Linsert[A](key: ByteString, position: Position, pivot: ByteString, value: ByteString, h: Option[Long] => A) extends ListAlgebra[A] 19 | 20 | final case class Llen[A](key: ByteString, h: Long => A) extends ListAlgebra[A] 21 | 22 | final case class Lpop[A](key: ByteString, h: Option[ByteString] => A) extends ListAlgebra[A] 23 | 24 | final case class Lpush[A](key: ByteString, values: NonEmptyList[ByteString], h: Long => A) extends ListAlgebra[A] 25 | 26 | final case class Lpushx[A](key: ByteString, value: ByteString, h: Long => A) extends ListAlgebra[A] 27 | 28 | final case class Lrange[A](key: ByteString, start: Long, stop: Long, h: Seq[ByteString] => A) extends ListAlgebra[A] 29 | 30 | final case class Lrem[A](key: ByteString, count: Long, value: ByteString, h: Long => A) extends ListAlgebra[A] 31 | 32 | final case class Lset[A](key: ByteString, index: Long, value: ByteString, h: Status => A) extends ListAlgebra[A] 33 | 34 | final case class Ltrim[A](key: ByteString, start: Long, stop: Long, a: Status => A) extends ListAlgebra[A] 35 | 36 | final case class Rpop[A](key: ByteString, h: Option[ByteString] => A) extends ListAlgebra[A] 37 | 38 | final case class Rpoplpush[A](source: ByteString, destination: ByteString, h: Option[ByteString] => A) extends ListAlgebra[A] 39 | 40 | final case class Rpush[A](key: ByteString, values: NonEmptyList[ByteString], h: Long => A) extends ListAlgebra[A] 41 | 42 | final case class Rpushx[A](key: ByteString, value: ByteString, h: Long => A) extends ListAlgebra[A] 43 | 44 | trait ListInstances { 45 | implicit val listAlgebraFunctor: Functor[ListAlgebra] = 46 | new Functor[ListAlgebra] { 47 | def map[A, B](a: ListAlgebra[A])(f: A => B): ListAlgebra[B] = 48 | a match { 49 | case Blpop(k, t, h) => Blpop(k, t, x => f(h(x))) 50 | case Brpop(k, t, h) => Brpop(k, t, x => f(h(x))) 51 | case Brpoplpush(s, d, t, h) => Brpoplpush(s, d, t, x => f(h(x))) 52 | case Lindex(k, i, h) => Lindex(k, i, x => f(h(x))) 53 | case Linsert(k, p, i, v, h) => Linsert(k, p, i, v, x => f(h(x))) 54 | case Llen(k, h) => Llen(k, x => f(h(x))) 55 | case Lpop(k, h) => Lpop(k, x => f(h(x))) 56 | case Lpush(k, v, h) => Lpush(k, v, x => f(h(x))) 57 | case Lpushx(k, v, h) => Lpushx(k, v, x => f(h(x))) 58 | case Lrange(k, s, t, h) => Lrange(k, s, t, x => f(h(x))) 59 | case Lrem(k, c, v, h) => Lrem(k, c, v, x => f(h(x))) 60 | case Lset(k, i, v, h) => Lset(k, i, v, x => f(h(x))) 61 | case Ltrim(k, s, t, h) => Ltrim(k, s, t, x => f(h(x))) 62 | case Rpop(k, h) => Rpop(k, x => f(h(x))) 63 | case Rpoplpush(s, d, h) => Rpoplpush(s, d, x => f(h(x))) 64 | case Rpush(k, v, h) => Rpush(k, v, x => f(h(x))) 65 | case Rpushx(k, v, h) => Rpushx(k, v, x => f(h(x))) 66 | } 67 | } 68 | } 69 | 70 | trait ListFunctions extends InjectFunctions { 71 | def blpop[F[_]: Functor](keys: NonEmptyList[ByteString], timeout: Seconds)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[(ByteString, ByteString)]] = 72 | inject[F, ListAlgebra, Option[(ByteString, ByteString)]](Blpop(keys, timeout, Free.point(_))) 73 | 74 | def brpop[F[_]: Functor](keys: NonEmptyList[ByteString], timeout: Seconds)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[(ByteString, ByteString)]] = 75 | inject[F, ListAlgebra, Option[(ByteString, ByteString)]](Brpop(keys, timeout, Free.point(_))) 76 | 77 | def brpoplpush[F[_]: Functor](source: ByteString, destination: ByteString, timeout: Seconds)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[ByteString]] = 78 | inject[F, ListAlgebra, Option[ByteString]](Brpoplpush(source, destination, timeout, Free.point(_))) 79 | 80 | def lindex[F[_]: Functor](key: ByteString, index: Long)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[ByteString]] = 81 | inject[F, ListAlgebra, Option[ByteString]](Lindex(key, index, Free.point(_))) 82 | 83 | def linsert[F[_]: Functor](key: ByteString, position: Position, pivot: ByteString, value: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[Long]] = 84 | inject[F, ListAlgebra, Option[Long]](Linsert(key, position, pivot, value, Free.point(_))) 85 | 86 | def llen[F[_]: Functor](key: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Long] = 87 | inject[F, ListAlgebra, Long](Llen(key, Free.point(_))) 88 | 89 | def lpop[F[_]: Functor](key: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[ByteString]] = 90 | inject[F, ListAlgebra, Option[ByteString]](Lpop(key, Free.point(_))) 91 | 92 | def lpush[F[_]: Functor](key: ByteString, values: NonEmptyList[ByteString])(implicit I: Inject[ListAlgebra, F]): Free[F, Long] = 93 | inject[F, ListAlgebra, Long](Lpush(key, values, Free.point(_))) 94 | 95 | def lpushx[F[_]: Functor](key: ByteString, value: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Long] = 96 | inject[F, ListAlgebra, Long](Lpushx(key, value, Free.point(_))) 97 | 98 | def lrange[F[_]: Functor](key: ByteString, start: Long, stop: Long)(implicit I: Inject[ListAlgebra, F]): Free[F, Seq[ByteString]] = 99 | inject[F, ListAlgebra, Seq[ByteString]](Lrange(key, start, stop, Free.point(_))) 100 | 101 | def lrem[F[_]: Functor](key: ByteString, count: Long, value: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Long] = 102 | inject[F, ListAlgebra, Long](Lrem(key, count, value, Free.point(_))) 103 | 104 | def lset[F[_]: Functor](key: ByteString, index: Long, value: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Status] = 105 | inject[F, ListAlgebra, Status](Lset(key, index, value, Free.point(_))) 106 | 107 | def ltrim[F[_]: Functor](key: ByteString, start: Long, stop: Long)(implicit I: Inject[ListAlgebra, F]): Free[F, Status] = 108 | inject[F, ListAlgebra, Status](Ltrim(key, start, stop, Free.point(_))) 109 | 110 | def rpop[F[_]: Functor](key: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[ByteString]] = 111 | inject[F, ListAlgebra, Option[ByteString]](Rpop(key, Free.point(_))) 112 | 113 | def rpoplpush[F[_]: Functor](source: ByteString, destination: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Option[ByteString]] = 114 | inject[F, ListAlgebra, Option[ByteString]](Rpoplpush(source, destination, Free.point(_))) 115 | 116 | def rpush[F[_]: Functor](key: ByteString, values: NonEmptyList[ByteString])(implicit I: Inject[ListAlgebra, F]): Free[F, Long] = 117 | inject[F, ListAlgebra, Long](Rpush(key, values, Free.point(_))) 118 | 119 | def rpushx[F[_]: Functor](key: ByteString, value: ByteString)(implicit I: Inject[ListAlgebra, F]): Free[F, Long] = 120 | inject[F, ListAlgebra, Long](Rpushx(key, value, Free.point(_))) 121 | } 122 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/package.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | 3 | import scala.collection.immutable.Seq 4 | 5 | import scalaz.{Coproduct, Free} 6 | 7 | package object algebra { 8 | type Seconds = Long 9 | 10 | type Milliseconds = Long 11 | 12 | type Microseconds = Int 13 | 14 | type ByteString = Seq[Byte] 15 | 16 | type C0[A] = Coproduct[ConnectionAlgebra, HashAlgebra, A] 17 | 18 | type C1[A] = Coproduct[KeyAlgebra, C0, A] 19 | 20 | type C2[A] = Coproduct[ListAlgebra, C1, A] 21 | 22 | type C3[A] = Coproduct[ScriptAlgebra, C2, A] 23 | 24 | type C4[A] = Coproduct[ServerAlgebra, C3, A] 25 | 26 | type C5[A] = Coproduct[SetAlgebra, C4, A] 27 | 28 | type C6[A] = Coproduct[StringAlgebra, C5, A] 29 | 30 | type C7[A] = Coproduct[ZSetAlgebra, C6, A] 31 | 32 | type RedisAlgebra[A] = C7[A] 33 | 34 | type RedisAlgebraFree[A] = Free[RedisAlgebra, A] 35 | 36 | type R[A] = RedisAlgebra[A] 37 | 38 | type F[A] = RedisAlgebraFree[A] 39 | 40 | object connection extends ConnectionInstances with ConnectionFunctions 41 | 42 | object hash extends HashInstances with HashFunctions 43 | 44 | object key extends KeyInstances with KeyFunctions 45 | 46 | object list extends ListInstances with ListFunctions 47 | 48 | object script extends ScriptInstances with ScriptFunctions 49 | 50 | object server extends ServerInstances with ServerFunctions 51 | 52 | object set extends SetInstances with SetFunctions 53 | 54 | object string extends StringInstances with StringFunctions 55 | 56 | object zset extends ZSetInstances with ZSetFunctions 57 | 58 | object all 59 | extends ConnectionInstances 60 | with ConnectionFunctions 61 | with HashInstances 62 | with HashFunctions 63 | with KeyInstances 64 | with KeyFunctions 65 | with ListInstances 66 | with ListFunctions 67 | with ScriptInstances 68 | with ScriptFunctions 69 | with ServerInstances 70 | with ServerFunctions 71 | with SetInstances 72 | with SetFunctions 73 | with StringInstances 74 | with StringFunctions 75 | with ZSetInstances 76 | with ZSetFunctions 77 | } 78 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/script.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{\/, Free, Functor, Inject, InjectFunctions, NonEmptyList} 5 | 6 | import data.{LuaResult, Status} 7 | 8 | sealed abstract class ScriptAlgebra[A] 9 | 10 | final case class Eval[A](script: ByteString, keys: Seq[ByteString], args: Seq[ByteString], h: LuaResult => A) extends ScriptAlgebra[A] 11 | 12 | final case class Evalsha[A](sha1: ByteString, keys: Seq[ByteString], args: Seq[ByteString], h: LuaResult => A) extends ScriptAlgebra[A] 13 | 14 | final case class Scriptexists[A](scripts: NonEmptyList[ByteString], h: NonEmptyList[Boolean] => A) extends ScriptAlgebra[A] 15 | 16 | final case class Scriptflush[A](h: Status => A) extends ScriptAlgebra[A] 17 | 18 | final case class Scriptkill[A](h: Status => A) extends ScriptAlgebra[A] 19 | 20 | final case class Scriptload[A](script: ByteString, h: Option[ByteString] => A) extends ScriptAlgebra[A] 21 | 22 | trait ScriptInstances { 23 | implicit val scriptAlgebraFunctor: Functor[ScriptAlgebra] = 24 | new Functor[ScriptAlgebra] { 25 | def map[A, B](a: ScriptAlgebra[A])(f: A => B): ScriptAlgebra[B] = 26 | a match { 27 | case Eval(s, k, a, h) => Eval(s, k, a, x => f(h(x))) 28 | case Evalsha(s, k, a, h) => Evalsha(s, k, a, x => f(h(x))) 29 | case Scriptexists(s, h) => Scriptexists(s, x => f(h(x))) 30 | case Scriptflush(h) => Scriptflush(x => f(h(x))) 31 | case Scriptkill(h) => Scriptkill(x => f(h(x))) 32 | case Scriptload(s, h) => Scriptload(s, x => f(h(x))) 33 | } 34 | } 35 | } 36 | 37 | trait ScriptFunctions extends InjectFunctions { 38 | def eval[F[_]: Functor]( 39 | script: ByteString, 40 | keys: Seq[ByteString] = Nil, 41 | args: Seq[ByteString] = Nil)(implicit I: Inject[ScriptAlgebra, F]): Free[F, LuaResult] = 42 | inject[F, ScriptAlgebra, LuaResult](Eval(script, keys, args, Free.point(_))) 43 | 44 | def evalsha[F[_]: Functor]( 45 | sha1: ByteString, 46 | keys: Seq[ByteString] = Nil, 47 | args: Seq[ByteString] = Nil)(implicit I: Inject[ScriptAlgebra, F]): Free[F, LuaResult] = 48 | inject[F, ScriptAlgebra, LuaResult](Evalsha(sha1, keys, args, Free.point(_))) 49 | 50 | def scriptexists[F[_]: Functor](scripts: NonEmptyList[ByteString])(implicit I: Inject[ScriptAlgebra, F]): Free[F, NonEmptyList[Boolean]] = 51 | inject[F, ScriptAlgebra, NonEmptyList[Boolean]](Scriptexists(scripts, Free.point(_))) 52 | 53 | def scriptflush[F[_]: Functor](implicit I: Inject[ScriptAlgebra, F]): Free[F, Status] = 54 | inject[F, ScriptAlgebra, Status](Scriptflush(Free.point(_))) 55 | 56 | def scriptkill[F[_]: Functor](implicit I: Inject[ScriptAlgebra, F]): Free[F, Status] = 57 | inject[F, ScriptAlgebra, Status](Scriptkill(Free.point(_))) 58 | 59 | def scriptload[F[_]: Functor](script: ByteString)(implicit I: Inject[ScriptAlgebra, F]): Free[F, Option[ByteString]] = 60 | inject[F, ScriptAlgebra, Option[ByteString]](Scriptload(script, Free.point(_))) 61 | } 62 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/server.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{Free, Functor, Inject, InjectFunctions} 5 | 6 | import data.{Master, SlowlogResult, SlowlogSubcommand, Status} 7 | 8 | sealed abstract class ServerAlgebra[A] 9 | 10 | final case class Bgrewriteaof[A](h: Status => A) extends ServerAlgebra[A] 11 | 12 | final case class Bgsave[A](h: Status => A) extends ServerAlgebra[A] 13 | 14 | final case class Clientgetname[A](h: Option[ByteString] => A) extends ServerAlgebra[A] 15 | 16 | final case class Clientkill[A](ip: ByteString, port: Int, h: Status => A) extends ServerAlgebra[A] 17 | 18 | final case class Clientlist[A](h: Seq[ByteString] => A) extends ServerAlgebra[A] 19 | 20 | final case class Clientsetname[A](name: ByteString, h: Status => A) extends ServerAlgebra[A] 21 | 22 | final case class Configget[A](parameter: ByteString, h: Seq[ByteString] => A) extends ServerAlgebra[A] 23 | 24 | final case class Configresetstat[A](h: Status => A) extends ServerAlgebra[A] 25 | 26 | final case class Configrewrite[A](h: Status => A) extends ServerAlgebra[A] 27 | 28 | final case class Configset[A](parameter: ByteString, value: ByteString, h: Status => A) extends ServerAlgebra[A] 29 | 30 | final case class Dbsize[A](h: Short => A) extends ServerAlgebra[A] 31 | 32 | final case class Debugobject[A](key: ByteString, h: Status => A) extends ServerAlgebra[A] 33 | 34 | final case class Debugsegfault[A](h: Status => A) extends ServerAlgebra[A] 35 | 36 | final case class Flushall[A](h: Status => A) extends ServerAlgebra[A] 37 | 38 | final case class Flushdb[A](h: Status => A) extends ServerAlgebra[A] 39 | 40 | final case class Info[A](section: Option[ByteString], h: ByteString => A) extends ServerAlgebra[A] 41 | 42 | final case class Lastsave[A](h: Seconds => A) extends ServerAlgebra[A] 43 | 44 | final case class Monitor[A](h: Stream[ByteString] => A) extends ServerAlgebra[A] 45 | 46 | final case class Save[A](h: Status => A) extends ServerAlgebra[A] 47 | 48 | final case class Shutdown[A](save: Option[Boolean], h: Status => A) extends ServerAlgebra[A] 49 | 50 | final case class Slaveof[A](master: Master, h: Status => A) extends ServerAlgebra[A] 51 | 52 | final case class Slowlog[A](subcommand: SlowlogSubcommand, h: SlowlogResult => A) extends ServerAlgebra[A] 53 | 54 | final case class Sync[A](a: A) extends ServerAlgebra[A] 55 | 56 | final case class Time[A](h: ((Seconds, Microseconds)) => A) extends ServerAlgebra[A] 57 | 58 | trait ServerInstances { 59 | implicit val serverAlgebraFunctor: Functor[ServerAlgebra] = 60 | new Functor[ServerAlgebra] { 61 | def map[A, B](a: ServerAlgebra[A])(f: A => B): ServerAlgebra[B] = 62 | a match { 63 | case Bgrewriteaof(h) => Bgrewriteaof(x => f(h(x))) 64 | case Bgsave(h) => Bgsave(x => f(h(x))) 65 | case Clientgetname(h) => Clientgetname(x => f(h(x))) 66 | case Clientkill(i, p, h) => Clientkill(i, p, x => f(h(x))) 67 | case Clientlist(h) => Clientlist(x => f(h(x))) 68 | case Clientsetname(n, h) => Clientsetname(n, x => f(h(x))) 69 | case Configget(p, h) => Configget(p, x => f(h(x))) 70 | case Configresetstat(h) => Configresetstat(x => f(h(x))) 71 | case Configrewrite(h) => Configrewrite(x => f(h(x))) 72 | case Configset(p, v, h) => Configset(p, v, x => f(h(x))) 73 | case Dbsize(h) => Dbsize(x => f(h(x))) 74 | case Debugobject(k, h) => Debugobject(k, x => f(h(x))) 75 | case Debugsegfault(h) => Debugsegfault(x => f(h(x))) 76 | case Flushall(h) => Flushall(x => f(h(x))) 77 | case Flushdb(h) => Flushdb(x => f(h(x))) 78 | case Info(s, h) => Info(s, x => f(h(x))) 79 | case Lastsave(h) => Lastsave(x => f(h(x))) 80 | case Monitor(h) => Monitor(x => f(h(x))) 81 | case Save(h) => Save(x => f(h(x))) 82 | case Shutdown(s, h) => Shutdown(s, x => f(h(x))) 83 | case Slaveof(m, h) => Slaveof(m, x => f(h(x))) 84 | case Slowlog(s, h) => Slowlog(s, x => f(h(x))) 85 | case Sync(a) => Sync(f(a)) 86 | case Time(h) => Time(x => f(h(x))) 87 | } 88 | } 89 | } 90 | 91 | trait ServerFunctions extends InjectFunctions { 92 | def bgrewriteaof[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 93 | inject[F, ServerAlgebra, Status](Bgrewriteaof(Free.point(_))) 94 | 95 | def bgsave[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 96 | inject[F, ServerAlgebra, Status](Bgsave(Free.point(_))) 97 | 98 | def clientgetname[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Option[ByteString]] = 99 | inject[F, ServerAlgebra, Option[ByteString]](Clientgetname(Free.point(_))) 100 | 101 | def clientkill[F[_]: Functor](ip: ByteString, port: Int)(implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 102 | inject[F, ServerAlgebra, Status](Clientkill(ip, port, Free.point(_))) 103 | 104 | def clientlist[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Seq[ByteString]] = 105 | inject[F, ServerAlgebra, Seq[ByteString]](Clientlist(Free.point(_))) 106 | 107 | def clientsetname[F[_]: Functor](name: ByteString)(implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 108 | inject[F, ServerAlgebra, Status](Clientsetname(name, Free.point(_))) 109 | 110 | def configget[F[_]: Functor](parameter: ByteString)(implicit I: Inject[ServerAlgebra, F]): Free[F, Seq[ByteString]] = 111 | inject[F, ServerAlgebra, Seq[ByteString]](Configget(parameter, Free.point(_))) 112 | 113 | def configresetstat[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 114 | inject[F, ServerAlgebra, Status](Configresetstat(Free.point(_))) 115 | 116 | def configrewrite[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 117 | inject[F, ServerAlgebra, Status](Configrewrite(Free.point(_))) 118 | 119 | def configset[F[_]: Functor](parameter: ByteString, value: ByteString)(implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 120 | inject[F, ServerAlgebra, Status](Configset(parameter, value, Free.point(_))) 121 | 122 | def dbsize[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Short] = 123 | inject[F, ServerAlgebra, Short](Dbsize(Free.point(_))) 124 | 125 | def debugobject[F[_]: Functor](key: ByteString)(implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 126 | inject[F, ServerAlgebra, Status](Debugobject(key, Free.point(_))) 127 | 128 | def debugsegfault[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 129 | inject[F, ServerAlgebra, Status](Debugsegfault(Free.point(_))) 130 | 131 | def flushall[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 132 | inject[F, ServerAlgebra, Status](Flushall(Free.point(_))) 133 | 134 | def flushdb[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 135 | inject[F, ServerAlgebra, Status](Flushdb(Free.point(_))) 136 | 137 | def info[F[_]: Functor](section: Option[ByteString] = None)(implicit I: Inject[ServerAlgebra, F]): Free[F, ByteString] = 138 | inject[F, ServerAlgebra, ByteString](Info(section, Free.point(_))) 139 | 140 | def lastsave[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Seconds] = 141 | inject[F, ServerAlgebra, Seconds](Lastsave(Free.point(_))) 142 | 143 | def monitor[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Stream[ByteString]] = 144 | inject[F, ServerAlgebra, Stream[ByteString]](Monitor(Free.point(_))) 145 | 146 | def save[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 147 | inject[F, ServerAlgebra, Status](Save(Free.point(_))) 148 | 149 | def shutdown[F[_]: Functor](save: Option[Boolean] = None)(implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 150 | inject[F, ServerAlgebra, Status](Shutdown(save, Free.point(_))) 151 | 152 | def slaveof[F[_]: Functor](master: Master)(implicit I: Inject[ServerAlgebra, F]): Free[F, Status] = 153 | inject[F, ServerAlgebra, Status](Slaveof(master, Free.point(_))) 154 | 155 | def slowlog[F[_]: Functor](subcommand: SlowlogSubcommand)(implicit I: Inject[ServerAlgebra, F]): Free[F, SlowlogResult] = 156 | inject[F, ServerAlgebra, SlowlogResult](Slowlog(subcommand, Free.point(_))) 157 | 158 | def sync[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, Unit] = 159 | inject[F, ServerAlgebra, Unit](Sync(Free.point(()))) 160 | 161 | def time[F[_]: Functor](implicit I: Inject[ServerAlgebra, F]): Free[F, (Seconds, Microseconds)] = 162 | inject[F, ServerAlgebra, (Seconds, Microseconds)](Time(Free.point(_))) 163 | } 164 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/set.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scala.collection.immutable.{Set => ScalaSet} 5 | 6 | import scalaz.{Free, Functor, Inject, InjectFunctions, NonEmptyList} 7 | 8 | sealed abstract class SetAlgebra[A] 9 | 10 | final case class Sadd[A](key: ByteString, members: NonEmptyList[ByteString], h: Long => A) extends SetAlgebra[A] 11 | 12 | final case class Scard[A](key: ByteString, h: Long => A) extends SetAlgebra[A] 13 | 14 | final case class Sdiff[A](keys: NonEmptyList[ByteString], h: ScalaSet[ByteString] => A) extends SetAlgebra[A] 15 | 16 | final case class Sdiffstore[A](destination: ByteString, keys: NonEmptyList[ByteString], h: Long => A) extends SetAlgebra[A] 17 | 18 | final case class Sinter[A](keys: NonEmptyList[ByteString], h: ScalaSet[ByteString] => A) extends SetAlgebra[A] 19 | 20 | final case class Sinterstore[A](destination: ByteString, keys: NonEmptyList[ByteString], h: Long => A) extends SetAlgebra[A] 21 | 22 | final case class Sismember[A](key: ByteString, member: ByteString, h: Boolean => A) extends SetAlgebra[A] 23 | 24 | final case class Smembers[A](key: ByteString, h: ScalaSet[ByteString] => A) extends SetAlgebra[A] 25 | 26 | final case class Smove[A](source: ByteString, destination: ByteString, member: ByteString, h: Boolean => A) extends SetAlgebra[A] 27 | 28 | final case class Spop[A](key: ByteString, h: Option[ByteString] => A) extends SetAlgebra[A] 29 | 30 | final case class Srandmember[A](key: ByteString, count: Option[Long], h: ScalaSet[ByteString] => A) extends SetAlgebra[A] 31 | 32 | final case class Srem[A](key: ByteString, members: NonEmptyList[ByteString], h: Long => A) extends SetAlgebra[A] 33 | 34 | final case class Sunion[A](keys: NonEmptyList[ByteString], h: ScalaSet[ByteString] => A) extends SetAlgebra[A] 35 | 36 | final case class Sunionstore[A](destination: ByteString, keys: NonEmptyList[ByteString], h: Long => A) extends SetAlgebra[A] 37 | 38 | trait SetInstances { 39 | implicit val setAlgebraFunctor: Functor[SetAlgebra] = 40 | new Functor[SetAlgebra] { 41 | def map[A, B](a: SetAlgebra[A])(f: A => B): SetAlgebra[B] = 42 | a match { 43 | case Sadd(k, m, h) => Sadd(k, m, x => f(h(x))) 44 | case Scard(k, h) => Scard(k, x => f(h(x))) 45 | case Sdiff(k, h) => Sdiff(k, x => f(h(x))) 46 | case Sdiffstore(d, k, h) => Sdiffstore(d, k, x => f(h(x))) 47 | case Sinter(k, h) => Sinter(k, x => f(h(x))) 48 | case Sinterstore(d, k, h) => Sinterstore(d, k, x => f(h(x))) 49 | case Sismember(k, m, h) => Sismember(k, m, x => f(h(x))) 50 | case Smembers(k, h) => Smembers(k, x => f(h(x))) 51 | case Smove(s, d, m, h) => Smove(s, d, m, x => f(h(x))) 52 | case Spop(k, h) => Spop(k, x => f(h(x))) 53 | case Srandmember(k, c, h) => Srandmember(k, c, x => f(h(x))) 54 | case Srem(k, m, h) => Srem(k, m, x => f(h(x))) 55 | case Sunion(k, h) => Sunion(k, x => f(h(x))) 56 | case Sunionstore(d, k, h) => Sunionstore(d, k, x => f(h(x))) 57 | } 58 | } 59 | } 60 | 61 | trait SetFunctions extends InjectFunctions { 62 | def sadd[F[_]: Functor](key: ByteString, members: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, Long] = 63 | inject[F, SetAlgebra, Long](Sadd(key, members, Free.point(_))) 64 | 65 | def scard[F[_]: Functor](key: ByteString)(implicit I: Inject[SetAlgebra, F]): Free[F, Long] = 66 | inject[F, SetAlgebra, Long](Scard(key, Free.point(_))) 67 | 68 | def sdiff[F[_]: Functor](keys: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, ScalaSet[ByteString]] = 69 | inject[F, SetAlgebra, ScalaSet[ByteString]](Sdiff(keys, Free.point(_))) 70 | 71 | def sdiffstore[F[_]: Functor](destination: ByteString, keys: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, Long] = 72 | inject[F, SetAlgebra, Long](Sdiffstore(destination, keys, Free.point(_))) 73 | 74 | def sinter[F[_]: Functor](keys: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, ScalaSet[ByteString]] = 75 | inject[F, SetAlgebra, ScalaSet[ByteString]](Sinter(keys, Free.point(_))) 76 | 77 | def sinterstore[F[_]: Functor](destination: ByteString, keys: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, Long] = 78 | inject[F, SetAlgebra, Long](Sinterstore(destination, keys, Free.point(_))) 79 | 80 | def sismember[F[_]: Functor](key: ByteString, member: ByteString)(implicit I: Inject[SetAlgebra, F]): Free[F, Boolean] = 81 | inject[F, SetAlgebra, Boolean](Sismember(key, member, Free.point(_))) 82 | 83 | def smembers[F[_]: Functor](key: ByteString)(implicit I: Inject[SetAlgebra, F]): Free[F, ScalaSet[ByteString]] = 84 | inject[F, SetAlgebra, ScalaSet[ByteString]](Smembers(key, Free.point(_))) 85 | 86 | def smove[F[_]: Functor](source: ByteString, destination: ByteString, member: ByteString)(implicit I: Inject[SetAlgebra, F]): Free[F, Boolean] = 87 | inject[F, SetAlgebra, Boolean](Smove(source, destination, member, Free.point(_))) 88 | 89 | def spop[F[_]: Functor](key: ByteString)(implicit I: Inject[SetAlgebra, F]): Free[F, Option[ByteString]] = 90 | inject[F, SetAlgebra, Option[ByteString]](Spop(key, Free.point(_))) 91 | 92 | def srandmember[F[_]: Functor](key: ByteString, count: Option[Long] = None)(implicit I: Inject[SetAlgebra, F]): Free[F, ScalaSet[ByteString]] = 93 | inject[F, SetAlgebra, ScalaSet[ByteString]](Srandmember(key, count, Free.point(_))) 94 | 95 | def srem[F[_]: Functor](key: ByteString, members: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, Long] = 96 | inject[F, SetAlgebra, Long](Srem(key, members, Free.point(_))) 97 | 98 | def sunion[F[_]: Functor](keys: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, ScalaSet[ByteString]] = 99 | inject[F, SetAlgebra, ScalaSet[ByteString]](Sunion(keys, Free.point(_))) 100 | 101 | def sunionstore[F[_]: Functor](destination: ByteString, keys: NonEmptyList[ByteString])(implicit I: Inject[SetAlgebra, F]): Free[F, Long] = 102 | inject[F, SetAlgebra, Long](Sunionstore(destination, keys, Free.point(_))) 103 | } 104 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/string.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{\/, Free, Functor, Inject, InjectFunctions, NonEmptyList} 5 | 6 | import data.{BitOperation, SetOption, Status} 7 | 8 | sealed abstract class StringAlgebra[A] 9 | 10 | final case class Append[A](key: ByteString, value: ByteString, h: Long => A) extends StringAlgebra[A] 11 | 12 | final case class Bitcount[A](key: ByteString, range: Option[(Long, Long)], h: Long => A) extends StringAlgebra[A] 13 | 14 | final case class Bitop[A](operation: BitOperation, h: Long => A) extends StringAlgebra[A] 15 | 16 | final case class Decr[A](key: ByteString, h: Long => A) extends StringAlgebra[A] 17 | 18 | final case class Decrby[A](key: ByteString, decrement: Long, h: Long => A) extends StringAlgebra[A] 19 | 20 | final case class Get[A](key: ByteString, h: Option[ByteString] => A) extends StringAlgebra[A] 21 | 22 | final case class Getbit[A](key: ByteString, offset: Long, h: Boolean => A) extends StringAlgebra[A] 23 | 24 | final case class Getrange[A](key: ByteString, start: Long, end: Long, h: ByteString => A) extends StringAlgebra[A] 25 | 26 | final case class Getset[A](key: ByteString, value: ByteString, h: Option[ByteString] => A) extends StringAlgebra[A] 27 | 28 | final case class Incr[A](key: ByteString, h: Long => A) extends StringAlgebra[A] 29 | 30 | final case class Incrby[A](key: ByteString, increment: Long, h: Long => A) extends StringAlgebra[A] 31 | 32 | final case class Incrbyfloat[A](key: ByteString, increment: BigDecimal, h: BigDecimal => A) extends StringAlgebra[A] 33 | 34 | final case class Mget[A](keys: NonEmptyList[ByteString], h: Seq[Option[ByteString]] => A) extends StringAlgebra[A] 35 | 36 | final case class Mset[A](pairs: NonEmptyList[(ByteString, ByteString)], h: Status => A) extends StringAlgebra[A] 37 | 38 | final case class Msetnx[A](pairs: NonEmptyList[(ByteString, ByteString)], h: Boolean => A) extends StringAlgebra[A] 39 | 40 | final case class Psetex[A](key: ByteString, in: Milliseconds, value: ByteString, h: Status => A) extends StringAlgebra[A] 41 | 42 | final case class Set[A](key: ByteString, value: ByteString, in: Option[Seconds \/ Milliseconds], option: Option[SetOption], h: Boolean => A) extends StringAlgebra[A] 43 | 44 | final case class Setbit[A](key: ByteString, offset: Long, value: Boolean, h: Long => A) extends StringAlgebra[A] 45 | 46 | final case class Setex[A](key: ByteString, in: Seconds, value: ByteString, h: Status => A) extends StringAlgebra[A] 47 | 48 | final case class Setnx[A](key: ByteString, value: ByteString, h: Boolean => A) extends StringAlgebra[A] 49 | 50 | final case class Setrange[A](key: ByteString, offset: Long, value: ByteString, h: Long => A) extends StringAlgebra[A] 51 | 52 | final case class Strlen[A](key: ByteString, h: Long => A) extends StringAlgebra[A] 53 | 54 | trait StringInstances { 55 | implicit val stringAlgebraFunctor: Functor[StringAlgebra] = 56 | new Functor[StringAlgebra] { 57 | def map[A, B](a: StringAlgebra[A])(f: A => B): StringAlgebra[B] = 58 | a match { 59 | case Append(k, v, h) => Append(k, v, x => f(h(x))) 60 | case Bitcount(k, r, h) => Bitcount(k, r, x => f(h(x))) 61 | case Bitop(o, h) => Bitop(o, x => f(h(x))) 62 | case Decr(k, h) => Decr(k, x => f(h(x))) 63 | case Decrby(k, d, h) => Decrby(k, d, x => f(h(x))) 64 | case Get(k, h) => Get(k, x => f(h(x))) 65 | case Getbit(k, o, h) => Getbit(k, o, x => f(h(x))) 66 | case Getrange(k, s, e, h) => Getrange(k, s, e, x => f(h(x))) 67 | case Getset(k, v, h) => Getset(k, v, x => f(h(x))) 68 | case Incr(k, h) => Incr(k, x => f(h(x))) 69 | case Incrby(k, i, h) => Incrby(k, i, x => f(h(x))) 70 | case Incrbyfloat(k, i, h) => Incrbyfloat(k, i, x => f(h(x))) 71 | case Mget(k, h) => Mget(k, x => f(h(x))) 72 | case Mset(p, h) => Mset(p, x => f(h(x))) 73 | case Msetnx(p, h) => Msetnx(p, x => f(h(x))) 74 | case Psetex(k, i, v, h) => Psetex(k, i, v, x => f(h(x))) 75 | case Set(k, v, i, o, h) => Set(k, v, i, o, x => f(h(x))) 76 | case Setbit(k, o, v, h) => Setbit(k, o, v, x => f(h(x))) 77 | case Setex(k, i, v, h) => Setex(k, i, v, x => f(h(x))) 78 | case Setnx(k, v, h) => Setnx(k, v, x => f(h(x))) 79 | case Setrange(k, o, v, h) => Setrange(k, o, v, x => f(h(x))) 80 | case Strlen(k, h) => Strlen(k, x => f(h(x))) 81 | } 82 | } 83 | } 84 | 85 | trait StringFunctions extends InjectFunctions { 86 | def append[F[_]: Functor](key: ByteString, value: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 87 | inject[F, StringAlgebra, Long](Append(key, value, Free.point(_))) 88 | 89 | def bitcount[F[_]: Functor](key: ByteString, range: Option[(Long, Long)])(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 90 | inject[F, StringAlgebra, Long](Bitcount(key, range, Free.point(_))) 91 | 92 | def bitop[F[_]: Functor](operation: BitOperation)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 93 | inject[F, StringAlgebra, Long](Bitop(operation, Free.point(_))) 94 | 95 | def decr[F[_]: Functor](key: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 96 | inject[F, StringAlgebra, Long](Decr(key, Free.point(_))) 97 | 98 | def decrby[F[_]: Functor](key: ByteString, decrement: Long)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 99 | inject[F, StringAlgebra, Long](Decrby(key, decrement, Free.point(_))) 100 | 101 | def get[F[_]: Functor](key: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Option[ByteString]] = 102 | inject[F, StringAlgebra, Option[ByteString]](Get(key, Free.point(_))) 103 | 104 | def getbit[F[_]: Functor](key: ByteString, offset: Long)(implicit I: Inject[StringAlgebra, F]): Free[F, Boolean] = 105 | inject[F, StringAlgebra, Boolean](Getbit(key, offset, Free.point(_))) 106 | 107 | def getrange[F[_]: Functor](key: ByteString, start: Long, end: Long)(implicit I: Inject[StringAlgebra, F]): Free[F, ByteString] = 108 | inject[F, StringAlgebra, ByteString](Getrange(key, start, end, Free.point(_))) 109 | 110 | def getset[F[_]: Functor](key: ByteString, value: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Option[ByteString]] = 111 | inject[F, StringAlgebra, Option[ByteString]](Getset(key, value, Free.point(_))) 112 | 113 | def incr[F[_]: Functor](key: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 114 | inject[F, StringAlgebra, Long](Incr(key, Free.point(_))) 115 | 116 | def incrby[F[_]: Functor](key: ByteString, increment: Long)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 117 | inject[F, StringAlgebra, Long](Incrby(key, increment, Free.point(_))) 118 | 119 | def incrbyfloat[F[_]: Functor](key: ByteString, increment: BigDecimal)(implicit I: Inject[StringAlgebra, F]): Free[F, BigDecimal] = 120 | inject[F, StringAlgebra, BigDecimal](Incrbyfloat(key, increment, Free.point(_))) 121 | 122 | def mget[F[_]: Functor](keys: NonEmptyList[ByteString])(implicit I: Inject[StringAlgebra, F]): Free[F, Seq[Option[ByteString]]] = 123 | inject[F, StringAlgebra, Seq[Option[ByteString]]](Mget(keys, Free.point(_))) 124 | 125 | def mset[F[_]: Functor](pairs: NonEmptyList[(ByteString, ByteString)])(implicit I: Inject[StringAlgebra, F]): Free[F, Status] = 126 | inject[F, StringAlgebra, Status](Mset(pairs, Free.point(_))) 127 | 128 | def msetnx[F[_]: Functor](pairs: NonEmptyList[(ByteString, ByteString)])(implicit I: Inject[StringAlgebra, F]): Free[F, Boolean] = 129 | inject[F, StringAlgebra, Boolean](Msetnx(pairs, Free.point(_))) 130 | 131 | def psetex[F[_]: Functor](key: ByteString, in: Milliseconds, value: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Status] = 132 | inject[F, StringAlgebra, Status](Psetex(key, in, value, Free.point(_))) 133 | 134 | def set[F[_]: Functor]( 135 | key: ByteString, 136 | value: ByteString, 137 | in: Option[Seconds \/ Milliseconds] = None, 138 | option: Option[SetOption] = None)(implicit I: Inject[StringAlgebra, F]): Free[F, Boolean] = 139 | inject[F, StringAlgebra, Boolean](Set(key, value, in, option, Free.point(_))) 140 | 141 | def setbit[F[_]: Functor](key: ByteString, offset: Long, value: Boolean)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 142 | inject[F, StringAlgebra, Long](Setbit(key, offset, value, Free.point(_))) 143 | 144 | def setex[F[_]: Functor](key: ByteString, in: Seconds, value: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Status] = 145 | inject[F, StringAlgebra, Status](Setex(key, in, value, Free.point(_))) 146 | 147 | def setnx[F[_]: Functor](key: ByteString, value: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Boolean] = 148 | inject[F, StringAlgebra, Boolean](Setnx(key, value, Free.point(_))) 149 | 150 | def setrange[F[_]: Functor](key: ByteString, offset: Long, value: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 151 | inject[F, StringAlgebra, Long](Setrange(key, offset, value, Free.point(_))) 152 | 153 | def strlen[F[_]: Functor](key: ByteString)(implicit I: Inject[StringAlgebra, F]): Free[F, Long] = 154 | inject[F, StringAlgebra, Long](Strlen(key, Free.point(_))) 155 | } 156 | -------------------------------------------------------------------------------- /src/main/scala/redis/algebra/zset.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{Free, Functor, Inject, InjectFunctions, NonEmptyList} 5 | 6 | import data.{Aggregate, Endpoint, Limit, Sum} 7 | 8 | sealed abstract class ZSetAlgebra[A] 9 | 10 | final case class Zadd[A](key: ByteString, pairs: NonEmptyList[(Double, ByteString)], h: Long => A) extends ZSetAlgebra[A] 11 | 12 | final case class Zcard[A](key: ByteString, h: Long => A) extends ZSetAlgebra[A] 13 | 14 | final case class Zcount[A](key: ByteString, min: Endpoint, max: Endpoint, h: Long => A) extends ZSetAlgebra[A] 15 | 16 | final case class Zincrby[A](key: ByteString, increment: Double, member: ByteString, h: Double => A) extends ZSetAlgebra[A] 17 | 18 | final case class Zinterstore[A](destination: ByteString, keys: NonEmptyList[ByteString], weights: Option[NonEmptyList[Double]], aggregate: Aggregate, h: Long => A) extends ZSetAlgebra[A] 19 | 20 | final case class Zrange[A](key: ByteString, start: Long, stop: Long, withScores: Boolean, h: Seq[(ByteString, Option[Double])] => A) extends ZSetAlgebra[A] 21 | 22 | final case class Zrangebyscore[A](key: ByteString, min: Endpoint, max: Endpoint, withScores: Boolean, limit: Option[Limit], h: Seq[(ByteString, Option[Double])] => A) extends ZSetAlgebra[A] 23 | 24 | final case class Zrank[A](key: ByteString, member: ByteString, h: Option[Long] => A) extends ZSetAlgebra[A] 25 | 26 | final case class Zrem[A](key: ByteString, members: NonEmptyList[ByteString], h: Long => A) extends ZSetAlgebra[A] 27 | 28 | final case class Zremrangebyrank[A](key: ByteString, start: Long, stop: Long, h: Long => A) extends ZSetAlgebra[A] 29 | 30 | final case class Zremrangebyscore[A](key: ByteString, start: Endpoint, stop: Endpoint, h: Long => A) extends ZSetAlgebra[A] 31 | 32 | final case class Zrevrange[A](key: ByteString, start: Long, stop: Long, withScores: Boolean, h: Seq[(ByteString, Option[Double])] => A) extends ZSetAlgebra[A] 33 | 34 | final case class Zrevrangebyscore[A](key: ByteString, min: Endpoint, max: Endpoint, withScores: Boolean, limit: Option[Limit], h: Seq[(ByteString, Option[Double])] => A) extends ZSetAlgebra[A] 35 | 36 | final case class Zrevrank[A](key: ByteString, member: ByteString, h: Option[Long] => A) extends ZSetAlgebra[A] 37 | 38 | final case class Zscore[A](key: ByteString, member: ByteString, h: Option[Double] => A) extends ZSetAlgebra[A] 39 | 40 | final case class Zunionstore[A](destination: ByteString, keys: NonEmptyList[ByteString], weights: Option[NonEmptyList[Double]], aggregate: Aggregate, h: Long => A) extends ZSetAlgebra[A] 41 | 42 | trait ZSetInstances { 43 | implicit val zsetAlgebraFunctor: Functor[ZSetAlgebra] = 44 | new Functor[ZSetAlgebra] { 45 | def map[A, B](a: ZSetAlgebra[A])(f: A => B): ZSetAlgebra[B] = 46 | a match { 47 | case Zadd(k, p, h) => Zadd(k, p, x => f(h(x))) 48 | case Zcard(k, h) => Zcard(k, x => f(h(x))) 49 | case Zcount(k, m, n, h) => Zcount(k, m, n, x => f(h(x))) 50 | case Zincrby(k, i, m, h) => Zincrby(k, i, m, x => f(h(x))) 51 | case Zinterstore(d, k, w, g, h) => Zinterstore(d, k, w, g, x => f(h(x))) 52 | case Zrange(k, s, t, w, h) => Zrange(k, s, t, w, x => f(h(x))) 53 | case Zrangebyscore(k, m, n, w, l, h) => Zrangebyscore(k, m, n, w, l, x => f(h(x))) 54 | case Zrank(k, m, h) => Zrank(k, m, x => f(h(x))) 55 | case Zrem(k, m, h) => Zrem(k, m, x => f(h(x))) 56 | case Zremrangebyrank(k, s, t, h) => Zremrangebyrank(k, s, t, x => f(h(x))) 57 | case Zremrangebyscore(k, s, t, h) => Zremrangebyscore(k, s, t, x => f(h(x))) 58 | case Zrevrange(k, s, t, w, h) => Zrevrange(k, s, t, w, x => f(h(x))) 59 | case Zrevrangebyscore(k, m, n, w, l, h) => Zrevrangebyscore(k, m, n, w, l, x => f(h(x))) 60 | case Zrevrank(k, m, h) => Zrevrank(k, m, x => f(h(x))) 61 | case Zscore(k, m, h) => Zscore(k, m, x => f(h(x))) 62 | case Zunionstore(d, k, w, g, h) => Zunionstore(d, k, w, g, x => f(h(x))) 63 | } 64 | } 65 | } 66 | 67 | trait ZSetFunctions extends InjectFunctions { 68 | def zadd[F[_]: Functor](key: ByteString, pairs: NonEmptyList[(Double, ByteString)])(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 69 | inject[F, ZSetAlgebra, Long](Zadd(key, pairs, Free.point(_))) 70 | 71 | def zcard[F[_]: Functor](key: ByteString)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 72 | inject[F, ZSetAlgebra, Long](Zcard(key, Free.point(_))) 73 | 74 | def zcount[F[_]: Functor](key: ByteString, min: Endpoint, max: Endpoint)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 75 | inject[F, ZSetAlgebra, Long](Zcount(key, min, max, Free.point(_))) 76 | 77 | def zincrby[F[_]: Functor](key: ByteString, increment: Double, member: ByteString)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Double] = 78 | inject[F, ZSetAlgebra, Double](Zincrby(key, increment, member, Free.point(_))) 79 | 80 | def zinterstore[F[_]: Functor]( 81 | destination: ByteString, 82 | keys: NonEmptyList[ByteString], 83 | weights: Option[NonEmptyList[Double]] = None, 84 | aggregate: Aggregate = Sum)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 85 | inject[F, ZSetAlgebra, Long](Zinterstore(destination, keys, weights, aggregate, Free.point(_))) 86 | 87 | def zrange[F[_]: Functor]( 88 | key: ByteString, 89 | start: Long, 90 | stop: Long, 91 | withScores: Boolean = false)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Seq[(ByteString, Option[Double])]] = 92 | inject[F, ZSetAlgebra, Seq[(ByteString, Option[Double])]](Zrange(key, start, stop, withScores, Free.point(_))) 93 | 94 | def zrangebyscore[F[_]: Functor]( 95 | key: ByteString, 96 | min: Endpoint, 97 | max: Endpoint, 98 | withScores: Boolean = false, 99 | limit: Option[Limit] = None)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Seq[(ByteString, Option[Double])]] = 100 | inject[F, ZSetAlgebra, Seq[(ByteString, Option[Double])]](Zrangebyscore(key, min, max, withScores, limit, Free.point(_))) 101 | 102 | def zrank[F[_]: Functor](key: ByteString, member: ByteString)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Option[Long]] = 103 | inject[F, ZSetAlgebra, Option[Long]](Zrank(key, member, Free.point(_))) 104 | 105 | def zrem[F[_]: Functor](key: ByteString, members: NonEmptyList[ByteString])(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 106 | inject[F, ZSetAlgebra, Long](Zrem(key, members, Free.point(_))) 107 | 108 | def zremrangebyrank[F[_]: Functor](key: ByteString, start: Long, stop: Long)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 109 | inject[F, ZSetAlgebra, Long](Zremrangebyrank(key, start, stop, Free.point(_))) 110 | 111 | def zremrangebyscore[F[_]: Functor](key: ByteString, start: Endpoint, stop: Endpoint)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 112 | inject[F, ZSetAlgebra, Long](Zremrangebyscore(key, start, stop, Free.point(_))) 113 | 114 | def zrevrange[F[_]: Functor]( 115 | key: ByteString, 116 | start: Long, 117 | stop: Long, 118 | withScores: Boolean = false)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Seq[(ByteString, Option[Double])]] = 119 | inject[F, ZSetAlgebra, Seq[(ByteString, Option[Double])]](Zrevrange(key, start, stop, withScores, Free.point(_))) 120 | 121 | def zrevrangebyscore[F[_]: Functor]( 122 | key: ByteString, 123 | min: Endpoint, 124 | max: Endpoint, 125 | withScores: Boolean = false, 126 | limit: Option[Limit] = None)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Seq[(ByteString, Option[Double])]] = 127 | inject[F, ZSetAlgebra, Seq[(ByteString, Option[Double])]](Zrevrangebyscore(key, min, max, withScores, limit, Free.point(_))) 128 | 129 | def zrevrank[F[_]: Functor](key: ByteString, member: ByteString)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Option[Long]] = 130 | inject[F, ZSetAlgebra, Option[Long]](Zrevrank(key, member, Free.point(_))) 131 | 132 | def zscore[F[_]: Functor](key: ByteString, member: ByteString)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Option[Double]] = 133 | inject[F, ZSetAlgebra, Option[Double]](Zscore(key, member, Free.point(_))) 134 | 135 | def zunionstore[F[_]: Functor]( 136 | destination: ByteString, 137 | keys: NonEmptyList[ByteString], 138 | weights: Option[NonEmptyList[Double]] = None, 139 | aggregate: Aggregate = Sum)(implicit I: Inject[ZSetAlgebra, F]): Free[F, Long] = 140 | inject[F, ZSetAlgebra, Long](Zunionstore(destination, keys, weights, aggregate, Free.point(_))) 141 | } 142 | -------------------------------------------------------------------------------- /src/test/scala/redis/algebra/bytestring.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{ImmutableArray => IA} 5 | 6 | trait ByteStringFunctions { 7 | def bytes(a: String) = IA.make(a.getBytes(`UTF-8`)) 8 | 9 | def string(a: ByteString) = new String(a.toArray, `UTF-8`) 10 | 11 | private val `UTF-8` = "UTF-8" 12 | } 13 | -------------------------------------------------------------------------------- /src/test/scala/redis/algebra/interpreter.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import scalaz.{-\/, \/-, Coproduct, Free, Functor, ImmutableArray => IA} 5 | 6 | import all._, Interpreter._ 7 | 8 | sealed abstract class Interpreter[F[_] : Functor] { 9 | def runAlgebra[A](algebra: F[Mem => (A, Mem)], mem: Mem): (A, Mem) 10 | } 11 | 12 | sealed trait InterpreterInstances { 13 | implicit val connectionAlgebraInterpreter: Interpreter[ConnectionAlgebra] = 14 | new Interpreter[ConnectionAlgebra] { 15 | def runAlgebra[A](algebra: ConnectionAlgebra[Mem => (A, Mem)], mem: Mem) = 16 | algebra match { 17 | case _ => ??? 18 | } 19 | } 20 | implicit val hashAlgebraInterpreter: Interpreter[HashAlgebra] = 21 | new Interpreter[HashAlgebra] { 22 | def runAlgebra[A](algebra: HashAlgebra[Mem => (A, Mem)], mem: Mem) = 23 | algebra match { 24 | case _ => ??? 25 | } 26 | } 27 | 28 | implicit val keyAgebraInterpreter: Interpreter[KeyAlgebra] = 29 | new Interpreter[KeyAlgebra] with ByteStringFunctions { 30 | def runAlgebra[A](algebra: KeyAlgebra[Mem => (A, Mem)], mem: Mem) = 31 | algebra match { 32 | case Del(k, h) => 33 | val (b, c) = k.list.foldLeft((0L, mem)) { 34 | case ((b,c), a) => 35 | if (c.contains(string(a))) (b + 1, c - string(a)) else (b, c) 36 | } 37 | h(b)(c) 38 | case Dump(k, h) => h(mem.get(string(k)).map(a => bytes(a.hashCode.toString)))(mem) 39 | case Exists(k, h) => h(mem.contains(string(k)))(mem) 40 | case _ => ??? 41 | } 42 | } 43 | 44 | implicit val listAlgebraInterpreter: Interpreter[ListAlgebra] = 45 | new Interpreter[ListAlgebra] { 46 | def runAlgebra[A](algebra: ListAlgebra[Mem => (A, Mem)], mem: Mem) = 47 | algebra match { 48 | case _ => ??? 49 | } 50 | } 51 | 52 | implicit val scriptAlgebraInterpreter: Interpreter[ScriptAlgebra] = 53 | new Interpreter[ScriptAlgebra] { 54 | def runAlgebra[A](algebra: ScriptAlgebra[Mem => (A, Mem)], mem: Mem) = 55 | algebra match { 56 | case _ => ??? 57 | } 58 | } 59 | 60 | implicit val serverAlgebraInterpreter: Interpreter[ServerAlgebra] = 61 | new Interpreter[ServerAlgebra] { 62 | def runAlgebra[A](algebra: ServerAlgebra[Mem => (A, Mem)], mem: Mem) = 63 | algebra match { 64 | case _ => ??? 65 | } 66 | } 67 | 68 | implicit val setAlgebraInterpreter: Interpreter[SetAlgebra] = 69 | new Interpreter[SetAlgebra] { 70 | def runAlgebra[A](algebra: SetAlgebra[Mem => (A, Mem)], mem: Mem) = 71 | algebra match { 72 | case _ => ??? 73 | } 74 | } 75 | 76 | implicit val stringAlgebraInterpreter: Interpreter[StringAlgebra] = 77 | new Interpreter[StringAlgebra] { 78 | def runAlgebra[A](algebra: StringAlgebra[Mem => (A, Mem)], mem: Mem) = 79 | algebra match { 80 | case _ => ??? 81 | } 82 | } 83 | 84 | implicit val zsetAlgebraInterpreter: Interpreter[ZSetAlgebra] = 85 | new Interpreter[ZSetAlgebra] { 86 | def runAlgebra[A](algebra: ZSetAlgebra[Mem => (A, Mem)], mem: Mem) = 87 | algebra match { 88 | case _ => ??? 89 | } 90 | } 91 | 92 | implicit def coproductAlgebraInterpreter[F[_]: Interpreter: Functor, G[_]: Interpreter: Functor]: 93 | Interpreter[({ type l[a] = Coproduct[F, G, a] })#l] = { 94 | type H[A] = Coproduct[F, G, A] 95 | new Interpreter[H] { 96 | def runAlgebra[A](algebra: H[Mem => (A, Mem)], mem: Mem) = 97 | algebra.run match { 98 | case -\/(fa) => implicitly[Interpreter[F]].runAlgebra(fa, mem) 99 | case \/-(fa) => implicitly[Interpreter[G]].runAlgebra(fa, mem) 100 | } 101 | } 102 | } 103 | } 104 | 105 | sealed trait InterpreterFunctions { 106 | type Mem = Map[String, String] 107 | 108 | def run[A](algebra: Free[R, A], mem: Mem): A = 109 | algebra.resume.fold({ (a: R[Free[R, A]]) => 110 | val (x, y) = implicitly[Interpreter[R]].runAlgebra(a.map(a => (mem: Mem) => (a, mem)), mem) 111 | run(x, y) 112 | }, a => a) 113 | } 114 | 115 | object Interpreter extends InterpreterInstances with InterpreterFunctions 116 | -------------------------------------------------------------------------------- /src/test/scala/redis/algebra/keyspec.scala: -------------------------------------------------------------------------------- 1 | package redis 2 | package algebra 3 | 4 | import org.specs2._ 5 | 6 | import scalaz.{ImmutableArray => IA, NonEmptyList}, NonEmptyList._ 7 | 8 | import all._ 9 | 10 | class KeyAlgebraSpec extends Specification with ByteStringFunctions { def is = s2""" 11 | This is the specification for the KeyAlgebra. 12 | 13 | A Del command issued with some existing keys should 14 | result in the number of keys deleted $e1 15 | 16 | A Dump command issued with an existing key should 17 | result in a some(serialized value) $e2 18 | 19 | A Dump command issued with a nonexisting key should 20 | result in a none $e3 21 | 22 | An Exists command issued with an existing key should 23 | result in true $e4 24 | 25 | An Exists command issued with a nonexisting key should 26 | result in false $e5 27 | """ 28 | 29 | def e1 = interpreter.run(del(nels(keya, keyb, nonexisting)), map) === 2 30 | 31 | def e2 = interpreter.run(dump(keya), map).map(string(_)) must beSome(serialize(string(keya))) 32 | 33 | def e3 = interpreter.run(dump(nonexisting), map) must beNone 34 | 35 | def e4 = interpreter.run(exists(keya), map) === true 36 | 37 | def e5 = interpreter.run(exists(nonexisting), map) === false 38 | 39 | def serialize(k: String) = map(k).hashCode.toString 40 | 41 | val keya = bytes("a") 42 | 43 | val keyb = bytes("b") 44 | 45 | val keyc = bytes("c") 46 | 47 | val nonexisting = bytes("x") 48 | 49 | val map = Map(string(keya) -> "x", string(keyb) -> "y", string(keyc) -> "z") 50 | 51 | val interpreter = Interpreter 52 | } 53 | --------------------------------------------------------------------------------