I did the following to create a dynamic select list (using 2.1M2 with the hello-slick activator template). It *seems* to
work fine (but it is quite untested except for this code). What do you think?
import scala.slick.driver.H2Driver.simple._
import scala.slick.lifted.{FlatShapeLevel, Shape, ProductNodeShape}
class ListShape[Level <: ShapeLevel, M <: IndexedSeq[Any], U <: IndexedSeq[Any], P <: IndexedSeq[Any]](val shapes: Seq[Shape[_, _, _, _]]) extends ProductNodeShape[Level, IndexedSeq[Any], M, U, P] {
override def getIterator(value: IndexedSeq[Any]) = value.iterator
def getElement(value: IndexedSeq[Any], idx: Int) = value(idx)
def buildValue(elems: IndexedSeq[Any]) = elems
def copy(shapes: Seq[Shape[_ <: ShapeLevel, _, _, _]]) = new ListShape(shapes)
}
object ListShape {
def apply(numColumns: Int) : Shape[FlatShapeLevel, IndexedSeq[Any], IndexedSeq[Any], IndexedSeq[Any]] = {
val columnShapes = (0 until numColumns).map(_ => Shape.columnShape[Any, FlatShapeLevel])
new ListShape(columnShapes.toVector)
}
}
object CaseClassMapping extends App {
// the base query for the Users table
val users = TableQuery[Users]
val db = Database.forURL("jdbc:h2:mem:hello", driver = "org.h2.Driver")
db.withSession { implicit session =>
// create the schema
users.ddl.create
// insert two User instances
users += User("John Doe", Some("Dorpstreet"), Some(13))
users += User("Fred Smith", Some("42 Elmstreet"), None)
val columns = Vector(("NAME", "string"), ("ID", "int"), ("ADDRESS", "string?"), ("HOUSENO", "int?"))
implicit val shape = ListShape(columns.size)
val q = users.filter(t =>
t.id >= 1.bind).map { u =>
columns.map( c => {
c._2 match {
case "string" => u.column[String](c._1)
case "string?" => u.column[Option[String]](c._1)
case "int" => u.column[Int](c._1)
case "int?" => u.column[Option[Int]](c._1)
case _ => throw new RuntimeException("Unsupported column type")
}
})
}
println(q.selectStatement)
val list = q.list.asInstanceOf[List[Product]].map(_.productIterator.toList)
println(list)
}
}
case class User(name: String, address: Option[String], houseno: Option[Int], id: Option[Int] = None)
class Users(tag: Tag) extends Table[User](tag, "USERS") {
// Auto Increment the id primary key column
def id = column[Int]("ID", O.PrimaryKey, O.AutoInc)
// The name can't be null
def name = column[String]("NAME", O.NotNull)
def address = column[Option[String]]("ADDRESS")
def houseno = column[Option[Int]]("HOUSENO")
// the * projection (e.g. select * ...) auto-transforms the tupled
// column values to / from a User
def * = (name, address, houseno, id.?) <> (User.tupled, User.unapply)
}