将 Slick 与无形 HList 一起使用
Using Slick with shapeless HList
Slick 的 对 HList
的支持通常是一件很棒的事情。不幸的是,它有自己的实现,几乎不提供任何有用的操作。因此,我想改用 shapeless HList
。这应该是“trivial”,但我不知道如何做到这一点。在网上搜索时,我没有发现有人成功完成此任务的证据。
我认为实现 ProvenShape
(如所宣传的 here)就足够了,但由于我无法理解 Slick 的 (Proven)Shape
s,我没能实现这个。
我基本上是为了煮这个
class Users( tag: Tag )
extends Table[Long :: String :: HNil]( tag, "users" )
{
def id = column[Long]( "id", O.PrimaryKey, O.AutoInc )
def email = column[String]( "email" )
override def * = ( id, email ) <>[TableElementType, ( Long, String )](
_.productElements,
hlist => Some( hlist.tupled )
)
}
降至
class Users( tag: Tag )
extends Table[Long :: String :: HNil]( tag, "users" )
{
def id = column[Long]( "id", O.PrimaryKey, O.AutoInc )
def email = column[String]( "email" )
override def * = id :: email :: HNil
}
您一语中的 - 如果您可以为 HLists
生产 Shapes
,Slick 的其余机器将启动以生产您需要的 ProvenShape
默认投影。
这是一个简单的实现,允许您创建 Tables
of HLists
:
import scala.annotation.tailrec
import scala.reflect.ClassTag
import shapeless.{ HList, ::, HNil }
import slick.lifted.{ Shape, ShapeLevel, MappedProductShape }
final class HListShape[L <: ShapeLevel, M <: HList, U <: HList : ClassTag, P <: HList]
(val shapes: Seq[Shape[_, _, _, _]]) extends MappedProductShape[L, HList, M, U, P] {
def buildValue(elems: IndexedSeq[Any]) =
elems.foldRight(HNil: HList)(_ :: _)
def copy(shapes: Seq[Shape[_ <: ShapeLevel, _, _, _]]) =
new HListShape(shapes)
def classTag: ClassTag[U] = implicitly
def runtimeList(value: HList): List[Any] = {
@tailrec def loop(value: HList, acc: List[Any] = Nil): List[Any] = value match {
case HNil => acc
case hd :: tl => loop(tl, hd :: acc)
}
loop(value).reverse
}
override def getIterator(value: HList): Iterator[Any] =
runtimeList(value).iterator
def getElement(value: HList, idx: Int): Any =
runtimeList(value)(idx)
}
object HListShape {
implicit def hnilShape[L <: ShapeLevel]: HListShape[L, HNil, HNil, HNil] =
new HListShape[L, HNil, HNil, HNil](Nil)
implicit def hconsShape[L <: ShapeLevel, M1, M2 <: HList, U1, U2 <: HList, P1, P2 <: HList]
(implicit s1: Shape[_ <: ShapeLevel, M1, U1, P1], s2: HListShape[_ <: ShapeLevel, M2, U2, P2]):
HListShape[L, M1 :: M2, U1 :: U2, P1 :: P2] =
new HListShape[L, M1 :: M2, U1 :: U2, P1 :: P2](s1 +: s2.shapes)
}
我已经在 Github here 上进行了实施。原则上我认为 Generic
可以加入到映射案例 类 中而不需要 <>
.
Slick 的 对 HList
的支持通常是一件很棒的事情。不幸的是,它有自己的实现,几乎不提供任何有用的操作。因此,我想改用 shapeless HList
。这应该是“trivial”,但我不知道如何做到这一点。在网上搜索时,我没有发现有人成功完成此任务的证据。
我认为实现 ProvenShape
(如所宣传的 here)就足够了,但由于我无法理解 Slick 的 (Proven)Shape
s,我没能实现这个。
我基本上是为了煮这个
class Users( tag: Tag )
extends Table[Long :: String :: HNil]( tag, "users" )
{
def id = column[Long]( "id", O.PrimaryKey, O.AutoInc )
def email = column[String]( "email" )
override def * = ( id, email ) <>[TableElementType, ( Long, String )](
_.productElements,
hlist => Some( hlist.tupled )
)
}
降至
class Users( tag: Tag )
extends Table[Long :: String :: HNil]( tag, "users" )
{
def id = column[Long]( "id", O.PrimaryKey, O.AutoInc )
def email = column[String]( "email" )
override def * = id :: email :: HNil
}
您一语中的 - 如果您可以为 HLists
生产 Shapes
,Slick 的其余机器将启动以生产您需要的 ProvenShape
默认投影。
这是一个简单的实现,允许您创建 Tables
of HLists
:
import scala.annotation.tailrec
import scala.reflect.ClassTag
import shapeless.{ HList, ::, HNil }
import slick.lifted.{ Shape, ShapeLevel, MappedProductShape }
final class HListShape[L <: ShapeLevel, M <: HList, U <: HList : ClassTag, P <: HList]
(val shapes: Seq[Shape[_, _, _, _]]) extends MappedProductShape[L, HList, M, U, P] {
def buildValue(elems: IndexedSeq[Any]) =
elems.foldRight(HNil: HList)(_ :: _)
def copy(shapes: Seq[Shape[_ <: ShapeLevel, _, _, _]]) =
new HListShape(shapes)
def classTag: ClassTag[U] = implicitly
def runtimeList(value: HList): List[Any] = {
@tailrec def loop(value: HList, acc: List[Any] = Nil): List[Any] = value match {
case HNil => acc
case hd :: tl => loop(tl, hd :: acc)
}
loop(value).reverse
}
override def getIterator(value: HList): Iterator[Any] =
runtimeList(value).iterator
def getElement(value: HList, idx: Int): Any =
runtimeList(value)(idx)
}
object HListShape {
implicit def hnilShape[L <: ShapeLevel]: HListShape[L, HNil, HNil, HNil] =
new HListShape[L, HNil, HNil, HNil](Nil)
implicit def hconsShape[L <: ShapeLevel, M1, M2 <: HList, U1, U2 <: HList, P1, P2 <: HList]
(implicit s1: Shape[_ <: ShapeLevel, M1, U1, P1], s2: HListShape[_ <: ShapeLevel, M2, U2, P2]):
HListShape[L, M1 :: M2, U1 :: U2, P1 :: P2] =
new HListShape[L, M1 :: M2, U1 :: U2, P1 :: P2](s1 +: s2.shapes)
}
我已经在 Github here 上进行了实施。原则上我认为 Generic
可以加入到映射案例 类 中而不需要 <>
.