Alan C.
Alan C.

Reputation: 645

In Scala, how do I share data between two sequential futures?

I want to share data between two sequentially-executed futures. Here's the draft of my code:

def deleteRecord(request: DeleteRequest): TwitterFuture[domain.Response] = {
    lazy val fn = {

      repository.findById(request.id).map { record: Option[TableRecord] =>
        val data = Map[String,Any](
            "id" -> String.valueOf(request.id),
            "study" -> String.valueOf(request.study),
            "associate" -> String.valueOf(record.get.associate),
            "role" -> String.valueOf(record.get.role)
          )
      }.flatMap { _ =>
        repo.delete(request.id).map { rowsAffected: Int =>
          /* audit study associate deletion */
          val event = audit(AuditEventType.RecordDeleted, principal.get, data)
          pipelineService.logEvent(topicSettings.database, event)

          domain.Response(status = Status.Created, data = Seq(rowsAffected))
        }
      }
    }

    secure(principal.get, fn)
  }

Specifically, I want event in the repo.delete block to have access to the data Map from the findById block.

I based my implementation of sequential futures on https://stackoverflow.com/a/25057306/3195691.

Upvotes: 0

Views: 268

Answers (1)

yǝsʞǝla
yǝsʞǝla

Reputation: 16422

You need to make that value a result of your future or in other words you should return it. Just declaring a variable does not make the block return it - it stays accessible only in the scope of its declaration.

Example of f1 producing/returning a result and f2 using it:

import scala.concurrent._
import ExecutionContext.Implicits.global
import scala.concurrent.duration._

scala> val f1 = Future(1)
f1: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@538f7b25

scala> val f2 = f1.flatMap { v1 => Future(v1 + 2) }
f2: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@28d364fd

scala> val res = Await.result(f2, 2 seconds) // just to show the result, don't use Await!
res: Int = 3

In your example it looks like findById returns a Future[Option[TableRecord]]. If so, then change your code to this:

repository.findById(request.id).map { record: Option[TableRecord] =>
        Map[String,Any](
            "id" -> String.valueOf(request.id),
            "study" -> String.valueOf(request.study),
            "associate" -> String.valueOf(record.get.associate),
            "role" -> String.valueOf(record.get.role)
        )
      }.flatMap { data => //... use `data` here

The type of a future returned from map is Future[Map[String,Any]] and the type of data passed to flatMap is Map[String,Any].

Upvotes: 2

Related Questions