How use guave cache loader in F polymorphic code - scala

I have a service, that returns joke from official example:
final case class JokeError(e: Throwable) extends RuntimeException
def impl[F[_] : Sync](C: Client[F]): Jokes[F] = new Jokes[F] {
val dsl = new Http4sClientDsl[F] {}
import dsl._
def get: F[Jokes.Joke] = {
C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError { case t => JokeError(t) }
}
}
But I want cache first requested joke (just by constant key, this doesn't matter) with guava cache:
object Jokes {
def apply[F[_]](implicit ev: Jokes[F]): Jokes[F] = ev
final case class Joke(joke: String) extends AnyRef
object Joke {
implicit val jokeDecoder: Decoder[Joke] = deriveDecoder[Joke]
implicit def jokeEntityDecoder[F[_]: Sync]: EntityDecoder[F, Joke] =
jsonOf
implicit val jokeEncoder: Encoder[Joke] = deriveEncoder[Joke]
implicit def jokeEntityEncoder[F[_]: Applicative]: EntityEncoder[F, Joke] =
jsonEncoderOf
}
final case class JokeError(e: Throwable) extends RuntimeException
def impl[F[_]: Sync](C: Client[F]): Jokes[F] = new Jokes[F]{
val cacheLoader : CacheLoader[String, Joke] = new CacheLoader[String, Joke] {
override def load(key: String): Joke = {
import dsl._
val joke: F[Joke] = C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError{ case t => JokeError(t)}
//? F[Joke] => Joke
null
}
}
val cache = CacheBuilder.newBuilder().build(cacheLoader)
val dsl = new Http4sClientDsl[F]{}
def get: F[Jokes.Joke] = {
//it's ok?
cache.get("constant").pure[F]
}
}
}
As you can see, cacheLoader requires "materialized" value F[Joke] => Joke. And cache return pure value without F
How can I use this cache in F polymorpic code?

You're basically asking how to run code polymorphic in F, to do so you need an Effect constraint to your F.
Also instead of using pure, you would need to use delay, since getting a value from the cache is a side effect.
val cacheLoader : CacheLoader[String, Joke] = new CacheLoader[String, Joke] {
override def load(key: String): Joke = {
import dsl._
val joke: F[Joke] = C.expect[Joke](GET(uri"https://icanhazdadjoke.com/"))
.adaptError{ case t => JokeError(t)}
// This is a side effect, but can't avoid it due to the way the API is designed
joke.toIO.unsafeRunSync()
}
}
val cache = CacheBuilder.newBuilder().build(cacheLoader)
val dsl = new Http4sClientDsl[F]{}
def get: F[Jokes.Joke] = {
// This is okay :)
Sync[F].delay(cache.get("constant"))
}
As an aside, if you want to use something that interoperates really well with http4s, I strongly recommend mules. Check it out here:
https://github.com/ChristopherDavenport/mules

Related

How to propagate context via Kleisli?

Just trying to propagate my tracing context inside Kleisli as it was done originally in the next tutorial.
object TraceLogger {
def log(msg: String): Kleisli[IO, UUID, Unit] = Kleisli { traceId => IO(println(s"[$traceId] $msg")) }
}
trait ServiceStub {
def request(arg: String): Kleisli[IO, UUID, _]
}
trait ClientStub {
def get(arg: String): Kleisli[IO, UUID, _]
}
case class FirstServiceExample(clientStub: ClientStub) extends ServiceStub {
override def request(arg: String): Kleisli[IO, UUID, _] = Kleisli { (context: UUID) =>
val requestComputation = clientStub.get("calling second service!")
TraceLogger.log(arg)
requestComputation(context)
}
}
case class FirstClientExample(service: FirstServiceExample) {
def request(): IO[_] = {
val traceId = UUID.randomUUID()
service.request("root!").run(traceId)
}
}
And now I need to run execution:
val exampleClientStub = new ClientStub() {
override def get(arg: String): Kleisli[IO, UUID, _] = Kleisli.ask
}
val exampleClientService = FirstServiceExample(exampleClientStub)
FirstClientExample(exampleClientService).request().unsafeRunSync()
But, unfortunately, I don't see any logs here. Would you kindly help me to find an issue?
TraceLogger.log(arg) This returns an IO which is just a description of computation; it is doing nothing.
And since you just leave that value alone it is equivalent to just having a 1 in the middle of your code, it is simply discarded.
You need to chain your IOs together to create new IOs that represent "do this and then do that", that is basically what the flatMap method does.
Kleisli { (context: UUID) =>
val requestComputation = clientStub.get("calling second service!")
TraceLogger.log(arg)(context) >> // >> is equivalent to flatMap(_ => )
requestComputation(context)
}
(There is probably a better way to write this, I am not used to Kliesli)
Fabio's series on "Programas as Values" may be very useful: https://systemfw.org/archive.html

Is it possible to write a upickle Serializer for akka

I would like to implement an akka Serializer using upickle but I'm not sure its possible. To do so I would need to implement a Serializer something like the following:
import akka.serialization.Serializer
import upickle.default._
class UpickleSerializer extends Serializer {
def includeManifest: Boolean = true
def identifier = 1234567
def toBinary(obj: AnyRef): Array[Byte] = {
writeBinary(obj) // ???
}
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
readBinary(bytes) // ???
}
}
The problem is I cannot call writeBinary/readBinary without having the relevant Writer/Reader. Is there a way I can look these up based on the object class?
Take a look at following files, you should get some ideas!
CborAkkaSerializer.scala
LocationAkkaSerializer.scala
Note: These serializers are using cbor
I found a way to do it using reflection. I base the solution on the assumption that any object that needs to be serialized should have defined a ReadWriter in its companion object:
class UpickleSerializer extends Serializer {
private var map = Map[Class[_], ReadWriter[AnyRef]]()
def includeManifest: Boolean = true
def identifier = 1234567
def toBinary(obj: AnyRef): Array[Byte] = {
implicit val rw = getReadWriter(obj.getClass)
writeBinary(obj)
}
def fromBinary(bytes: Array[Byte], clazz: Option[Class[_]]): AnyRef = {
implicit val rw = lookup(clazz.get)
readBinary[AnyRef](bytes)
}
private def getReadWriter(clazz: Class[_]) = map.get(clazz) match {
case Some(rw) => rw
case None =>
val rw = lookup(clazz)
map += clazz -> rw
rw
}
private def lookup(clazz: Class[_]) = {
import scala.reflect.runtime._
val rootMirror = universe.runtimeMirror(clazz.getClassLoader)
val classSymbol = rootMirror.classSymbol(clazz)
val moduleSymbol = classSymbol.companion.asModule
val moduleMirror = rootMirror.reflectModule(moduleSymbol)
val instanceMirror = rootMirror.reflect(moduleMirror.instance)
val members = instanceMirror.symbol.typeSignature.members
members.find(_.typeSignature <:< typeOf[ReadWriter[_]]) match {
case Some(rw) =>
instanceMirror.reflectField(rw.asTerm).get.asInstanceOf[ReadWriter[AnyRef]]
case None =>
throw new RuntimeException("Not found")
}
}
}

