Итак, я пытаюсь реализовать метод zipHList
, который похож на Query.zip
, но возвращает HLists вместо кортежей.Я начинаю с формы запроса:
implicit class QueryExt[+E, U, C[_]](query:Query[E, U, C]) {
def zipHList[E2, U2, D[_]](q2: Query[E2, U2, D]): Query[HCons[E, HCons[E2, HNil]], HCons[U, HCons[U2, HNil]], C] = standardHListJoin(q2, JoinType.Zip)
private[this] def standardHListJoin[E2, U2, D[_]](q2: Query[E2, U2, D], jt: JoinType) = {
val leftGen, rightGen = new AnonSymbol
val aliased1 = query.shaped.encodeRef(Ref(leftGen))
val aliased2 = q2.shaped.encodeRef(Ref(rightGen))
new BaseHListJoinQuery[E, E2, U, U2, C, E, E2](leftGen, rightGen, query.toNode, q2.toNode, jt,
aliased1.zipHList(aliased2), aliased1.value, aliased2.value)
}
}
Затем поддерживающие формы:
implicit class ShapedValueExt[T, U](s: ShapedValue[T, U]) {
def zipHList[T2, U2](s2: ShapedValue[T2, U2]) = new ShapedValue[HCons[T, HCons[T2, HNil]], HCons[U, HCons[U2, HNil]]]((s.value :: s2.value :: HNil), hconsShape(s.shape, hconsShape(s2.shape, hnilShape))) //Shape.tuple2Shape(s.shape, s2.shape)
}
final class BaseHListJoinQuery[+E1, +E2, U1, U2, C[_], +B1, +B2](leftGen: TermSymbol, rightGen: TermSymbol, left: Node, right: Node, jt: JoinType, base: ShapedValue[_ <: HCons[E1, HCons[E2, HNil]], HCons[U1, HCons[U2, HNil]]], b1: B1, b2: B2)
extends WrappingQuery[HCons[E1, HCons[E2, HNil]], HCons[U1, HCons[U2, HNil]], C](AJoin(leftGen, rightGen, left, right, jt, LiteralNode(true)), base) {
}
Наконец, поддерживающие HList
формы:
object HListShapeSupport {
final class HListShape[Level <: ShapeLevel, M <: HList, U <: HList : ClassTag, P <: HList](val shapes: Seq[Shape[_, _, _, _]]) extends MappedScalaProductShape[Level, HList, M, U, P] {
def buildValue(elems: IndexedSeq[Any]) = elems.foldRight(HNil: HList)(_ :: _)
def copy(shapes: Seq[Shape[_ <: ShapeLevel, _, _, _]]) = new HListShape(shapes)
}
implicit def hnilShape[Level <: ShapeLevel] = new HListShape[Level, HNil.type, HNil.type, HNil.type](Nil)
implicit def hconsShape[Level <: ShapeLevel, M1, M2 <: HList, U1, U2 <: HList, P1, P2 <: HList](implicit s1: Shape[_ <: Level, M1, U1, P1], s2: HListShape[_ <: Level, M2, U2, P2]) =
new HListShape[Level, M1 :: M2, U1 :: U2, P1 :: P2](s1 +: s2.shapes)
class HListCaseClassShape[P <: Product, LiftedList, LiftedCaseClass <: P, PlainList, PlainCaseClass <: P](
mapLifted: LiftedList => LiftedCaseClass, mapPlain: PlainList => PlainCaseClass)(
implicit columnShapes: Shape[FlatShapeLevel, LiftedList, PlainList, LiftedList], classTag: ClassTag[PlainCaseClass])
extends MappedScalaProductShape[FlatShapeLevel, P, LiftedCaseClass, PlainCaseClass, LiftedCaseClass] {
val shapes = columnShapes.asInstanceOf[HListShape[_,_,_,_]].shapes
override def toMapped(v: Any) = {
val folded = v.asInstanceOf[Product].productIterator.foldRight(HNil: HList)(_ :: _)
mapPlain(folded.asInstanceOf[PlainList])
}
def buildValue(elems: IndexedSeq[Any]) = {
val list = elems.foldRight(HNil: HList)(_ :: _)
mapLifted(list.asInstanceOf[LiftedList])
}
def copy(s: Seq[Shape[_ <: ShapeLevel, _, _, _]]) = new HListCaseClassShape(mapLifted, mapPlain) { override val shapes = s }
}
}
Пока что,когда я пытаюсь запустить это, возникает следующая ошибка:
val q = names.zipHList(names)
val seq = Await.result(db.stream(q.result).foreach(println(_)), Duration.Inf)
println(seq)
// Exception in thread "main" java.lang.ClassCastException: scala.Tuple2 cannot be cast to slick.collection.heterogeneous.HCons
// at com.examples.HListZip$$anonfun$2.apply(HListZip.scala:57)
Кроме того, когда я просто пытаюсь получить результат, становится ясно, что на самом деле это список кортежей.
val names = TableQuery[People].map(_.name)
val q = names.zipHList(names)
val seq = Await.result(db.run(q.result), Duration.Inf)
println(seq)
// Vector((Joe,Joe), (Jack,Jack), (Jill,Jill), (John,John), (Jim,Jim)]
Что я делаю неправильно?Почему он считает, что форма - это кортеж, а не HList?