Как сложить сумму столбца в слик? - PullRequest
0 голосов
/ 17 июня 2020

У меня есть столбец:

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

, который я хочу суммировать:

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

Если нет строк или сумма отрицательна, вернуть 0 в противном случае вернуть sum:

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)

Прежде, чем я go продолжу спускаться по кроличьей норе, как это должно работать?

Я почти уверен, что мои намерения использование 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]])
    ...

1 Ответ

1 голос
/ 18 июня 2020

Мне непонятно, какие 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)
  }
...