Akka Http API singleton user context

I am writing a REST API using Scala and Akka Http.
For request handling, I implement Routes in the form of RequestContext => Future[RouteResult]
In each route, I have to pass the context of the user from function to function, which becomes a bit cumbersome. For example, in the code below, I always have to pass userContext into every function that interacts with the DB.
val route: Route = {
requestContext => {
val userContext = extractUser(requestContext)
val computeResult = compute(userContext)
requestContext.complete(computeResult)
}
}
However, if I set the context to a singleton, then it runs the risk of being overridden when the next calls comes in, since the API is multi-tenant.
Is there a better way to handle this?
Give an opportunity to Reader Monad. That will allow you a better abstraction over your UserContext.
This could be an aprox:
import scala.concurrent.Future
import scala.util.{Failure, Success}
import scalaz.{Reader, ReaderT}
trait UserContext {
val user: String
val passwd: String
}
trait YourDBFunctionsII[T] {
def compute(): Reader[UserContext, T]
def computeII(): Reader[UserContext, T]
}
object YourDBFunctionsII extends YourDBFunctionsII[String] {
override def compute(): Reader[UserContext, String] = Reader {
in: UserContext =>
???
}
override def computeII(): Reader[UserContext, String] = Reader {
in: UserContext =>
???
}
}
class YourRoutesII {
import YourDBFunctionsII._
val route: Route = { requestContext =>
{
val userContext: UserContext = ??? // Extract from RequestContext
val routines = for {
resul1 <- compute()
resul2 <- computeII()
} yield resul2
// Execute monad composition
val computeResult = routines.run(userContext)
requestContext.complete(computeResult)
}
}
}
If you need to deal with an asynchronous database driver you can use ScalaZ ReaderT type:
trait YourDBFunctionsIII[T] {
def compute(): ReaderT[Future, UserContext, T]
def computeII(): ReaderT[Future, UserContext, T]
}
// In case you want to deal with Futures
object YourDBFunctionsIII extends YourDBFunctionsIII[String] {
override def compute(): ReaderT[Future, UserContext, String] = ReaderT {
ctx =>
Future {
// Do something
ctx.passwd
}.recover {
case e: Throwable =>
"Error"
}
}
override def computeII(): ReaderT[Future, UserContext, String] = ReaderT {
ctx =>
Future {
// Do other thing
ctx.passwd
}
}
}
class YourRoutesIII {
import YourDBFunctionsIII._
val route: Route = { requestContext =>
{
val userContext: UserContext = ??? // Extract from RequestContext
val routines = for {
resul1 <- compute()
resul2 <- computeII()
} yield resul2
// Execute monad composition
val computeResult = routines.run(userContext)
requestContext.complete(computeResult)
}
}
}
In both cases you only need to run the monad composition with the UserContext instance.

