Skip to content

Instantly share code, notes, and snippets.

@deusaquilus
Created November 20, 2016 16:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save deusaquilus/5b52b82598c534ca09119efcf0acbc50 to your computer and use it in GitHub Desktop.
Save deusaquilus/5b52b82598c534ca09119efcf0acbc50 to your computer and use it in GitHub Desktop.
Creating a CaseClassShape that uses HList therefore can have >22 Arity
object CaseClassHListShapeQueryExample {
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 }
}
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 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")
}
}
def toLifted(list: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]]]]]]]]]]]]]]]]]]]]]]]]]) = {
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")
}
}
implicit object BShape extends HListCaseClassShape[
Product,
LiftedConsList,
LiftedB,
DirectConsList,
B](toLifted, toDirect)
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 )
def main(args:Array[String]) {
val queryAll = for {
f <- TableQuery[Users]
} yield LiftedB(f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind), f.name.getOrElse("".bind))
val db = SomeDriver.api.Database.forURL(
url = "jdbc:...",
driver = "...",
user = user,
password = password)
val res = db.stream(query.result).foreach(println(_))
Await.result(res, Duration.Inf)
}
}
@deusaquilus
Copy link
Author

deusaquilus commented Nov 21, 2016

The regular i.e. 'monomorphic' Slick CaseClassShape maps back and fourth via tuples which are still affected (as of slick 3.1.1 / Scala 2.11) by the 22 arity limitation. That is to say, if you want to create a CaseClassShape with more then 22 fields your are out of luck with out-of-the-box Slick. Fortunately using Stephan Zeiger's HListShape (info here) I have managed to create a HListCaseClassShape that overcomes the 22 arity limit by mapping to HLists instead of tuples (original posting here) which should work exactly the same way in most cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment