Scala Chain Returnable Futures Type

I am trying to link futures in Scala, but this gives me the wrong return type.

I have the following methods:

def getOneRecordByModel(x:DirectFlight): Future[Option[FlightByDetailModel]] = { select.allowFiltering().where(_.from eqs x.from).and(_.to eqs x.to).and(_.departure eqs x.departure).and(_.arrival eqs x.arrival).and(_.carrier eqs x.airline).and(_.code eqs x.flightCode).one() } def getRecordByUUID(x:FlightByDetailModel): Future[Option[FlightByUUIDModel]] = { select.allowFiltering().where(_.uuid eqs x.uuid).one() } def getUUIDRecordByModel(x:DirectFlight): Future[Option[FlightByUUIDModel]] = { getOneRecordByModel(x) andThen { case Success(Some(flight)) => getRecordByUUID(flight) case Success(x) => Success(x) case Failure(x) => Failure(x) } } 

But now I get an error that the return type is getUUIDRecordByModel Future[Option[FlightByDetailModel]]

How to tie them together?

+7
scala future
source share
4 answers

Instead, I would use flatMap .

 def getUUIDRecordByModel(x:DirectFlight): Future[Option[FlightByUUIDModel]] = { getOneRecordByModel(x) flatMap { case Some(flight) => getRecordByUUID(flight) case None => Future.successful(None) } } 

andThen applies the side effect function and returns the original Future , not the internal one.

+8
source share

This solution and 2 above it are, in fact, the same. They offer a simple flatMaps composition response. This is useful for one-time solutions.

 for { oUuid <- getOneRecordByModel(x) oFlight <- oUuid.map(getRecordByUUID).getOrElse(Future.successful(None)) } yield oFlight 

I suspect that I gave the method a signature, you are going to use this strategy a lot. If so, @Eugene Zhulenev answer above (which is a more functional solution). The thought of Monad Transformers may look a little intimidating at first glance, a piece of code here:

 val flightByUUID = for { flightByDetailModel <- optionT(getOneRecordByModel(x)) flightByUUIDModel <- optionT(getRecordByUUID(flightByDetailModel)) } yield flightByUUIDModel flightByUUID.run // this line grabs you a Future[Option[T]] 

Very simple and scalable when you start adding complexity. Hope this helps you.

+5
source share

You can do it beautifully with monad transformers with plasaz, optional. You can use a good set of articles, and more specific you need this one: http://eed3si9n.com/learning-scalaz/Monad+transformers.html#Monad+transformers

This is useful: http://noelwelsh.com/programming/2013/12/20/scalaz-monad-transformers/

 def getOneRecordByModel(x:DirectFlight): Future[Option[FlightByDetailModel]] = ??? def getRecordByUUID(x:FlightByDetailModel): Future[Option[FlightByUUIDModel]] = ??? def getUUIDRecordByModel(x:DirectFlight): Future[Option[FlightByUUIDModel]] = { import scalaz.OptionT._ val flightByUUID = for { flightByDetailModel <- optionT(getOneRecordByModel(x)) flightByUUIDModel <- optionT(getRecordByUUID(flightByDetailModel)) } yield flightByUUIDModel flightByUUID.run } 

To be able to use optionT with scala.concurrent.Future, you will need instances of Functor and Monad in the scope

  import scala.concurrent.Future object FutureMonadAndFunctor { import scalaz.Monad implicit def FutureM(implicit ec: ExecutionContext): Monad[Future] = new Monad[Future] { def point[A](a: => A): Future[A] = Future(a) def bind[A, B](fa: Future[A])(f: (A) => Future[B]): Future[B] = fa flatMap f } implicit def FutureF(implicit ec: ExecutionContext): Functor[Future] = new Functor[Future]{ def map[A, B](fa: Future[A])(f: (A) => B): Future[B] = fa map f } } import scala.concurrent.ExecutionContext.Implicits.global implicit val F = FutureMonadAndFunctor.FutureF implicit val M = FutureMonadAndFunctor.FutureM 
+3
source share

A simple solution is to use flatMap for composition instead of andThen, which is pretty specialized for side effects:

 getOneRecordByModel(x) flatMap { ... } 

For working with futures, I found it useful to read this page several times.

+2
source share

All Articles