2017-09-15 10 views
1

私は滑らかなcodegenを使って自動生成されたスカラコードを持っています。私はいくつかのテーブルがあることを見ている行はHListとして実装されています。 (しかし、これは滑らかなHListであり、通常の無形HListではありません)Slick HLISTから要素を取得する(またはSlick HLIstをシェープレスHListに変換する)

今、私は滑らかなクエリによって行として返されるHListの特定の要素を必要とします。

私はGoogleで検索して、このスレッド

Getting elements from an HList

しかし、これは滑らかなHListでは動作しません発見しました。それは私もこの方法を適用しようとした型崩れHList

のために非常によく動作し

ヴァルX:ロング= slickHList(2)

が、どのタイプがのexectedタイプに準拠していないので、これはコンパイルされません。長いです。私は嫌いでしょう.asInstanceOf

私は滑らかなHListの要素にアクセスすることができるタイプセーフな方法はありますか?

編集:私は上記のコードの問題は、私が期待していたとしてval item = container.get(1)から得itemの種類はat.OutなくLongということである

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

下のコードを書いた下に入力に基づい。

build.sbt

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

また、私はそれが拡張メソッドを作成することが可能です2つのコンパイルエラー

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) 

答えて

3

を参照してください。

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

例:

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 

こちらがお役に立てば幸いです。

編集:ここにタイプレベルの解決策があります。

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) 

} 

例:

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

が、これは素晴らしいです、ありがとうございました。あなたのソリューションを他のリンクと組み合わせました。私はまだ問題があります。私は上記の質問を更新しました。 –

+0

問題は、シェイプレスなhlistでは、 'container.get(1)'を実行すると、戻り値の型が 'at.Out'でLongではなく –

関連する問題