scala: будущая последовательность выполнения play-framework внутри одного запроса - PullRequest
0 голосов
/ 15 мая 2018

Я довольно новичок в функциональном программировании в scala и play-framework

У меня есть запрос API, который должен добавить главу в комикс, созданный этим конкретным пользователем, поэтому я должен убедиться, чтокомикс существует и принадлежит этому пользователю.Что усложняет, это Future, Option и т. Д., И я не могу убедиться, что последняя команда выполнена последней.Действительно, моя проблема возникает из-за того, что последняя команда выполняется до того, как весь мой доступ к БД завершен

Вот код, надеюсь, он понятен

  def addchapter(): Action[AnyContent] = Action.async { implicit request =>
    var hashMap: HashMap[String, JsValue] = HashMap()
    var apiResult: ApiResult = ApiResult(
    ReturnCode.COMIC_ADDCHAPTER.id,
    ReturnCode.COMIC_ADDCHAPTER.toString(),
    ReturnResult.RESULT_ERROR.toString(),
    "init"
  )
  var fHashMap: Future[HashMap[String, JsValue]] = Future {
    hashMap
  }
  try {
    val oReq = request.body.asJson
    val jsReq = oReq.getOrElse(JsString("null"))
    val sessionid = (jsReq \ 
      "sessionid").getOrElse(JsString("0")).as[String]
    val comicid = (jsReq \ 
      "comicid").getOrElse(JsString("comicid")).as[String]
    val foUser = userRepo.getUserBySessionId(sessionid)
    LogManager.DebugLog(this, "add chapter: " + sessionid + " => " + 
      comicid)
    fHashMap = foUser.flatMap( oUser => {
      oUser match {
        case Some(user) => {
          val foComic = comicRepo.getComicByComicId(comicid)
        fHashMap = foComic.flatMap( oComic => {
          oComic match {
            case Some(comic) => {                  
              LogManager.DebugLog(this, "about to add chapter")
              val fTup = comicRepo.addChapterToComic(comic)
              fHashMap = fTup.map( tuple => {
                val wr = tuple._1
                val mc = tuple._2
                apiResult = ApiResult(
                  ReturnCode.COMIC_ADDCHAPTER.id,
                  ReturnCode.COMIC_ADDCHAPTER.toString(),
                  ReturnResult.RESULT_ERROR.toString(),
                  "successfully added chapter!"
                )
                val payloadcomic = 
PayloadComicFactory.createWithComic(mc)
                hashMap("apiresult") = Json.toJson(apiResult)
                hashMap += "comic" -> Json.toJson(payloadcomic)
                LogManager.DebugLog(this, "successfully added 
chapter!")
                hashMap
              })
              // return
              fHashMap
            }
            case None => {
              apiResult = ApiResult(
                ReturnCode.COMIC_ADDCHAPTER.id,
                ReturnCode.COMIC_ADDCHAPTER.toString(),
                ReturnResult.RESULT_ERROR.toString(),
                "comic not found"
              )
              hashMap("apiresult") = Json.toJson(apiResult)
              Future { hashMap }
            }
          }
        })
        Future { hashMap }
      }
      case None => {
        apiResult = ApiResult(
          ReturnCode.COMIC_ADDCHAPTER.id,
          ReturnCode.COMIC_ADDCHAPTER.toString(),
          ReturnResult.RESULT_ERROR.toString(),
          "unauthorized to add chapter to this comic"
        )
        hashMap("apiresult") = Json.toJson(apiResult)
        Future { hashMap }
      }
    }
  })
    // I cannot put the return here, it is compile error saying that the return value is a Unit
    //      fHashMap.map( hashmap => {
    //        Ok(Json.toJson(hashmap))
    //      })
} catch {
  case t: Throwable => {
    LogManager.DebugException(this, "ex: ", t)
    // I cannot put it here, it is compile error saying that the return value is Unit
    //        fHashMap.map( hashmap => {
    //          Ok(Json.toJson(hashmap))
    //        })
    fHashMap
  }
}
    // I have to return here, but "return of the request" will be executed first before all my db access is completed, thus the ApiResult is still returning wrong state
LogManager.DebugLog(this, "return of the request")
fHashMap.map( hashmap => {
  Ok(Json.toJson(hashmap))


   })
  }

1 Ответ

0 голосов
/ 15 мая 2018

Вы можете попробовать следующий рефакторинг в качестве первого шага к более идиоматическому подходу Scala:

def addchapter(): Action[AnyContent] = Action.async { implicit request =>
  def apiResultJson(message: String) = 
    Json.toJson(ApiResult(
      ReturnCode.COMIC_ADDCHAPTER.id,
      ReturnCode.COMIC_ADDCHAPTER.toString(),
      ReturnResult.RESULT_ERROR.toString(),
      message))

  def okResponse(hashMapF: Future[HashMap]) =
    hasMapF.map(hashMap => Ok(Json.toJson(hashMap)))

  Try {
    val oReq = request.body.asJson
    val jsReq = oReq.getOrElse(JsString("null"))
    val sessionid = (jsReq \ "sessionid").getOrElse(JsString("0")).as[String]
    val comicid = (jsReq \ "comicid").getOrElse(JsString("comicid")).as[String]

    userRepo.getUserBySessionId(sessionid).flatMap {

      case Some(user) =>
        comicRepo.getComicByComicId(comicid).flatMap {

          case Some(comic) =>                     
            comicRepo.addChapterToComic(comic).map { tuple => 
              val payloadcomic = PayloadComicFactory.createWithComic(tuple._2)
              HashMap(
                "apiresult" -> apiResultJson("successfully added chapter!"),
                "comic" -> Json.toJson(payloadcomic))
              }

          case None => 
            Future(HashMap("apiresult" -> apiResultJson("comic not found")))

        }

      case None =>
        Future(HashMap(
          "apiresult" -> apiResultJson("unauthorized to add chapter to this comic")))

    }
  } match {
    case Success(resultHashMapF) =>
      okResponse(resultHashMapF)

    case Failure(t) =>
      okResponse(Future(HashMap("apiresult" -> apiResultJson(t.toString))))
  }
}
...