Environment-dependent database drivers with Slick

When we started to you use Slick for the first time, we had no clue on how to set up our code for multiple database types in our Play! application. In the development phase, our main goal was to run the application quickly with no interference with other developers’ code and development velocity, so we decided to use the in-memory database. We are dedicated towards Continuous Integration, so before every merge we run all the tests to check if the new code breaks the app. The QA environment should have the same properties as the production and we were aiming for the Azure SQL database. These two database types (in-memory and Azure SQL) use different drivers to operate. To keep our code consistent we only change the application.conf via CI Tools while we switch between stages of development.

We use Play’s default DB for establishing the connection to the database. In the DAO – data access object – classes, you have to import a specific driver to operate well. When you import multiple drivers, like import com.typesafe.slick.driver.ms.SQLServerDriver.api._ and import slick.driver.H2Driver.api._ , the DAO will only use one of those. This is really problematic, because those two objects contain the exact same methods with different implementation.

We needed to map the stages of development to the type of databases we were using.

Enviroment dependent database drivers with Slick

 

Solution A – Mapping with application.conf on ‘default’ database

Have the development stage in a configuration file so you can easily change it, but the development stage value should always be synchronized with your database config.

Now that we have the stages and the databases, the mapping is easy:

Using it is quite easy:

 

Solution B – Using Database config

Instead of using the default value for database config, you can easily create configs for each environment (dev, test, qa, prod) that also represent the required database driver. In this case, you don’t need separate configuration files, you can put all in one. So the previous example would look more like:

The mapping is still necessary. So our previous MultiDatabase trait would look like the following code, but you can use it the same way:

Putting all the database configs in one file may be cause for concern. You can accidentally run your app in prod mode while your development stage should be ‘in development’. Deploying app on-premise to your customer can cause security issues as well, for example by providing information about your infrastructure, but deploying the app to Azure can solve this problem.

 

Further Opportunities

While you are using the mapping, you can add extra features to your ‘profile’ like using the specific JodaTime for your database.

 

Summary

You need to map your Driver to your development stage no matter what. You can mix the solutions and change them according to your architecture. You can use them with the cake pattern, dependency injection and passing your JdbcProfile as a class member.

I hope you’ve found this article useful and feel free to contact me if you have any questions.

 

P.S.: Scala is awesome. But you should know that already. (wink)

Barnabás Oláh

Barnabás Oláh

Full-stack Developer at Wanari Ltd.
Never underestimate the capabilities of a lazy person.

  • Enpassant

    I thought you might be interested in this: Scala as a configuration language

    • Barnabás Oláh

      Thanks for pointing it out, looking into it. Btw this article kinda out dated we have better solutions. Will post about it 🙂