etaty/rediscala — pull request #36 by stratiator (2014-05-25 20:58:16+00:00)
Title: Added implicit conversion ability to scripting (like get and others does)

It can be handy if you have a secondary index on a set, and you'd like to get the item by secondary index with one command with having the convenience of conversion you get from get, hget, lpop and other commands.

For example you store users in a hash indexed with id and you also have a secondary index on email:
```scala
val transaction: TransactionBuilder = redis.transaction()
val emailSet: Future[Boolean] = transaction.hset(userEmailIndexKey, user.email, user.id)
val userSet: Future[Boolean] = transaction.hset(userSetKey, user.id.toString, user)
transaction.exec()
```

And when you get the user by email address, instead of doing this way:
```scala
def getUserByEmail(email: String): Future[Option[User]] = {
val script = RedisScript(
"local id = redis.call('hget', KEYS[1], ARGV[1]); " +
"if (id) then return redis.call('hget', KEYS[2], id); else return '' end;"
)
val reply = redis.evalshaOrEval(script, Seq(userEmailIndexKey, userSetKey), Seq(email))

for {
result <- reply
} yield {
val byteString = result.toByteString
if (byteString.length > 0) {
Some(User.byteStringFormatter.deserialize(byteString))
} else {
None
}
}
}
```
you can get by just doing this:
```scala
def getUserByEmail(email: String): Future[Option[User]] = {
val script = RedisScript(
"local id = redis.call('hget', KEYS[1], ARGV[1]); " +
"if (id) then return redis.call('hget', KEYS[2], id); else return '' end;"
)
redis.evalshaOrEvalForTypeOf[User](script, Seq(userEmailIndexKey, userSetKey), Seq(email))
}
```

So I added commands for eval, evalsha and evalshaOrEval with type conversion, also refactored out the request encoding to get rid of some code duplication.