Skip to content

Instantly share code, notes, and snippets.

@blast-hardcheese
Created October 16, 2015 08:10
Show Gist options
  • Save blast-hardcheese/779bb962cda1a27b8ad8 to your computer and use it in GitHub Desktop.
Save blast-hardcheese/779bb962cda1a27b8ad8 to your computer and use it in GitHub Desktop.
import shapeless._
import shapeless.labelled.KeyTag
import shapeless.record._
import shapeless.ops.hlist.ToList
import shapeless.ops.record.{ Keys, Values }
import shapeless.syntax.singleton._
import utils.ExtendedPostgresDriver.simple._
object slickless {
import scala.annotation.tailrec
import scala.reflect.ClassTag
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)
}
trait HListShapeImplicits {
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)
}
object SlicklessImplicits extends HListShapeImplicits
}
import slickless.SlicklessImplicits._
object Dynamic {
type BookTuple = (Long, String, String, Double)
type BookType = ::[Long, ::[String, ::[String, ::[Double, HNil]]]]
val _bookBuilder = implicitly[Generic.Aux[BookTuple, BookType]]
def apply(id: Long, author: String, title: String, price: Double): BookType = _bookBuilder.to(id, author, title, price)
def unapply(book: BookType): Option[BookTuple] = Some(_bookBuilder.from(book))
}
object Explicit {
type BookTuple = (Long, String, String, Double)
type BookType = Record.`"id" -> Long, "author" -> String, "title" -> String, "price" -> Double`.T
def apply(id: Long, author: String, title: String, price: Double): BookType = {
("id" ->> id) ::
("author" ->> author) ::
("title" ->> title) ::
("price" ->> price) ::
HNil
}
val tupled: BookTuple => BookType = (apply _).tupled
def unapply(book: BookType): Option[BookTuple] = {
val id :: author :: title :: price :: HNil = book
Some((id, author, title, price))
}
class Books(tag: Tag) extends Table[Long :: String :: String :: Double :: HNil](tag, "book") {
def id = column[Long ]("id", O.PrimaryKey, O.AutoInc)
def author = column[String]("author", O.NotNull)
def title = column[String]("title", O.NotNull)
def price = column[Double]("price", O.NotNull)
def * = ("id" ->> id) :: ("author" ->> author) :: ("title" ->> title) :: ("price" ->> price) :: HNil
}
val books = TableQuery[Books]
}
scala> val fromdb = DB.withSession { implicit s => Explicit.books.filter(_.id === 1L).run }
fromdb: Seq[Explicit.Books#TableElementType] = Vector(1 :: Devon Stewart :: Doing stuff :: 13.37 :: HNil)
scala> fromdb.head
res2: Explicit.Books#TableElementType = 1 :: Devon Stewart :: Doing stuff :: 13.37 :: HNil
scala> fromdb.head("author")
<console>:47: error: No field String("author") in record shapeless.::[Long,shapeless.::[String,shapeless.::[String,shapeless.::[Double,shapeless.HNil]]]]
fromdb.head("author")
^
scala> val a = fromdb.head
a: Explicit.Books#TableElementType = 1 :: Devon Stewart :: Doing stuff :: 13.37 :: HNil
scala> a: Explicit.BookType
<console>:48: error: type mismatch;
found : Explicit.Books#TableElementType
(which expands to) shapeless.::[Long,shapeless.::[String,shapeless.::[String,shapeless.::[Double,shapeless.HNil]]]]
required: Explicit.BookType
(which expands to) shapeless.::[Long with shapeless.labelled.KeyTag[String("id"),Long],shapeless.::[String with shapeless.labelled.KeyTag[String("author"),String],shapeless.::[String with shapeless.labelled.KeyTag[String("title"),String],shapeless.::[Double with shapeless.labelled.KeyTag[String("price"),Double],shapeless.HNil]]]]
a: Explicit.BookType
^
scala> a.asInstanceOf[Explicit.BookType]
res5: Explicit.BookType = 1 :: Devon Stewart :: Doing stuff :: 13.37 :: HNil
scala> res5("author")
res6: String = Devon Stewart
scala> res5("bogus")
<console>:49: error: No field String("bogus") in record shapeless.::[Long with shapeless.labelled.KeyTag[String("id"),Long],shapeless.::[String with shapeless.labelled.KeyTag[String("author"),String],shapeless.::[String with shapeless.labelled.KeyTag[String("title"),String],shapeless.::[Double with shapeless.labelled.KeyTag[String("price"),Double],shapeless.HNil]]]]
res5("bogus")
^
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment