根据成功的价值将成功转化为失败的最佳方法

The best way to convert Success into Failure depending on the value of Success

我用玩!带有 ReactiveMongo 插件的框架(相应版本 2.3 和 0.11)。我有下一个代码,它从 MongoDB 集合中删除项目,returns 一些受影响的项目:

/**
  * Removes all subscribers by subscription id
  * 
  * @param subscriptionId id of the subscription
  * @return count of removed subscribers
  */  
def deleteAll(subscriptionId: String): Future[Int] = {
      logger.debug(s"Removing all subscribers with subscription id '$subscriptionId'...")
      val query = BSONDocument("subscriptionId" -> BSONObjectID(subscriptionId))
      subscribersCollection.remove(query) map { writeResult: WriteResult =>
        writeResult.n match {
          case subscribersRemoved if subscribersRemoved > 0 =>
            logger.debug(s"Successfully removed $subscribersRemoved subscribers with subscribtion id '$subscriptionId'")
          case _ => logger.debug(s"No subscribers with subscribtion id '$subscriptionId' were removed")
        }
        writeResult.n
      }
  }

由于 ReactiveMongo 文档,WriteResult class returned by collection's remove() method 具有 hasErrorwriteErrors 等字段指示在执行数据库查询期间发生的错误。

那么,为了根据 WriteResulthasError 字段从中 return 失败,增强我的方法的最佳和最干净的方法是什么?

这是粗略的例子:

subscribersCollection.remove(query).??? match {
  case Success(writeResult) if writeResult.hasErrors => Failure(new DatabaseException(writeResult.errMsg, writeResult.code)
  case any => any
}

即我的方法应该 return a Failure 即使数据库查询 returns a Success with error fields

提前致谢!我真的很感激任何帮助,以使我的代码更好

P.S。我考虑过将我所有的代码包装在 Try 中,只是在 hasError 标志设置为 true 时抛出异常,但我相信它可以用更好的方式完成,也许 Futuretransform()方法

P.P.S。由于某些原因,来自 ReactiveMongo documentation 的代码示例和演示不处理 WriteError 的错误字段和标志。事实上,文档说

If the write result actually indicates an error, the Future will be in a failed state

但是,我已经在几个应用程序的生产代码中看到过这样的处理,所以它有点令人困惑。这样的处理是不是有点过分了?

使用flatMapFuture.failed

Future 上执行 flatMap 然后根据值 return Future.failed(new Exception("unexpected value"))

假设我们有一个函数return是一些 int

的未来
def httpStatus: Future[Int] = Future { 404 }

httpStatus.flatMap { 
 case 404 => //return failed future
  Future.failed(new Exception("Bad status"))
 case value => value
}

现在你的代码变成了

def deleteAll(subscriptionId: String): Future[Int] = {
      logger.debug(s"Removing all subscribers with subscription id '$subscriptionId'...")
      val query = BSONDocument("subscriptionId" -> BSONObjectID(subscriptionId))
      subscribersCollection.remove(query) flatMap { writeResult: WriteResult =>
        writeResult.n match {
          case subscribersRemoved if subscribersRemoved > 0 =>
            logger.debug(s"Successfully removed $subscribersRemoved subscribers with subscribtion id '$subscriptionId'")
            Future.successful(writeResult.n)
          case status => 
             logger.debug(s"No subscribers with subscribtion id '$subscriptionId' were removed")
             Future.failed(new Exception(s"bad status exception. status: $status"))
        }

      }
  }