I have a Slick 3.0 table definition similar to the following:
case class Simple(a: String, b: Int, c: Option[String])
trait Tables { this: JdbcDriver =>
import api._
class Simples(tag: Tag) extends Table[Simple](tag, "simples") {
def a = column[String]("a")
def b = column[Int]("b")
def c = column[Option[String]]("c")
def * = (a, b, c) <> (Simple.tupled, Simple.unapply)
}
lazy val simples = TableQuery[Simples]
}
object DB extends Tables with MyJdbcDriver
I would like to be able to do 2 things:
Seq[String]
Simple
, generate a Seq[String]
that would correspond to how the data would be inserted into the database using a raw query (e.g. Simple("hello", 1, None)
becomes Seq("'hello'", "1", "NULL")
)What would be the best way to do this using the Slick table definition?
<>
operator in the *
method without changing the order of values in Simple
, the row type of Simples
, i.e. what Ben assumed is not possible. The ProvenShape
return type of the *
projection method ensures that there is a Shape
available for translating between the Column
-based type in * and the client-side type and if you write def * = (c, b, a) <> Simple.tupled, Simple.unapply)
having Simple defined as case class Simple(a: String, b: Int, c: Option[String])
, Slick will complain with an error "No matching Shape found. Slick does not know how to map the given types...". Ergo, you can iterate over all the elements of an instance of Simple with its productIterator
.Simples
table in your code and querying metatables to get the same information you already have is not sensible. You can get all you column names with a one-liner simples.baseTableRow.create_*.map(_.name)
. Note that the *
projection of the table also defines the columns generated when you create the table schema. So the columns not mentioned in the projection are not created and the statement above is guaranteed to return exactly what you need and not to drop anything.To recap briefly:
Seq[String]
use
simples.baseTableRow.create_*.map(_.name).toSeq
Seq[String]
that would correspond to how the data
would be inserted into the database using a raw query for aSimple
,
an instance of Simple
use aSimple.productIterator.toSeq
To get the column names, try this:
db.run(for {
metaTables <- slick.jdbc.meta.MTable.getTables("simples")
columns <- metaTables.head.getColumns
} yield columns.map {_.name}) foreach println
This will print
Vector(a, b, c)
And for the case class values, you can use productIterator:
Simple("hello", 1, None).productIterator.toVector
is
Vector(hello, 1, None)
You still have to do the value mapping, and guarantee that the order of the columns in the table and the values in the case class are the same.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With