Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play 2.2 -Scala - How to chain Futures in Controller Action

I have 3 futures of type Response. The first future returns a JsValue which defines if future 2 and future 3 shall be executed or only future 3 shall be executed.

Pseudocode: If Future 1 then {future2 and future 3} else future 3

Iam trying to do this in a play framwork action which means in order to use the result of the futures later I cant use onSuccess, onFailure and onComplete because all of them return Unit and not the actual JsValue from the last future.

I tried to do this with map() and andThen but I am a Scala noob and I guess i wasn't able to do it because I always just missed a little point. Here is my current approach which does not work!

def addSuggestion(indexName: String, suggestion: String) = Action.async {
  val indexExistsQuery: IndexExistsQuery = new IndexExistsQuery(indexName);
  val addSuggestionQuery: AddSuggestionQuery = new AddSuggestionQuery(indexName, suggestion)
  val indexCreationQuery: CreateCompletionsFieldQuery = new CreateCompletionsFieldQuery(indexName)

  val futureResponse: Future[Response] = for {
    responseOne <- EsClient.execute(indexExistsQuery)
    responseTwo <- EsClient.execute(indexCreationQuery) if (indexExistsQuery.getBooleanResult(indexExistsQuery.getResult(responseOne)))
    responseThree <- EsClient.execute(addSuggestionQuery)
  } yield responseThree

  futureResponse.map { response =>
  Ok("Feed title: " + (response.json))
}
like image 635
MeiSign Avatar asked Oct 20 '22 22:10

MeiSign


1 Answers

I created some pseudocode:

checkIndexExists() map {
  case true => Future.successful()
  case false => createIndex()
} flatMap { _ =>
  query()
}.map { response =>
  Ok("Feed title: " + (response.json))
}.recover { 
  case _ => Ok("bla") 
} 

First you fire up the query if the index exists. Then you map that future how to work with that Future[Boolean] if it successful. Since you use map, you kind of extract the Boolean. If the index exists, you just create a future that is already complete. If the index not exists you need to fire up the index creation command. Now you have the situation that you have nested Future's (Future[Future[Response]]). Using flatMap you remove one dimension, so that you only have Future[Response]. That can be mapped to a Play result.

Update (the implementation of MeiSign):

  EsClient.execute(indexExistsQuery) map { response =>
      if (indexExistsQuery.getBooleanResult(indexExistsQuery.getResult(response))) Future.successful(Response)
      else EsClient.execute(indexCreationQuery)
    } flatMap { _ =>
      EsClient.execute(addSuggestionQuery)
    } map { response: Response =>
      Ok("Feed title: " + (response.json))
    }
like image 117
Schleichardt Avatar answered Nov 15 '22 05:11

Schleichardt