4

I started to use Slick 3.0.0 and I like it's succinct syntax. Nevertheless, I wasn't able to find a way to use it in a database agnostic way.

In the following example provided in the documentation: http://slick.typesafe.com/doc/3.0.0/gettingstarted.html

I'd like to be able to decouple somehow this code of the database used and avoid importing database specific in my code (i.e slick.driver.H2Driver.api._).

I tried to get rid of it by providing the connection using the cake pattern, but the ".result" member isn't available then.

A workaround would be to import slick.driver.JdbcDriver.api._, but it is deprecated and thus should not be a good starting point.

Anyone found a way to use Slick 3.0.0 in a database agnostic and elegant way?

This question isn't far of "How to write database-agnostic Play application and perform first-time database initialization?", but that one focuses on Slick 3.0.0. Sadely the answers provided with that former question aren't targetting Slick 3.0.0 except one which uses deprecated code.

Community
  • 1
  • 1
raphael
  • 93
  • 8
  • If you use basic/standard SQL, I guess you can use native queries in a way it would be easy to switch to another RDBMS (do you really need to?). – cchantep Jun 28 '15 at 23:01
  • Thanks @cchantep, you mean using the plain SQL queries of Slick (http://slick.typesafe.com/doc/3.0.0/sql.html)? About your question, yes I like to switch of RDBMS for some unit tests (where is use h2) and also I'd like to love to be able to change without having to rebuild my app. – raphael Jun 28 '15 at 23:21
  • If that's just for unit testing, you do not really need agnostic calls, but to be able to simulate the same DB behaviour, either with in-memory DB or using JDBC testing framework (like http://acolyte.eu.org ). – cchantep Jun 29 '15 at 00:28
  • This seems to be a duplicate of: http://stackoverflow.com/q/13661339/13822 – triggerNZ Jun 29 '15 at 00:39
  • @cchantep, then you suggest do use the specific driver of my RDBMS (in my case PostgreSQL) over an in-memory DB (i.e. H2) for unit testing? – raphael Jun 29 '15 at 17:54
  • It can be better for unit testing a persistence code. – cchantep Jun 29 '15 at 21:17

1 Answers1

8

The slick driver class you're looking for is slick.driver.JdbcProfile.

There's an official example project slick-multidb which you can obtain through activator (github). Here's the relevant code:

import scala.language.higherKinds
import slick.driver.JdbcProfile

/** All database code goes into the DAO (data access object) class which
  * is parameterized by a Slick driver that implements JdbcProfile.
  */
class DAO(val driver: JdbcProfile) {
  // Import the Scala API from the driver
  import driver.api._

  class Props(tag: Tag) extends Table[(String, String)](tag, "PROPS") {
    def key = column[String]("KEY", O.PrimaryKey)
    def value = column[String]("VALUE")
    def * = (key, value)
  }
  val props = TableQuery[Props]

  /** Create the database schema */
  def create: DBIO[Unit] =
    props.ddl.create

  /** Insert a key/value pair */
  def insert(k: String, v: String): DBIO[Int] =
    props += (k, v)

  /** Get the value for the given key */
  def get(k: String): DBIO[Option[String]] =
    (for(p <- props if p.key === k) yield p.value).result.headOption

  /** Get the first element for a Query from this DAO */
  def getFirst[M, U, C[_]](q: Query[M, U, C]): DBIO[U] =
    q.result.head
}

Client code:

val dao = new DAO(H2Driver)
import dao.driver.api._
db.run(dao.insert("foo", "bar"))
dwickern
  • 3,519
  • 1
  • 14
  • 21
  • 1
    Thanks for that answer! That's perfect! Thanks you! I cannot vote yet for your answer, but I'll asap! – raphael Jul 02 '15 at 12:08
  • Just something weird (that is also in the example of activator), it uses ` props.ddl.create` which is currently deprecated. It seems out that `props.schema.create` does the job. – raphael Jul 02 '15 at 12:18
  • If only this could be driver agnostic + generic in a way so that one could extend the Table-definition and the `TableQuery[T]` where `T <: Props` and still have all the benefits... I could not find a way. –  Sep 14 '16 at 19:33
  • @Sorona I was not aware that you could extend a `Table` definition. However, I think if you solve your problem for a single database driver, you can use this same technique to support multiple database drivers. – dwickern Sep 14 '16 at 20:58