Skip to content

Commit

Permalink
Merge pull request #243 from atais/api-cleanup
Browse files Browse the repository at this point in the history
Common interface for single redis client and cluster classes
  • Loading branch information
debasishg authored Aug 18, 2019
2 parents 2381a98 + 4c795a6 commit c519398
Show file tree
Hide file tree
Showing 57 changed files with 2,012 additions and 1,730 deletions.
1 change: 0 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ lazy val coreSettings = commonSettings ++ Seq(
"org.slf4j" % "slf4j-api" % "1.7.26",
"org.slf4j" % "slf4j-log4j12" % "1.7.26" % "provided",
"log4j" % "log4j" % "1.2.17" % "provided",
"junit" % "junit" % "4.12" % "test",
"org.scalatest" %% "scalatest" % "3.0.8" % "test"),

parallelExecution in Test := false,
Expand Down
46 changes: 23 additions & 23 deletions src/main/scala/com/redis/EvalOperations.scala
Original file line number Diff line number Diff line change
@@ -1,50 +1,50 @@
package com.redis

import serialization._
import com.redis.api.EvalApi
import com.redis.serialization._

trait EvalOperations { self: Redis =>
trait EvalOperations extends EvalApi {
self: Redis =>

// EVAL
// evaluates lua code on the server.
def evalMultiBulk[A](luaCode: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[A]]] =
send("EVAL", argsForEval(luaCode, keys, args))(asList[A])
override def evalMultiBulk[A](luaCode: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[A]]] =
send("EVAL", argsForEval(luaCode, keys, args))(asList[A])

