-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Why is there no ByteString => T deserializer? #3
Comments
Yes good idea! |
For an example of type-class based (de)serialization, have a look at my Riak library: https://github.com/agemooij/riak-scala-client The serialization stuff is here: https://github.com/agemooij/riak-scala-client/blob/master/src/main/scala/com/scalapenos/riak/RiakSerialization.scala I guess you would need different types of serializers depending on the Redis data type but I'm no Redis expert. |
What do you think of that ? // method api
def getT[T: ByteStringDeserializer](key: String): Future[Option[T]] =
send(Get(key))
def get(key: String): Future[Option[ByteString]] =
send(Get[ByteString](key))
// case class API
case class Get[T](key: String)(implicit bsDeserializer: ByteStringDeserializer[T]) extends RedisCommandBulk[Option[T]] {
val encodedRequest: ByteString = RedisProtocolRequest.multiBulk("GET", Seq(ByteString(key)))
def decodeReply(bulk: Bulk): Option[T] = bulk.response.map(bsDeserializer.deserialize)
}
// Example
for {
_ <- redis.set("getKey", "Hello")
getBS <- redis.get("getKey")
getString <- redis.getT[String]("getKey")
} yield {
getBS mustEqual Some(ByteString("Hello"))
getString mustEqual Some("Hello")
} |
I would get rid of the original 'get' method and rename
Note the low priority implicits trick that is very common in such situations where you want any implicit the user specifies to always win over your own defaults. Putting them one level deeper in the inheritance chain makes them lower priority but putting them in the companion object makes sure that your low priority default is always in scope. Ultimate easy of use combined with ultimate customizability :) Your example would the look something like this:
I would use exactly the same design for implementing Serializers so you have a nice symmetric API. |
Bye the way, looking at your current Also have a look at the Akka docs for encoding/decoding binary data using ByteStrings: http://doc.akka.io/docs/akka/2.2.0/scala/io-codec.html |
Thanks for LowPriorityImplicits trait, I didn't know about.
I pushed a draft branch : https://github.com/etaty/rediscala/tree/bytestring-deserializer |
The problem is in this call:
This call does not specify the desired outcome type T so the compiler will look for an unambigious implementation of the type class and finds two instead of one. The solution is to call the method like this:
If you plan to only provide the two default implementations you have now, then there would be a variation of the same trick that would help make it possible to call
Also don't forget to add the |
Thanks :) |
I have a problem : rediscala/src/test/scala/redis/commands/StringsSpec.scala Lines 99 to 100 in 6e83988
The scala compiler don't know the output type. I have to give it explicitly. So in the end, we always have to do : get[String]("key")
get[ByteString]("key")
get[MyType]("key") |
There is not really a way around this. If you want to get back a T from something that has been encoded without type information, then you will have to indicate which type you want to be produced. What is wrong with that? That is exactly the API that I would expect and want to find. In my Riak client I chose to make this a two-step process, returning an untyped RiakValue, which has an as[T] method to perform the deserialization. There too the user will need to pass in the type they expect to be returned. This is a feature that comes back in pretty much all Scala data store client libraries. |
I added a ByteStringSerializer #4 def get[K: ByteStringSerializer, R: ByteStringDeserializer](key: K): Future[Option[R]] =
send(Get(key))
//...
redis.get[String,String]("getKey") // Future[Option[String]]
redis.get("getKey") // Future[Option[ByteString]]
I don't know if i can improve the [String,String] to only [String] |
Well, the first question I would ask is whether you really want people to use non-String keys. What usage scenarios do you see for that? I'm not a very experienced Redis user but I haven't seen any examples where that would make sense. I would just use String keys and focus the Serializer/Deserializer pair purely on the values. |
I kept the non String Key possible, but you have to use case class commands. |
Looks good! |
redis.get("mykey") is returning Future[Option[ByteString]] type , Then how i can deserialize and get the orginal data from the result ? |
why empty list " List() " is returning while using redis.get("myKey") ? |
I can do
redis.set("key", MyCustomType(42))
as long as I have a valid RedisValueConverter in implicit scope for my custom type.But when I do
redis.get("key")
all I get is a rawOption[ByteString]
and I have to convert it back to my custom type myself.Why is there not a
get[T: RedisValueDeserializer](key: String): Future[Option[T]]
with some basic support for common types (Strings, Ints, Longs, Booleans, Lists, Sets, Maps, etc.)? Then I can have my ownRedisValueDeserializer
in scope to deserialize my custom types.The text was updated successfully, but these errors were encountered: