如何在 slick 中折叠一列的总和?
How to fold a the sum of a column in slick?
我有一栏:
val a: Rep[Long] = column[Long]("a")
我想总结一下:
val b: Rep[Option[Long]] = a.sum
如果没有行或总和为负,则 return 0
否则 return 总和:
val y: Rep[Long] = b.fold(0) { x => if (x < 0) 0 else x }
但是最后一个 fold
不会编译,因为 x
是 Rep[Long]
而不是 Long
.
存在从 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)
d2
应该是什么? Shape.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]])
...
我不清楚 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)
}
我有一栏:
val a: Rep[Long] = column[Long]("a")
我想总结一下:
val b: Rep[Option[Long]] = a.sum
如果没有行或总和为负,则 return 0
否则 return 总和:
val y: Rep[Long] = b.fold(0) { x => if (x < 0) 0 else x }
但是最后一个 fold
不会编译,因为 x
是 Rep[Long]
而不是 Long
.
存在从 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)
d2
应该是什么? Shape.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]])
...
我不清楚 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)
}