def evalBulk[A](luaCode: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[A] =
override def evalBulk[A](luaCode: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[A] =
send("EVAL", argsForEval(luaCode, keys, args))(asBulk)
def evalInt(luaCode: String, keys: List[Any], args: List[Any]): Option[Int] =

override def evalInt(luaCode: String, keys: List[Any], args: List[Any]): Option[Int] =
send("EVAL", argsForEval(luaCode, keys, args))(asInt)
def evalMultiSHA[A](shahash: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[A]]] =

override def evalMultiSHA[A](shahash: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[A]]] =
send("EVALSHA", argsForEval(shahash, keys, args))(asList[A])
def evalSHA[A](shahash: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[A] =

override def evalSHA[A](shahash: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[A] =
send("EVALSHA", argsForEval(shahash, keys, args))(asAny.asInstanceOf[Option[A]])

def evalSHABulk[A](shahash: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[A] =
override def evalSHABulk[A](shahash: String, keys: List[Any], args: List[Any])(implicit format: Format, parse: Parse[A]): Option[A] =
send("EVALSHA", argsForEval(shahash, keys, args))(asBulk)
def scriptLoad(luaCode: String): Option[String] = {

override def scriptLoad(luaCode: String): Option[String] = {
send("SCRIPT", List("LOAD", luaCode))(asBulk)
}
def scriptExists(shahash: String): Option[Int] = {

override def scriptExists(shahash: String): Option[Int] = {
send("SCRIPT", List("EXISTS", shahash))(asList[String]) match {
case Some(list) => {
if (list.size>0 && list(0).isDefined){
if (list.size > 0 && list(0).isDefined) {
Some(list(0).get.toInt)
}else{
} else {
None
}
}
case None => None
}
}
def scriptFlush: Option[String] = {

override def scriptFlush: Option[String] = {
send("SCRIPT", List("FLUSH"))(asString)
}

private def argsForEval(luaCode: String, keys: List[Any], args: List[Any]): List[Any] =
luaCode :: keys.length :: keys ::: args
}
135 changes: 39 additions & 96 deletions src/main/scala/com/redis/GeoOperations.scala
Original file line number Diff line number Diff line change
@@ -1,122 +1,65 @@
package com.redis

import com.redis.api.GeoApi
import com.redis.serialization._

/**
* Created by alexis on 05/09/16.
*/
trait GeoOperations { self: Redis =>
trait GeoOperations extends GeoApi {
self: Redis =>

private def flattenProduct3(in: Iterable[Product3[Any, Any, Any]]): List[Any] =
in.iterator.flatMap(x => Iterator(x._1, x._2, x._3)).toList

/**
* Add the given <code>members</code> in the <code>key</code> geo sorted set
* @param key The geo sorted set
* @param members The members to be added. Format is (longitude, latitude, member)
* @return The number of elements added to the index. Repeated elements are not added.
*/
def geoadd(key: Any, members: Iterable[Product3[Any, Any, Any]]): Option[Int] = {
override def geoadd(key: Any, members: Iterable[Product3[Any, Any, Any]]): Option[Int] = {
send("GEOADD", key :: flattenProduct3(members))(asInt)
}

/**
* Retrieve the position of the members in the key geo sorted set. Note that if a member is not part of the set, None
* will be returned for this element.
* @param key
* @param members
* @param format
* @param parse
* @tparam A
* @return the coordinates of the input members in the same order.
*/
def geopos[A](key: Any, members: Iterable[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[List[Option[A]]]]] = {
override def geopos[A](key: Any, members: Iterable[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[List[Option[A]]]]] = {
send("GEOPOS", key :: members.toList)(receive(multiBulkNested).map(_.map(_.map(_.map(_.map(parse))))))
}

/**
* Get the geohash for each member in the key geo index.
* @param key
* @param members
* @param format
* @param parse
* @tparam A
* @return The geohash of each queried member.
*/
def geohash[A](key: Any, members: Iterable[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[A]]]= {
override def geohash[A](key: Any, members: Iterable[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[A]]] = {
send("GEOHASH", key :: members.toList)(asList[A])
}

def geodist(key: Any, m1: Any, m2: Any, unit: Option[Any]): Option[String] = {
override def geodist(key: Any, m1: Any, m2: Any, unit: Option[Any]): Option[String] = {
send("GEODIST", List(key, m1, m2) ++ unit.toList)(asBulk[String])
}

/**
* Search for members around an origin point in the key geo sorted set
* @param key The geo index we are searching in
* @param longitude The base longitude for distance computation
* @param latitude The base latitude for distance computation
* @param radius The radius of the circle we want to search in
* @param unit The unit of the radius. Can be m (meters), km (kilometers), mi (miles), ft (feet)
* @param withCoord If true, the coordinate of the found members will be returned in the result
* @param withDist If true, the distance between the origin and the found members will be returned in the result
* @param withHash If true, the hash of the found members will be returned in the result
* @param count Max number of expected results
* @param sort The sorting strategy. If empty, order is not guaranteed. Can be ASC (ascending) or DESC (descending)
* @param store The Redis store we want to write the result in
* @param storeDist The redis storedist we want to write the result in
* @return The found members as GeoRadiusMember instances
*/
def georadius(key: Any,
longitude: Any,
latitude: Any,
radius: Any,
unit: Any,
withCoord: Boolean,
withDist: Boolean,
withHash: Boolean,
count: Option[Int],
sort: Option[Any],
store: Option[Any],
storeDist: Option[Any]): Option[List[Option[GeoRadiusMember]]] = {
val radArgs = List( if (withCoord) List("WITHCOORD") else Nil
, if (withDist) List("WITHDIST") else Nil
, if (withHash) List("WITHHASH") else Nil
, sort.fold[List[Any]](Nil)(b => List(b))
, count.fold[List[Any]](Nil)(b => List("COUNT", b))
, store.fold[List[Any]](Nil)(b => List("STORE", b))
, storeDist.fold[List[Any]](Nil)(b => List("STOREDIST", b))
).flatten
override def georadius(key: Any,
longitude: Any,
latitude: Any,
radius: Any,
unit: Any,
withCoord: Boolean,
withDist: Boolean,
withHash: Boolean,
count: Option[Int],
sort: Option[Any],
store: Option[Any],
storeDist: Option[Any]): Option[List[Option[GeoRadiusMember]]] = {
val radArgs = List(if (withCoord) List("WITHCOORD") else Nil
, if (withDist) List("WITHDIST") else Nil
, if (withHash) List("WITHHASH") else Nil
, sort.fold[List[Any]](Nil)(b => List(b))
, count.fold[List[Any]](Nil)(b => List("COUNT", b))
, store.fold[List[Any]](Nil)(b => List("STORE", b))
, storeDist.fold[List[Any]](Nil)(b => List("STOREDIST", b))
).flatten
send("GEORADIUS", List(key, longitude, latitude, radius, unit) ++ radArgs)(receive(geoRadiusMemberReply))
}

/**
* Search for members around a specific memberin the key geo sorted set
* @param key The geo index we are searching in
* @param member The member we are searching around
* @param radius The radius of the circle we want to search in
* @param unit The unit of the radius. Can be m (meters), km (kilometers), mi (miles), ft (feet)
* @param withCoord If true, the coordinate of the found members will be returned in the result
* @param withDist If true, the distance between the origin and the found members will be returned in the result
* @param withHash If true, the hash of the found members will be returned in the result
* @param count Max number of expected results
* @param sort The sorting strategy. If empty, order is not guaranteed. Can be ASC (ascending) or DESC (descending)
* @param store The Redis store we want to write the result in
* @param storeDist The redis storedist we want to write the result in
* @return The found members as GeoRadiusMember instances
*/
def georadiusbymember[A](key: Any,
member: Any,
radius: Any,
unit: Any,
withCoord: Boolean,
withDist: Boolean,
withHash: Boolean,
count: Option[Int],
sort: Option[Any],
store: Option[Any],
storeDist: Option[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[GeoRadiusMember]]] = {
val radArgs = List( if (withCoord) List("WITHCOORD") else Nil
override def georadiusbymember[A](key: Any,
member: Any,
radius: Any,
unit: Any,
withCoord: Boolean,
withDist: Boolean,
withHash: Boolean,
count: Option[Int],
sort: Option[Any],
store: Option[Any],
storeDist: Option[Any])(implicit format: Format, parse: Parse[A]): Option[List[Option[GeoRadiusMember]]] = {
val radArgs = List(if (withCoord) List("WITHCOORD") else Nil
, if (withDist) List("WITHDIST") else Nil
, if (withHash) List("WITHHASH") else Nil
, sort.fold[List[Any]](Nil)(b => List(b))
Expand Down
98 changes: 29 additions & 69 deletions src/main/scala/com/redis/HashOperations.scala
Original file line number Diff line number Diff line change
@@ -1,64 +1,27 @@
package com.redis

import serialization._
import com.redis.api.HashApi
import com.redis.serialization._

trait HashOperations {
trait HashOperations extends HashApi {
self: Redis =>
/**
* Sets <code>field</code> in the hash stored at <code>key</code> to <code>value</code>.
* If <code>key</code> does not exist, a new key holding a hash is created.
* If field already exists in the hash, it is overwritten.
*
* @see [[http://redis.io/commands/hset HSET documentation]]
* @deprecated return value semantics is inconsistent with [[com.redis.HashOperations#hsetnx]] and
* [[com.redis.HashOperations#hmset]]. Use [[com.redis.HashOperations#hset1]] instead
* @return <code>True</code> if <code>field</code> is a new field in the hash and value was set,
* <code>False</code> if <code>field</code> already exists in the hash and the value was updated.
*
*/
def hset(key: Any, field: Any, value: Any)(implicit format: Format): Boolean =
send("HSET", List(key, field, value))(asBoolean)

/** Sets <code>field</code> in the hash stored at <code>key</code> to <code>value</code>.
* If <code>key</code> does not exist, a new key holding a hash is created.
* If field already exists in the hash, it is overwritten.
*
* @see [[http://redis.io/commands/hset HSET documentation]]
* @return <code>Some(0)</code> if <code>field</code> is a new field in the hash and value was set,
* <code>Some(1)</code> if <code>field</code> already exists in the hash and the value was updated.
*/
def hset1(key: Any, field: Any, value: Any)(implicit format: Format): Option[Long] =
send("HSET", List(key, field, value))(asLong)

/**
* Sets <code>field</code> in the hash stored at <code>key</code> to <code>value</code>, only if field does not yet exist.
* If key does not exist, a new key holding a hash is created.
* If field already exists, this operation has no effect.
*
* @see [[http://redis.io/commands/hsetnx HSETNX documentation]]
* @return <code>True</code> if <code>field</code> is a new field in the hash and value was set.
* </code>False</code> if <code>field</code> exists in the hash and no operation was performed.
*/
def hsetnx(key: Any, field: Any, value: Any)(implicit format: Format): Boolean =
send("HSETNX", List(key, field, value))(asBoolean)

def hget[A](key: Any, field: Any)(implicit format: Format, parse: Parse[A]): Option[A] =

override def hset(key: Any, field: Any, value: Any)(implicit format: Format): Boolean =
send("HSET", List(key, field, value))(asBoolean)

override def hset1(key: Any, field: Any, value: Any)(implicit format: Format): Option[Long] =
send("HSET", List(key, field, value))(asLong)

override def hsetnx(key: Any, field: Any, value: Any)(implicit format: Format): Boolean =
send("HSETNX", List(key, field, value))(asBoolean)

override def hget[A](key: Any, field: Any)(implicit format: Format, parse: Parse[A]): Option[A] =
send("HGET", List(key, field))(asBulk)

/**
* Sets the specified fields to their respective values in the hash stored at key.
* This command overwrites any existing fields in the hash.
* If key does not exist, a new key holding a hash is created.
*
* @param map from fields to values
* @see [[http://redis.io/commands/hmset HMSET documentation]]
* @return <code>True</code> if operation completed successfully,
* <code>False</code> otherwise.
*/
def hmset(key: Any, map: Iterable[Product2[Any, Any]])(implicit format: Format): Boolean =
send("HMSET", key :: flattenPairs(map))(asBoolean)

def hmget[K, V](key: Any, fields: K*)(implicit format: Format, parseV: Parse[V]): Option[Map[K, V]] =
override def hmset(key: Any, map: Iterable[Product2[Any, Any]])(implicit format: Format): Boolean =
send("HMSET", key :: flattenPairs(map))(asBoolean)

override def hmget[K, V](key: Any, fields: K*)(implicit format: Format, parseV: Parse[V]): Option[Map[K, V]] =
send("HMGET", key :: fields.toList) {
asList.map { values =>
fields.zip(values).flatMap {
Expand All @@ -68,39 +31,36 @@ trait HashOperations {
}
}

def hincrby(key: Any, field: Any, value: Long)(implicit format: Format): Option[Long] =
override def hincrby(key: Any, field: Any, value: Long)(implicit format: Format): Option[Long] =
send("HINCRBY", List(key, field, value))(asLong)

def hincrbyfloat(key: Any, field: Any, value: Float)(implicit format: Format): Option[Float] =
override def hincrbyfloat(key: Any, field: Any, value: Float)(implicit format: Format): Option[Float] =
send("HINCRBYFLOAT", List(key, field, value))(asBulk.map(_.toFloat))

def hexists(key: Any, field: Any)(implicit format: Format): Boolean =
override def hexists(key: Any, field: Any)(implicit format: Format): Boolean =
send("HEXISTS", List(key, field))(asBoolean)

def hdel(key: Any, field: Any, fields: Any*)(implicit format: Format): Option[Long] =
override def hdel(key: Any, field: Any, fields: Any*)(implicit format: Format): Option[Long] =
send("HDEL", List(key, field) ::: fields.toList)(asLong)

def hlen(key: Any)(implicit format: Format): Option[Long] =
override def hlen(key: Any)(implicit format: Format): Option[Long] =
send("HLEN", List(key))(asLong)

def hkeys[A](key: Any)(implicit format: Format, parse: Parse[A]): Option[List[A]] =
override def hkeys[A](key: Any)(implicit format: Format, parse: Parse[A]): Option[List[A]] =
send("HKEYS", List(key))(asList.map(_.flatten))

def hvals[A](key: Any)(implicit format: Format, parse: Parse[A]): Option[List[A]] =
override def hvals[A](key: Any)(implicit format: Format, parse: Parse[A]): Option[List[A]] =
send("HVALS", List(key))(asList.map(_.flatten))

@deprecated("Use the more idiomatic variant hgetall1, which has the returned Map behavior more consistent. See issue https://github.com/debasishg/scala-redis/issues/122", "3.2")
def hgetall[K, V](key: Any)(implicit format: Format, parseK: Parse[K], parseV: Parse[V]): Option[Map[K, V]] =
override def hgetall[K, V](key: Any)(implicit format: Format, parseK: Parse[K], parseV: Parse[V]): Option[Map[K, V]] =
send("HGETALL", List(key))(asListPairs[K, V].map(_.flatten.toMap))

def hgetall1[K, V](key: Any)(implicit format: Format, parseK: Parse[K], parseV: Parse[V]): Option[Map[K, V]] =
override def hgetall1[K, V](key: Any)(implicit format: Format, parseK: Parse[K], parseV: Parse[V]): Option[Map[K, V]] =
send("HGETALL", List(key))(asListPairs[K, V].map(_.flatten.toMap)) match {
case s@Some(m) if m.nonEmpty => s
case _ => None
}

// HSCAN
// Incrementally iterate hash fields and associated values (since 2.8)
def hscan[A](key: Any, cursor: Int, pattern: Any = "*", count: Int = 10)(implicit format: Format, parse: Parse[A]): Option[(Option[Int], Option[List[Option[A]]])] =
send("HSCAN", key :: cursor :: ((x: List[Any]) => if (pattern == "*") x else "match" :: pattern :: x) (if (count == 10) Nil else List("count", count)))(asPair)
override def hscan[A](key: Any, cursor: Int, pattern: Any = "*", count: Int = 10)(implicit format: Format, parse: Parse[A]): Option[(Option[Int], Option[List[Option[A]]])] =
send("HSCAN", key :: cursor :: ((x: List[Any]) => if (pattern == "*") x else "match" :: pattern :: x) (if (count == 10) Nil else List("count", count)))(asPair)
}
Loading

0 comments on commit c519398

Please sign in to comment.