Search code examples
databasescalah2slick

Setting up Slick 3.xx to use different databases in different environments


I've been running Slick against our Oracle database for a while. Now I'd like to also use it against H2, in our integration tests. I imagined this to be only about changing the drivers being loaded, but now I realized all my repositories are riddled with a import slick.jdbc.OracleProfile.api._, which makes me think my repositories are at this moment tied to OracleSQL.

What would the standard procedure be to have Slick support loading either Oracle or H2 drivers based on different configuration files?


Solution

  • You'll need to abstract the Slick profile via JdbcProfile. That will get rid of the Oracle-specific parts you've identified as the problem.

    It sounds like you have a reasonably large application. In that case, it's common (in my experience) to make the Slick profile a parameter to a class or trait, and then pass in the specific profile when you know what it is.

    For example (using the sample code in Essential Slick) we can say that our application profile must have a JdbcProfile:

    import slick.jdbc.JdbcProfile
    
    trait Profile {
      val profile: JdbcProfile
    }
    

    Then, for each module of the database code, we import the profile API:

    trait DatabaseModule1 { self: Profile =>
      import profile.api._
    
      // Write database code here
    }
    

    Notice how the abstract profile.api._ import replaces a database specific slick.jdbc.OracleProfile.api._

    If you have many modules you can combine them all together into a case class:

    class DatabaseLayer(val profile: JdbcProfile) extends
      Profile with
      DatabaseModule1 with
      DatabaseModule2
    

    And finally, at the edge of your program you can decide what configuration to use:

    object Main extends App {
    
      // At this point, you can make a test and decide which specific
      // database you want to use. Here I'm saying it's always H2:
      val databaseLayer = new DatabaseLayer(slick.jdbc.H2Profile)
    
      // You can now use methods in `databaseLayer`, 
      // or pass it to other modules in your system
    }
    

    This is described further in: