2017-09-15 3 views
1

Ich habe scala-Code mit slick codegen automatisch generiert. Ich sehe, dass einige Tabellen Zeilen als HLists implementiert sind. (aber das sind Slick HList, nicht die normale formlose HList)Elemente aus Slick HLIST holen (oder Slick HLIst in Shapeless HList umwandeln)

Jetzt möchte ich ein bestimmtes Element aus dem HList als eine Zeile von der Slick-Abfrage zurückgegeben.

ich gegoogelt und diesen Thread gefunden

Getting elements from an HList

Aber für Slick hList funktioniert nicht. es funktioniert sehr gut für Shapeless hList

Ich habe auch versucht die Methode anwenden

val x: Long = slickHList (2)

aber nicht kompilieren, weil Art Alle entspricht nicht exected Typ Lange. Ich würde es hassen, eine .asInstanceOf

zu tun Gibt es eine typsichere Weise, in der ich auf die Elemente des Slick HList zugreifen kann?

Edit: auf der Grundlage der eingegebenen unter ich den Code unter

package com.abhi 

object SlickAndShapeless { 
    import slick.collection.heterogeneous.{HCons, HList, HNil} 
    import slick.collection.heterogeneous.syntax.HNil 

    type MyRow = HCons[Long, HCons[String, HNil]] 
    val row : MyRow = 1L :: "foo" :: HNil 
    import HListExtensions._ 
    val hlist = row.asShapeless 
    val container = new Container(hlist) 
    val item = container.get(1) 
} 

class Container[L <: shapeless.HList](list: L) { 
    import shapeless._ 
    import nat._ 
    import ops.hlist._ 
    def get(n: Nat)(implicit at: At[L, n.N]): at.Out = list[n.N] 
} 

object HListExtensions { 
    import slick.collection.heterogeneous.{HNil => SHNil, HList => SHList, HCons} 
    import shapeless.{::, HList, HNil} 

    implicit class HListShapelessSlick(val list: HList) extends AnyVal { 
     def asSlick : SHList = list match { 
     case HNil => SHNil 
     case head :: tail => head :: tail.asSlick 
     } 
    } 

    implicit class HListSlickShapeless(val list: SHList) extends AnyVal { 
     def asShapeless : HList = list match { 
     case SHNil => HNil 
     case HCons(head, tail) => head :: tail.asShapeless 
     } 
    } 
} 

Das Problem mit dem obigen Code ist geschrieben, dass die Art von item von val item = container.get(1) erhalten at.Out und nicht Long als ich erwartet hatte.

build.sbt

libraryDependencies ++= Seq(
    "com.typesafe.slick" % "slick_2.12" % "3.2.1", 
    "com.chuusai" % "shapeless_2.12" % "2.3.2" 
) 

ich zwei Compiler-Fehler auch

Error:(19, 35) Implicit not found: shapeless.Ops.At[shapeless.HList, shapeless.Succ[shapeless._0]]. You requested to access an element at the position shapeless.Succ[shapeless._0], but the HList shapeless.HList is too short. 
    val item : Long = container.get(1) 
Error:(19, 35) not enough arguments for method get: (implicit at: shapeless.ops.hlist.At[shapeless.HList,shapeless.Succ[shapeless._0]])at.Out. 
Unspecified value parameter at. 
    val item : Long = container.get(1) 

Antwort

3

Es ist möglich, erstellen Erweiterungsmethoden finden Sie unter:

object HListExtensions { 

    import slick.collection.heterogeneous.{HNil => SHNil, HList => SHList, HCons} 
    import shapeless.{ ::, HList, HNil } 

    implicit class HListShapelessSlick(val list:HList) extends AnyVal { 
    def asSlick:SHList = list match { 
     case HNil => SHNil 
     case head :: tail => head :: tail.asSlick 
    } 
    } 

    implicit class HListSlickShapeless(val list:SHList) extends AnyVal { 
    def asShapeless:HList = list match { 
     case SHNil => HNil 
     case HCons(head, tail) => head :: tail.asShapeless 
    } 
    } 
} 

Beispiel:

scala>import HListExtensions._ 
import HListExtensions._ 

scala> val x1:HList = 1 :: 2 :: HNil 
x1: slick.collection.heterogeneous.HList = 1 :: 2 :: HNil 

scala> x1.asShapeless 
res1: shapeless.HList = 1 :: 2 :: HNil 

scala> x1.asShapeless.asSlick 
res2: slick.collection.heterogeneous.HList = 1 :: 2 :: HNil 

Ich hoffe, das hilft.

Bearbeiten: Hier ist Typ-Level-Lösung.

object HListsConvertersTypeLevel { 

    import shapeless.{::} 

    sealed trait HConv[From <: heterogeneous.HList, To <: shapeless.HList] { 
    def convert(list: From): To 
    } 

    implicit def buildHConvNil: HConv[heterogeneous.HNil.type, shapeless.HNil] = 
    new HConv[heterogeneous.HNil.type, shapeless.HNil] { 
     override def convert(list: heterogeneous.HNil.type): shapeless.HNil = shapeless.HNil 
    } 

    implicit def buildHConv[H, T <: heterogeneous.HList, T2 <: shapeless.HList](
     implicit conv: HConv[T, T2]): HConv[HCons[H, T], ::[H, T2]] = new HConv[HCons[H, T], ::[H, T2]] { 

    override def convert(list: HCons[H, T]): ::[H, T2] = { 
     list.head :: conv.convert(list.tail) 
    } 
    } 

    def toShapeless[A <: heterogeneous.HList, B <: shapeless.HList](list: A)(implicit conv: HConv[A, B]): B = conv.convert(list) 

} 

Beispiel:

object SlickAndShapeless { 
    import slick.collection.heterogeneous.{HCons, HNil} 
    import slick.collection.heterogeneous.syntax.HNil 

    type MyRow = HCons[Long, HCons[String, HNil]] 
    val row: MyRow = 1L :: "foo" :: HNil 

    import HListsConvertersTypeLevel._ 
    val hlist   = toShapeless(row) 
    val item: Long = hlist.head 
    val item2: String = hlist.tail.head 
} 
+0

Vielen Dank dieses ist groß. Ich habe deine Lösung mit der anderen Verbindung kombiniert. aber ich habe immer noch ein Problem. Ich habe meine Frage oben aktualisiert. –

+0

Das Problem ist, dass auf der formlosen hlist, wenn ich ein 'container.get (1)' tun, der Rückgabetyp vom Typ 'at.Out' ist und nicht Long –

Verwandte Themen