首页 > 解决方案 > 如何折叠光滑的列的总和?

问题描述

我有一个专栏:

val a: Rep[Long] = column[Long]("a")

我想总结一下:

val b: Rep[Option[Long]] = a.sum

如果没有行或总和为负,则返回0,否则返回总和:

val y: Rep[Long] = b.fold(0) { x => if (x < 0) 0 else x }

但是,最后一个fold不会编译,因为x它是 aRep[Long]而不是 a Long

有一个 to 的隐式b转换AnyOptionExtensionMethods[Rep[Option[Long]], Rep[Long]]Rep[Long]这是导致问题的第二种类型参数。我希望它是Long。明确表示如下:

val c: LongJdbcType = longColumnType
val d: Shape[FlatShapeLevel, Rep[Long], Long, Rep[Long]] = Shape.repColumnShape[Long, FlatShapeLevel](c)
val e: OptionLift[Rep[Long], Rep[Option[Long]]] = OptionLift.repOptionLift[Rep[Long], Long](d)
val f: AnyOptionExtensionMethods[Rep[Option[Long]], Rep[Long]] = anyOptionExtensionMethods[Long, Rep[Long]](b)(e)

我需要的是:

val d2: Shape[FlatShapeLevel, Long, Long, Long] = ???
val e2: OptionLift[Long, Rep[Option[Long]]] = OptionLift.anyOptionLift[Long, Long](d2)
val f2: AnyOptionExtensionMethods[Rep[Option[Long]], Long] = anyOptionExtensionMethods[Long, Long](b)(e2)

应该是什么d2Shape.primitiveShape是我所期望的,但需要有一个OptionLift.constOptionLift功能。所以现在我坚持:

val d3: Shape[FlatShapeLevel, Long, Long, ConstColumn[Long]] = Shape.primitiveShape[Long, FlatShapeLevel]
val e3: OptionLift[Long, Rep[Option[Long]]] = ???
val f3: AnyOptionExtensionMethods[Rep[Option[Long]], Long] = anyOptionExtensionMethods[Long, Long](b)(e3)

在我进一步深入兔子洞之前,这应该如何工作?

我很确定我的预期用途fold是有效的。至少这符合我的直觉以及文档:

/** Extension methods for Options of single- and multi-column values */
final class AnyOptionExtensionMethods[O <: Rep[_], P](val r: O) extends AnyVal {
  /** Apply `f` to the value inside this Option, if it is non-empty, otherwise return `ifEmpty`. */
  def fold[B, BP](ifEmpty: B)(f: P => B)(implicit shape: Shape[FlatShapeLevel, B, _, BP]): BP = {
  ...

更新:

可能有一个线索,getOrElse因为它正在进行一些铸造恶作剧:

  def getOrElse[M, P2 <: P](default: M)(implicit shape: Shape[FlatShapeLevel, M, _, P2], ol: OptionLift[P2, O]): P =
    // P2 != P can only happen if M contains plain values, which pack to ConstColumn instead of Rep.
    // Both have the same packedShape (RepShape), so we can safely cast here:
    fold[P, P](shape.pack(default): P)(identity)(shape.packedShape.asInstanceOf[Shape[FlatShapeLevel, P, _, P]])
    ...

标签: scalaslick

解决方案


我不清楚你想从折叠中产生什么 SQL。折叠的主体需要是 Slick 可以变成 SQL 的东西。

要处理来自数据库的可选结果,您可以做的是过滤掉不需要的值:

val query: Rep[Int] = table.map(_.number).sum
   .filter(_ >= 0)
   .getOrElse(0)

这将变成一个 SQL Case 表达式。

或者也许运行这个客户端会更清楚:

val action: DBIO[Int] =
  table.map(_.number).sum.result.map { optional =>
      // Now in Scala, client side
      optional.fold(0)(x => if (x < 0) 0 else x)
  }

推荐阅读