Подтвердить что ты не робот

Использование Slick с бесформенным HList

Поддержка Slick для HList - это, как правило, замечательная вещь. К сожалению, он поставляется с собственной реализацией, которая практически не дает никаких полезных операций. Поэтому я хотел бы использовать бесформенный HList. Предполагается, что это " тривиальный", но я понятия не имею, как это сделать правильно. Поиск в Интернете не нашел доказательств того, что кому-то удалось выполнить эту задачу.

Я предполагаю, что этого достаточно, чтобы реализовать ProvenShape (как объявлено здесь), но поскольку я не понимаю концепцию Slick's (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
}
4b9b3361

Ответ 1

Вы ударяете гвоздь на голову - если вы можете произвести Shapes для HLists, остальная часть инструментов Slick запустит передачу, чтобы получить ProvenShape, который вам нужен для проекции по умолчанию.

Здесь реализована реализация bare-bones, которая позволяет создавать Tables из 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 здесь. В принципе, я думаю, что Generic можно было бы вовлечь в битву для сопоставления классов классов без необходимости <>.