2013-10-23 23 views
4

我有3类期货的回应。第一个未来将返回一个JsValue,它定义将来2和将来3将被执行还是仅仅执行未来3。玩2.2 -Scala - 如何在控制器行动链期货

伪代码: 如果未来1,则{future2和未来3} 否则未来3

荫试图做到这一点的一出戏framwork行动,这意味着为了以后使用期货的结果,我不能使用onSuccess,onFailure和onComplete,因为它们都返回Unit而不是最后一个未来的实际JsValue。

我试图用map()和then来做到这一点,但我是斯卡拉noob,我想我无法做到这一点,因为我总是错过了一点。这是我目前的方法,这是行不通的!

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)) 
} 

回答

3

我创造了一些伪代码:

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

首先,你火起来的查询,如果该索引存在。 然后,如果它成功,那么您将映射未来如何与Future[Boolean]一起工作。由于您使用地图,因此您需要提取Boolean。如果索引存在,您只需创建一个已经完成的未来。如果索引不存在,则需要启动索引创建命令。现在,您遇到嵌套FutureFuture[Future[Response]])的情况。使用flatMap您删除一个维度,以便您只有Future[Response]。这可以映射到播放结果。

更新(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)) 
    } 
+2

这里实施的解决方案,非常感谢你: https://gist.github.com/MeiSign/d7ab401c717e8b8ef6b9 – MeiSign

+1

你为什么要创建索引@运行?不应该这样做吗? –

+1

在我的用例索引中有一个固定的映射,我希望能够在运行时创建它们。我们在这里谈论的是可被视为内容容器的elasticsearch索引。 – MeiSign

0

我发现这个解决办法,但我不认为这是一个很好的解决方案,因为荫使用Await.result(),这是一个阻塞操作。 如果有人知道如何重构此代码而不阻止操作,请让我知道。

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 indexExists: Boolean = indexExistsQuery.getBooleanResult(indexExistsQuery.getResult(Await.result(EsClient.execute(indexExistsQuery), 5.second))) 
    if (indexExists) { 
    EsClient.execute(addSuggestionQuery).map { response => Ok("Feed title: " + (response.json)) } 
    } else { 
    val futureResponse: Future[Response] = for { 
     responseTwo <- EsClient.execute(indexCreationQuery) 
     responseThree <- EsClient.execute(addSuggestionQuery) 
    } yield responseThree 

    futureResponse.map { response => 
     { 
     Ok("Feed title: " + (response.json)) 
     } 
    }.recover { case _ => Ok("bla") } 
    } 
}