Is there something like Map.keySet for a partial function in scala?

More specifically, I have:
case class Key (key: String)
abstract class abstr {
type MethodMap = PartialFunction[Key, String => Unit]
def myMap: MethodMap // abstract
def useIt (key: Key, value: String) = {
val meth = myMap(key)
meth(value)
}
def report = {
for (key <- myMap.keySet) // how to do this
println("I support "+key)
}
}
I use it like this:
class concrete extends abstr {
var one: Boolean
def method1(v: String): Unit = ???
def method2(v: String): Unit = ???
def map1: MethodMap = {
case Key("AAA") => method1
}
def map2: MethodMap = {
case Key("AAA") => method2
}
override def myMap: MethodMap = if (one) map1 else map2
}
Of course, this is somewhat simplified, but the report function is necessary.
Some history: I first had it implemented using Map but then I changed it to PartialFunction in order to support the following override def myMap: MethodMap = if (one) map1 else map2.
Any suggestion to refactor my code to support everything is also appreciated.
No. PartialFunction can be defined (and often is) on infinite sets. E.g. what do you expect report to return in these situations:
class concrete2 extends abstr {
def myMap = { case Key(_) => ??? }
}
or
class concrete2 extends abstr {
def myMap = { case Key(key) if key.length > 3 => ??? }
}
? If you have a finite list of values you are interested in, you can do
abstract class abstr {
type MethodMap = PartialFunction[Key, String => Unit]
def myMap: MethodMap // abstract
val keys: Seq[Key] = ...
def report = {
for (key <- keys if myMap.isDefined(key))
println("I support "+key)
}
}
Some history: I first had it implemented using Map but then I changed it to PartialFunction in order to support the last line in second part.
Why? This would work just as well with Map.
In your solution, is there any way to define the domain of the partial function to be the finite set keys
def f: MethodMap = { case key if keys.contains(key) => ... }
Of course, the domain isn't part of the type.

scala: how to implement this matcher in specs2

