Trying to make a HCons List CaseClassShape

喜夏-厌秋 提交于 2019-12-11 23:46:38

问题


Okay, so I want to create a HListCaseClassShape that will let me create case classes that overcome the 22 arity limit. So, starting from Stefan Zeiger's code here.

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)

Then I go on to create my HListCaseClassShape:

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)(_ :: _)
    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 }
}

And finally, I try to instantiate it

case class LiftedB(data1: Rep[String], data2: Rep[String], data3: Rep[String], data4: Rep[String], data5: Rep[String], data6: Rep[String], data7: Rep[String], data8: Rep[String], data9: Rep[String], data10: Rep[String], data11: Rep[String], data12: Rep[String], data13: Rep[String], data14: Rep[String], data15: Rep[String], data16: Rep[String], data17: Rep[String], data18: Rep[String], data19: Rep[String], data20: Rep[String], data21: Rep[String], data22: Rep[String], data23: Rep[String], data24: Rep[String], data25: Rep[String])
case class B(data1: String, data2: String, data3: String, data4: String, data5: String, data6: String, data7: String, data8: String, data9: String, data10: String, data11: String, data12: String, data13: String, data14: String, data15: String, data16: String, data17: String, data18: String, data19: String, data20: String, data21: String, data22: String, data23: String, data24: String, data25: String )

... and then the shape:

type DirectConsList = HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HCons[String, HNil]]]]]]]]]]]]]]]]]]]]]]]]]
type LiftedConsList = HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HCons[Rep[String], HNil]]]]]]]]]]]]]]]]]]]]]]]]]

implicit object BShape extends HListCaseClassShape[
  Product,
  LiftedConsList,
  LiftedB,
  DirectConsList,
  B](toLifted, toDirect)

def toLifted(list: LiftedConsList) = {
  list match {
    case data1 :: data2 :: data3 :: data4 :: data5 :: data6 :: data7 :: data8 :: data9 :: data10 :: data11 :: data12 :: data13 :: data14 :: data15 :: data16 :: data17 :: data18 :: data19 :: data20 :: data21 :: data22 :: data23 :: data24 :: data25 :: HNil => {
      LiftedB(data1, data2, data3, data4, data5, data6, data7, data8, data9, data10, data11, data12, data13, data14, data15, data16, data17, data18, data19, data20, data21, data22, data23, data24, data25 )
    }
    case _ => throw new Exception("malformed HList")
  }
}

def toDirect(list:DirectConsList) = {
  list match {
    case data1 :: data2 :: data3 :: data4 :: data5 :: data6 :: data7 :: data8 :: data9 :: data10 :: data11 :: data12 :: data13 :: data14 :: data15 :: data16 :: data17 :: data18 :: data19 :: data20 :: data21 :: data22 :: data23 :: data24 :: data25 :: HNil => {
      B(data1, data2, data3, data4, data5, data6, data7, data8, data9, data10, data11, data12, data13, data14, data15, data16, data17, data18, data19, data20, data21, data22, data23, data24, data25 )
    }
    case _ => throw new Exception("malformed HList")
  }
}

Only when I instantiate and run via db.stream it throws an exception:

Exception in thread "main" java.lang.ClassCastException: slick.collection.heterogeneous.HCons cannot be cast to com.example.CaseClassShapeQueryExample$B
  at com.example.CaseClassShapeQueryExample$$anonfun$2.apply(CaseClassShapeQueryExample.scala:106)
  at slick.backend.DatabasePublisher$$anon$3$$anonfun$onNext$1.apply(DatabasePublisher.scala:48)
  at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)

So it's got the plain tuple object (i.e. DirectConsList) coming back from the query but I can't cast it into the B object. What am I doing wrong???


回答1:


Looks like all I was missing was a mapPlain(folded.asInstanceOf[PlainList]) in the toMapped method. Working HListCaseClassShape implementation is as follows:

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 }
}

Also, gist is available here: HListCaseClassShape.



来源:https://stackoverflow.com/questions/40543310/trying-to-make-a-hcons-list-caseclassshape

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!