基于凭据的多个可选调用的Scala for / yield

时间:2018-07-26 21:09:36

标签: scala lagom

我需要在一次调用中获得一个包含3个其他案例类的完整案例类。但是,根据用户凭据,他们可能会或可能不会访问该案例类的某些部分。

下面是我当前的操作方式(它有效)。正在拨打电话,但随后清除了未经授权的案件类别。理想情况下,如果它们没有适当的凭据,我想停止通话(由于带宽低),并返回无。

持久性实体服务调用需要一个Option [PersonOne]和Option [PersonTwo],因此.ask必须返回该值,否则它表示正在返回一个对象且不会编译。

override def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) = ServerServiceCall { _ =>
for {
  g <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)
  h <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne) //if (credOne) **this 'if' does not work**

  s <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo)
} yield {
  val x: Option[PersonOne] = if (credOne == Some(true)) h else None
  val y: Option[PersonTwo] = if (credTwo == Some(true)) s else None
  CompletePerson(g.get, x, y)

  //TODO catch if no employee is returned
  //throw NotFound (s"Person not Found with $id");
}

}

3 个答案:

答案 0 :(得分:1)

这是函数的一个版本,如果适当的凭据值为ask,则只会调用Some(true)

override def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) = ServerServiceCall { _ =>
  CompletePerson(
    registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral).get,
    credOne.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne)),
    credTwo.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo))
  )
}

关键部分是这样:

credX.filter(_ == true).flatMap(...)
  • 如果credXNone,它将返回None
  • 如果credX包含false,它将返回None
  • 如果credXSome(true),那么flatMap将调用ask函数
  • 如果ask返回None,则表达式将返回None,否则它将返回Some[PersonX]

我对某些数据类型不清楚,但是我认为这应该使您了解如何处理此代码。 (例如,裸露的.get看起来很危险,因为它可能引发异常)

评论后编辑

我解决了filter(_)的一个问题,应该是filter(_ == true)

看起来ask实际上返回了Option[Option[T]],在这种情况下,这可能更接近于所需的条件。

def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) = ServerServiceCall { _ =>
  for {
    g <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)
    gen <- g
  } yield {
    val p1 = credOne.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne))).flatten
    val p2 = credTwo.filter(_ == true).flatMap(_ => registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo))).flatten

    CompletePerson(gen, p1, p2)
  }
}

答案 1 :(得分:0)

我不确定您要问什么,但是您是否担心

registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)

返回None,您将继续拨打昂贵的.ask电话吗?正如我们从中看到的那样,不会发生的变化

def giveMeSome = {println("giving you Some"); Some(1)}
def giveMeNone = {println("giving you None"); None}
def giveMeSomeMore = {println("giving you Some more"); Some(2)}

val ans = for {
  a <- giveMeSome
  f <- giveMeNone
  q <- giveMeSomeMore
} yield (a, f, q)

println(ans)

可打印

giving you Some
giving you None
None

我们还可以看到,在这种情况下,您会得到None的回信。我无法确定您是否想要None或引发错误。如果您要输入错误,则可以包装上面的内容

答案 2 :(得分:0)

我没有完全解决您的问题,但是根据我的理解,您想先检查credOne == Some(true)&& credTwo == Some(true),然后继续进行其他操作,否则返回None

override def getPerson(id: UUID, credOne: Option[Boolean], credTwo: Option[Boolean]) 
  =
   for {
       cone <- credOne
       ctwo <- credTwo
       if cone
       if ctwo
   } yield {
   ServerServiceCall { _ =>
     for {
         g <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonGeneral)
         h <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonOne)
         s <- registry.refFor[PersonEntity](id.toString()).ask(GetPersonTwo)
         if g.isDefined
         } yield {
           CompletePerson(g.get, h, s)
          }
       }