Home > Back-end >  Handle Future[Option[T]] when traversing a List
Handle Future[Option[T]] when traversing a List

Time:10-29

  def getCommentIds(
      commentTargetId: Long,
      sortOrder: CommentOrderEnum): Future[Seq[CommentStatsBO]]

def getCommentDetail(commentId: Long): Future[Option[CommentDetailDTO]]

def getCommentListWithDetail(
      targetId: Long,
      sortOrder: CommentOrderEnum,
      page: Int): Future[Seq[CommentDetailDTO]] = {
    commentModel.getCommentIds(targetId, sortOrder).flatMap {
      commentStatsBOSeq =>
        Future.traverse(commentStatsBOSeq) { commentStatsBO =>
// commentDetail is a Future[Option[T]]
          val commentDetail = getCommentDetail(commentStatsBO.iId)
          commentDetail.map(commentOpt =>
            commentOpt
// merge the stat info into the comment detail
              .map(_.copy(replyCount = Some(commentStatsBO.replyCount)))
              .getOrElse(CommentDetailDTO))

        }

    }
  }

case class CommentDetailDTO(
    id: Long,
    author: JsObject,
    detail: CommentDetail,
replyCount: Option[Int] = None
)

Firstly, the function getCommentIds returns a sequence of CommentStatsBO, then traversing it and try to get detail for every comment. Here comes the question, getCommentDetail returns a Future which contains an option since the comment maybe not found, in this case, how to filter those ones whose option is None? I have tried getOrElse , but don't know how to define an empty object just like Json.obj() since case class doesn't support. Thanks!

CodePudding user response:

Don't try to do too many things at the same time, rather build the solution you need step by step.

If you do a simple Future.traverse using just getCommentDetail you will get a Future[Seq[Option[CommentDetailDTO]]] which then you can map and use collect with the Seq to remove the Option

def getCommentListWithDetail(
  targetId: Long,
  sortOrder: CommentOrderEnum,
  page: Int
): Future[Seq[CommentDetailDTO]] =
  commentModel.getCommentIds(targetId, sortOrder).flatMap { commentStatsBOSeq =>
    Future.traverse(commentStatsBOSeq) { commentStatsBO =>
      getCommentDetail(commentStatsBO.iId)
    } map { commentOptionalDetails =>
      commentOptionalDetails.collect {
        case Some(commentDetail) => commentDetail
      }
    }
  }

Or if you use cats, you can use traverseFilter

import cats.syntax.all._

def getCommentListWithDetail(
  targetId: Long,
  sortOrder: CommentOrderEnum,
  page: Int
): Future[Seq[CommentDetailDTO]] =
  commentModel.getCommentIds(targetId, sortOrder).flatMap { commentStatsBOSeq =>
    commentStatsBOSeq.traverseFilter(getCommentDetail)
  }
  • Related