nt, Option[Double])) * - Unpacked: (Int, (Int, String), (Int, Option[Double])) * - Packed: (Column[Int], Column[(Int, String)], (Column[Int], Column[Option[Double]])) * - Linearized: (Int, Int, String, Int, Option[Double]) */
abstract class Shape[Level <: ShapeLevel, -Mixed, Unpacked_, Packed_] {...}
上面的Mixed就是ProvenShape的T,Unpacked就是U。如此看来T代表Query[T]的T,而U就是返回结果类型了。如果我们能提供T的Shape隐式实例就能把U升格成ProvenShape[U]。我们来看看Slick官方文件上的例子:
import scala.reflect.ClassTag // A custom record class
case class Pair[A, B](a: A, b: B) // A Shape implementation for Pair
final class PairShape[Level <: ShapeLevel, M <: Pair[_,_], U <: Pair[_,_] : ClassTag, P <: Pair[_,_]]( val shapes: Seq[Shape[_, _, _, _]]) extends MappedScalaProductShape[Level, Pair[_,_], M, U, P] { def buildValue(elems: IndexedSeq[Any]) = Pair(elems(0), elems(1)) def copy(shapes: Seq[Shape[_ <: ShapeLevel, _, _, _]]) = new PairShape(shapes) } implicit def pairShape[Level <: ShapeLevel, M1, M2, U1, U2, P1, P2]( implicit s1: Shape[_ <: Level, M1, U1, P1], s2: Shape[_ <: Level, M2, U2, P2] ) = new PairShape[Level, Pair[M1, M2], Pair[U1, U2], Pair[P1, P2]](Seq(s1, s2)) // Use it in a table definition
class A(tag: Tag) extends Table[Pair[Int, String]](tag, "shape_a") { def id = column[Int]("id", O.PrimaryKey) def s = column[String]("s") def * = Pair(id, s) } val as = TableQuery[A]
现在Projection可以写成Pair(id,s)。也就是说因为有了implicit def pairShape[...](...):PairShape所以Pair(id,s)被升格成ProvenShape[Pair]。这样Query的返回类型就是Seq[Pair]了。实际上Slick本身提供了Tuple、Case Class、HList等类型的默认Shape隐式实例,所以我们可以把Projection直接写成 def * = (...) 或 Person(...) 或 Int::String::HNil。下面是Tuple的默认Shape:
trait TupleShapeImplicits { @inline implicit final def tuple1Shape[Level <: ShapeLevel, M1, U1, P1](implicit u1: Shape[_ <: Level, M1, U1, P1]): Shape[Level, Tuple1[M1], Tuple1[U1], Tuple1[P1]] =
new TupleShape[Level, Tuple1[M1], Tuple1[U1], Tuple1[P1]](u1) @inline implicit final def tuple2Shape[Level <: ShapeLevel, M1,M2, U1,U2, P1,P2](implicit u1: Shape[_ <: Level, M1, U1, P1], u2: Shape[_ <: Level, M2, U2, P2]): Shape[Level, (M1,M2), (U1,U2), (P1,P2)] =
new TupleShape[Level, (M1,M2), (U1,U2), (P1,P2)](u1,u2) ...
回到主题,下面是一个典型的Slick数据库表读取例子:
1 class TupleTypedPerson(tag: Tag) extends Table[( 2 Option[Int],String,Int,Option[String])](tag,"PERSON") { 3 def id = column[Int]("id",O.PrimaryKey,O.AutoInc) 4 def name = column[String]("name") 5 def age = column[Int]("age") 6 def alias = column[Option[String]]("alias") 7 def * = (id.?,name,age,alias) 8 } 9 val tupleTypedPerson = TableQuery[TupleTypedPerson] 10
11 val db = Database.forURL("jdbc:h2:mem:test1;DB_CLOSE_DELAY=-1", driver = "org.h2.Driver") 12 val createSchemaAction = tupleTypedPerson.schema.create 13 Await.ready(db.run(createSchemaAction),Duration.Inf) 14 val initDataAction = DBIO.seq { 15 tupleTypedPerson ++= Seq( 16 (Some(0),"Tiger Chan", 45, Some("Tiger_XC")), 17 (Some(0),"Johnny Cox", 17, None), 18 (Some(0),"Cathy Williams", 18, Some("Catty")), 19 (Some(0),"David Wong", 43, None) 20 ) 21 } 22 Await.ready(db.run(initDataAction),Duration.Inf) 23 val queryAction = tupleTypedPerson.result 24
25 Await.result(db.run(queryAction),Duration. |