I have async Play Action, that retrieves data from the datbase, using Slick. And Slick, obviously, uses Futures to avoid blocking:
def show(id: Long) = Action.async {
db.run(entities.filter(_.id === id).result.headOption).map {
case None => templateFor("NEW_OBJECT")
case Some(x) => Ok(x)
}
def templateFor(code: String): Future[Result] = {
db.run(templates.filter(_.code === code).result.headOption).map {
case None => InternalServerError("No template")
case Some(x) => Ok(x)
}
}
The problem is that call to templateFor() returns Future, so the whole Action returns Future[Future[Result]] which is not what expected by Play. So, i would like to get rid of that nested Future. The simple way to do it is to Await for it's completion, but i would like to avoid unnecessary blocking. It would be nice if i would be able to take Future[Result] produced by templateFor() function and return it intact from my Action, thus replacing the outer Future with it.
You can use flatMap for that,
For any monandic strutcture such as Future[T], flatMap takes a function of type T => SomeOtherMonad[K], applies that function on all elements if monad and then flattens them to gives you Future[K].
def show(id: Long) = Action.async {
db.run(entities.filter(_.id === id).result.headOption).flatMap {
case None => templateFor("NEW_OBJECT")
case Some(x) => Future(Ok(x))
}
def templateFor(code: String): Future[Result] =
db.run(templates.filter(_.code === code).result.headOption).map {
case None => InternalServerError("No template")
case Some(x) => Ok(x)
}
}
Related
Some APIs offers paginated data.
I want to call the API and retrieve the data of all pages.
I was thinking an implementation of it using recursion.
I will call it to retrieve the first page data and the url of next page. If next page is empty it means there's no more data to retrieve.
I have this code, which is not really calling an API but it is useful to implement the recursive function I need. The issue I'm facing is that I can't add the tailrec annotation, I can't transform it to be tail recursive.
How can I achieve it?
Code for simulating the API which return results in pages:
final case class Response(data: List[Int], nextUrl: Option[String])
object Api {
def getNumbers(url: String): Future[Response] = {
url match {
case "1" => Future.successful(Response(List(1, 2), Option("2")))
case "2" => Future.successful(Response(List(3, 4), Option("3")))
case "3" => Future.successful(Response(List(5, 6), None))
case _ => Future.failed(new RuntimeException("Error!"))
}
}
}
Function/method to call the API, which I want to convert it to tail recursion:
def getPaginatedData(url: String): Future[Seq[Int]] = {
// #tailrec
def loop(url: String, acc: Seq[Int]): Future[Seq[Int]] = {
Api.getNumbers(url).flatMap { response =>
response.nextUrl match {
case None => Future.successful(acc ++ response.data)
case Some(link) => loop(link, acc ++ response.data)
}
}
}
loop(url, List.empty)
}
To run the example:
def main(args: Array[String]): Unit = {
SomeService.getPaginatedData("1").onComplete {
case Failure(e) => println(s"Error! $e")
case Success(value) => println(value)
}
}
Consider the scenario
trait Checker {
def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]]
}
This trait is implemented by various class's.
Lets say
class CheckerImpl1 extends Checker {
override def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]] = ???
}
class CheckerImpl2 extends Checker {
override def check()(implicit ec: ExecutionContext): Future[Either[String, Unit]] = ???
}
Now, I need to define a new function that will call check() function for each of these implementation classes in sequence(sequence does not matter) and return a new either i.e. Future[Either[String, Unit]] where String here is concatenated string of left for the check() implementation result.
So if CheckerImpl1.check() returns Left("error1") and CheckerImpl2.check() returns Left("error2") then result of the new function will return Left("error1&error2") (& just separate two strings).
OR
So if CheckerImpl1.check() returns Right(()) and CheckerImpl2.check() returns Left("error2") then result of the new function will return Left("error2").
OR
So if CheckerImpl1.check() returns Right(()) and CheckerImpl2.check() returns Right(()) then result of the new function will return Right(()).
What I have done right now is
(CheckerImpl1.check(), CheckerImpl2.check())
.mapN {
case (Right(_), Right(_)) => Right(())
case (Left(err), Right(_)) => Left(err)
case (Right(_), Left(err)) => Left(err)
case (Left(err1), Left(err2)) => Left(err1 ++ "&" ++ err2)))
}
But this is not a ideal solution, because if I add more implementation, then I would need to add more of these case statement.
Is there a better way of doing this ?
So you have a List of Future Eithers.
val lfe :List[Future[Either[String,Unit]]] = ???
To get all the Left strings together in one Future[String] you could do this...
val res :Future[String] =
Future.sequence(lfe)
.map(_.flatMap(_.fold(Some(_),_ => None)).mkString(" & "))
If I understand correctly, you eventually want to get Future[Either[String, Unit]] type. Why not just .sequence futures and .fold the results?
val checkers: List[Checker] = ???
Future.sequence(checkers.map(_.check()))
.map { results => results.foldLeft(Right(()): Either[String, Unit]) {
case (Left(acc), Left(err)) => Left(s"$acc&$err")
case (Right(_), Left(err)) => Left(err)
case (acc, Right(_)) => acc
}}
The only code change you need now is to augment checkers list.
Somewhat more elegant using cats (if you are not familiar with kind projector plugin - that's where the * comes from).
import cats.implicilts._
checkers.map(_.check()).sequence
.map { results =>
results.map(_.toValidatedNec)
.sequence[ValidatedNec[String, *], Unit]
.leftMap(_.toList.mkString("&"))
.map(_ => ())
.toEither
}
I have a toy function defined as follows:
case class Foo (a : Int, b : String)
def get(): Either[String, Future[Option[Foo]]] = {
Right(Future.successful(Some(Foo(1, "ABS"))))
}
In the Scala Play controller, I attempt to pattern match on the result of this function call:
def hello() : Action[AnyContent] = Action.async { implicit request =>
get() match {
case Right(x) => x.map{
case foo => Ok(Json.toJson(foo))
case None => NoContent
}
case Left(x) => InternalServerError(x)
}
}
The problem is the last Left case statement. If I omit it, then everything type checks. But as soon as I add that Left case statement to handle the error condition, it breaks as the code does not type check anymore. What am I doing wrong here?
You are not returning a Future from your left case, and your InternalServerError wont be automatically wrapped, so you have to do this way:
case Left(x) => Future.successful(InternalServerError(x))
I have a Future[T] and I want to map the result, on both success and failure.
Eg, something like
val future = ... // Future[T]
val mapped = future.mapAll {
case Success(a) => "OK"
case Failure(e) => "KO"
}
If I use map or flatmap, it will only map successes futures. If I use recover, it will only map failed futures. onComplete executes a callback but does not return a modified future. Transform will work, but takes 2 functions rather than a partial function, so is a bit uglier.
I know I could make a new Promise, and complete that with onComplete or onSuccess/onFailure, but I was hoping there was something I was missing that would allow me to do the above with a single PF.
Edit 2017-09-18: As of Scala 2.12, there is a transform method that takes a Try[T] => Try[S]. So you can write
val future = ... // Future[T]
val mapped = future.transform {
case Success(_) => Success("OK")
case Failure(_) => Success("KO")
}
For 2.11.x, the below still applies:
AFAIK, you can't do this directly with a single PF. And transform transforms Throwable => Throwable, so that won't help you either. The closest you can get out of the box:
val mapped: Future[String] = future.map(_ => "OK").recover{case _ => "KO"}
That said, implementing your mapAll is trivial:
implicit class RichFuture[T](f: Future[T]) {
def mapAll[U](pf: PartialFunction[Try[T], U]): Future[U] = {
val p = Promise[U]()
f.onComplete(r => p.complete(Try(pf(r))))
p.future
}
}
Since Scala 2.12 you can use transform to map both cases:
future.transform {
case Success(_) => Try("OK")
case Failure(_) => Try("KO")
}
You also have transformWith if you prefer to use a Future instead of a Try. Check the documentation for details.
In a first step, you could do something like:
import scala.util.{Try,Success,Failure}
val g = future.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map {
case Success(s) => ...
case Failure(t) => ...
}
where T is the type of the future result. Then you can use an implicit conversion to add this structure the Future trait as a new method:
implicit class MyRichFuture[T]( fut: Future[T] ) {
def mapAll[U]( f: PartialFunction[Try[T],U] )( implicit ec: ExecutionContext ): Future[U] =
fut.map( Success(_):Try[T] ).recover{
case t => Failure(t)
}.map( f )
}
which implements the syntax your are looking for:
val future = Future{ 2 / 0 }
future.mapAll {
case Success(i) => i + 0.5
case Failure(_) => 0.0
}
Both map and flatMap variants:
implicit class FutureExtensions[T](f: Future[T]) {
def mapAll[Target](m: Try[T] => Target)(implicit ec: ExecutionContext): Future[Target] = {
val promise = Promise[Target]()
f.onComplete { r => promise success m(r) }(ec)
promise.future
}
def flatMapAll[Target](m: Try[T] => Future[Target])(implicit ec: ExecutionContext): Future[Target] = {
val promise = Promise[Target]()
f.onComplete { r => m(r).onComplete { z => promise complete z }(ec) }(ec)
promise.future
}
}
I'd like to implement validation for a sequence of operations that all return Either[Error,Item]
It should be fail-fast (in my initial need), I mean, returning Either[Error,Seq[Item]].
If there is an error, it's obvious i do not want the following operations to be performed.
But in the future i may want to collect all the errors instead of returning only the first one.
I know Scalaz can do the job but for now I quite don't understand all parts of Scalaz and I'm pretty sure there's a simpler way to do it without using Scalaz, but using by-name parameters for exemple.
Is there a way to store by-name parameters in a sequence?
So that i can create a sequence of by-name values that represent my operations?
I mean, some kind of type Seq[=> Either[Error,Item]]
Then I could do something like calling takeWhile or collectFirst or something somilar, without all the operations being performed before the creation of the sequence?
I would expect the operations to be performed only when iterating on the sequence.
Thanks
You can indeed use a Seq[() => Either[Error, Item]] to defer the computation at collection creation time. So for example
val doSomething1: () => Either[Error, Item] = () => { println(1); Right(1) }
val doSomething2: () => Either[Error, Item] = () => { println(2); Right(2) }
val doSomething3: () => Either[Error, Item] = () => { println(3); Left("error") }
val doSomething4: () => Either[Error, Item] = () => { println(4); Right(3) }
val doSomething5: () => Either[Error, Item] = () => { println(5); Left("second error") }
val l = Seq(doSomething1, doSomething2, doSomething3, doSomething4, doSomething5)
(Items are Ints in the example and Errors are Strings)
Then you can process them lazily stopping at first failure using the following recursive function:
def processUntilFailure(l: Seq[() => Either[Error, Item]]): Either[Error, Seq[Item]] = {
l.headOption.map(_.apply() match {
case Left(error) => Left(error)
case Right(item) => processUntilFailure(l.tail).right.map(_ :+ item)
}).getOrElse(Right(Nil))
}
So now when I run processUntilFailure(l)
scala> processUntilFailure(l)
1
2
3
res1: Either[Error,Seq[Item]] = Left(error)
If you wanted to generate a Either[Seq[String], Seq[Int]] (processing all the operations). You could do it with a little change:
def processAll(l: Seq[() => Either[Error, Item]]): Either[Seq[Error], Seq[Item]] = {
l.headOption.map(_.apply() match {
case Left(error) => processAll(l.tail) match {
case Right(_) => Left(Seq(error))
case Left(previousErrors) => Left(previousErrors :+ error)
}
case Right(item) => processAll(l.tail).right.map(_ :+ item)
}).getOrElse(Right(Nil))
}
The only change as you can see is the Left case in the pattern match. Running this one:
scala> processAll(l)
1
2
3
4
5
res0: Either[Seq[Error],Seq[Item]] = Left(List(second error, error))
processAll can be replaced with a generic foldLeft on l
val zero: Either[Seq[Error], Seq[Item]] = Right(Seq[Item]())
l.foldLeft(zero) { (errorsOrItems: Either[Seq[Error], Seq[Item]], computation: () => Either[String, Int]) =>
computation.apply().fold(
{ (error: String) => Left(errorsOrItems.left.toOption.map(_ :+ error).getOrElse(Seq(error))) },
{ (int: Int) => errorsOrItems.right.map(_ :+ int) })
}
processUntilFailure can as well but not easily. Since aborting early from a fold is tricky. Here's a good answer about other possible approaches when you find yourself needing to do that.
You should be able to pull this off with the type Seq[Function0[Either[Error, Item]]]. Function0 is, obviously, a zero-argument function. The rest should be self-explanatory.
Scalaz provides the type IO for exactly this purpose, so you could actually use that as well. You may not want to yet, however, if you're just beginning to work with Scalaz.