I am trying to fix the following issue:
I have a Future[Map[A, B]]. For all B, I need to apply a method that convert B to a Future[C] and I want to give back a Future[Map[A, C]]
Here is the code I have so far:
def getClients(clientIds: Seq[Int]): Future[Map[Int, ClientData]] = {
def getClientData(clientInfo: ClientInfo): Future[ClientData] =
clientInfo match {
case ValidInfo(info) => getData(info)
case _ => throw new Exception
}
client.getClients(clientIds) map {
_.toMap map {
case (clientId: Int, clientInfo: ClientInfo) =>
getClientData(clientInfo) map {
clientData => (clientId, clientData)
}
}
}
}
This code is wrong as it returns a Iterable[Future[(Int, ClientData)]]
For info getClients is a thrift method that returns Future[Map[A, B]] where the Map is mutable, so I need to convert it to an immutable map first with toMap.
Thank you in advance for your help!
scala> def f: Future[Map[String, Future[Int]]] = ???
f: Future[Map[String,Future[Int]]]
scala> def x = for {
| m <- f
| i = m.map{ case (k, fv) => fv.map{ k -> _ } }
| l <- Future.sequence(i)
| } yield l.toMap
x: Future[Map[String,Int]]
Step by step:
Convert Future[Map[A, Future[B]]]
to Future[Iterable[Future[(A, B)]]]
:
scala> def x1 = f.map{ _.map{ case (k, fv) => fv.map{ k -> _ } } }
x1: Future[Iterable[Future[(String, Int)]]]
Convert Iterable[Future[(A, B)]]
to Future[Iterable[(A, B)]]
and flatten
Future[Future[...]]
using flatMap
:
scala> def x2 = x1.flatMap{ Future.sequence(_) }
x2: Future[immutable.Iterable[(String, Int)]]
Convert Iterable[(A, B)]
to Map[A, B]
:
scala> def x = x2.map{ _.toMap }
x: Future[Map[String,Int]]
For com.twitter.util.Future
you should use collect
instead of sequence
and toSeq
before collect
since it accepts Seq
:
def x = for {
m <- f
i = m.map{ case (k, fv) => fv.map{ k -> _ } }
l <- Future.collect(i.toSeq)
} yield l.toMap