I have the following method:
def save(entity: A): Either[List[Error],A] + {....
which I want to test using specs2
I want to test for the existence of a specific error when a required field is not specified, like this:
val noNickname = User(
nickname = "",
name = "new name",
)
noNickname.save must beLeft.like {
case errors => {
atLeastOnceWhen(errors) {
case error => {
error.errorCode must equalTo(Error.REQUIRED)
error.field must equalTo("nickname")
}
}
}
}
It works fine, but I'd like to define my own matcher to make it less verbose, like this:
noNickname.save must haveError.like {
case error => {
error.errorCode must equalTo(Error.REQUIRED)
error.field must equalTo("nickname")
}
}
}
I had a look at the documentation (http://etorreborre.github.com/specs2/guide/org.specs2.guide.Matchers.html#Matchers) but I can't figure out how to define a custom matcher like haveError.like
Here your code with a few changes to make it compile:
case class Error(errorCode: String, field: String)
def save[A](entity: A): Either[List[Error],A] = Left(List(Error("REQUIRED", "nickname")))
case class User(nickname: String, name: String)
val noNickname = User(nickname = "", name = "new name")
"save noNickName" >> {
save(noNickname) must haveError.like {
case error => {
error.errorCode must equalTo("REQUIRED")
error.field must equalTo("nickname")
}
}
}
def haveError[T] = new ErrorMatcher[T]
class ErrorMatcher[T] extends Matcher[Either[List[T], _]] {
def apply[S <: Either[List[T], _]](value: Expectable[S]) =
result(value.value.left.toOption.isDefined,
value.description + " is Left",
value.description + " is not Left",
value)
def like[U](f: PartialFunction[T, MatchResult[U]]) =
this and partialMatcher(f)
private def partialMatcher[U](f: PartialFunction[T, MatchResult[U]]) =
new Matcher[Either[List[T], _]] {
def apply[S <: Either[List[T], _]](value: Expectable[S]) = {
// get should always work here because it comes after the "and"
val errors = value.value.left.toOption.get
val res = atLeastOnceWhen[T, U](errors)(f)
result(res.isSuccess,
value.description+" is Left[T] and "+res.message,
value.description+" is Left[T] but "+res.message,
value)
}
}
}
Notice that the matcher is defined on Either[List[T], _] everywhere.
I'm also wondering about the failure messages that are returned in case you don't find the expected error message, they might not be very explicit when the partial function fails.
So you may want to aim for using a contain matcher. Like this:
"save noNickName" >> {
save(noNickname) must haveError.containing(Error("REQUIRED", "nickname"))
}
// I'm reusing the beLeft matcher here
def haveError[T]: Matcher[Either[List[T], _]] = beLeft
// and using an implicit conversion to extend it
implicit def toErrorListMatcher[T](m: Matcher[Either[List[T], _]]): ErrorListMatcher[T] =
new ErrorListMatcher[T](m)
class ErrorListMatcher[T](m: Matcher[Either[List[T], _]]) {
def containing(t: T) =
// the 'contain' matcher is adapted to take in an
// Either[List[T], _] and work on its left part
m and contain(t) ^^ ((e: Either[List[T], _]) => e.left.toOption.get)
}
[Update]
The first solution (using atLeastOnceWhen and a partial function) can be combined with the second one (using an implicit) and the beLike matcher, to get maximum reusability of existing specs2 code:
def haveError[T]: Matcher[Either[List[T], _] = beLeft
implicit def toErrorListMatcher[T](m: Matcher[Either[List[T], _]]): ErrorListMatcher[T] =
new ErrorListMatcher[T](m)
class ErrorListMatcher[T](m: Matcher[Either[List[T], _]]) {
// beLike checks one element
// beLike.atLeastOnce transforms that matcher on a
// matcher on a sequence of elements
def like[S](f: PartialFunction[T, MatchResult[S]]) = {
m and beLike(f).atLeastOnce ^^ ((e: Either[List[T], _]) => e.left.toOption.get)
}