A Quick Overview of Slick 3.0

A Quick Overview of Slick 3.0

A Quick Overview of Slick 3.0

At ScalaC we’ve recently started adopting Slick 3.0. If you haven’t tried it yet, hopefully these notes will make the process go smoother.

Configuration

Let’s start with something simple. While not a revolutionary change, the streamlined approach to configuring the database connection shows effort put into making Slick more pleasant to work with. The configuration can be specified entirely using Typesafe Config. An example application.conf can look like this:

https://gist.github.com/pjazdzewski1990/97313151f4e719bc33a0

The whole list of configuration options is available in the API docs.

Now all we need is to choose the appropriate config entry:

https://gist.github.com/pjazdzewski1990/3c9975db6fc1a00e04ed

It could be even simpler if we decided a priori on what database engine to choose. Here we are making our application compatible with any database that matches the JdbcProfile. More elaborate multi-DB patterns can be found in this Activator template

Another feature to note here is that Slick now by default uses HikariCP for connection pooling (it still needs to provided as a build dependency). You can configure it to your needs, choose to disable it, or provide a third-party connection pool implementation, all via Typesafe Config.

Actions

Slick 3.0 has been dubbed “reactive” and as you might expect that means querying is now asynchronous. Thus all interactions with a database return futures instead of plain result types. However there’s also an intermediate type DBIOAction which is a monad-like trait wrapping the result. In code they are usually referred by the type alias DBIO and can be processed via the usual combinators like mapflatMapandThen. Let’s look at an example:

https://gist.github.com/pjazdzewski1990/d94e0fe55f364292075f

The query API remains mostly the same as in Slick 2.1 (there are some differences with regard to types and improved support for Option and outer joins, but in the usual way of working with Slick they might go unnoticed). When we’re done composing the query we call the implicit .result on it which transforms it into a DBIOAction.

The action represents the communication with the database, but that will not happen until the it is scheduled for execution with db.run() which will return a Future actual with the actual data (db is the object we created from configuration in the previous paragraph).

Queries that perform mutation (updates, inserts, deletes) are already actions – there’s no need to transform them. Actions can be composed together to be run in a single session. The individual actions forming the composite will be executed sequentially, like in the example below:

https://gist.github.com/pjazdzewski1990/537835c0e6d73f3620c8

As you can see several actions are executed in one go. createIfNotExists is composed via map and flatMap transformations and the rest are linked together by >> (which is a shortcut for DBIOAction#andThen)

Transactions

Having such actions chained together it should be easy to run them within a single DB transaction, and in fact it is. Consider this example:

https://gist.github.com/pjazdzewski1990/b9175393d85a22d90551

All you need to do now is to run this action .transactionally:

https://gist.github.com/pjazdzewski1990/e40e453d65102275e14d

Plain SQL

One last thing to note about actions is that SQL interpolation using sqlu"..."and sql"...".as[T] also returns actions and running them is not different from other examples:

https://gist.github.com/pjazdzewski1990/79cb959e78c75ef67697

Reactive Streams

Slick 3.0 also supports the Reactive Streams API. Any action that returns a collection can be converted to a DatabasePublisher (which implements org.reactivestreams.Publisher). Such Publisher can for example be used to construct a Flow with Akka Streams:

https://gist.github.com/pjazdzewski1990/f0e6946145c3ae42406f

As I’m not going to cover Reactive Streams or Akka Streams here, that’s pretty much all there is to it :)

Type-checked SQL

Another interesting feature introduced in Slick 3.0 is its ability to type check hand-written SQL statements. Here’s how:

https://gist.github.com/pjazdzewski1990/a119876c9873e8d9ab56

Things to note here are the use of tsql interpolator and StaticDatabaseConfig annotation which points the configuration file and the path in that configuration which defines the database used during compilation. Thanks to macro-magic Slick connect to this database to examine correctness of the queries with regard to syntax as well as types.

Hence an additional bonus that we don’t need to write .as[String] here (as with the regular sql interpolator), the proper types are inferred by Slick (your IDE might not be so kind).

Now, don’t lose your head (as I nearly did) if doesn’t work for you. There’s either a bug or an omission in the documentation in that in order for the macro to work it is required to have an slf4j implementation provided as a dependency, and if using logback, it has to be defined in runtime scope (I learned this from this blog post and there’s also an issue reported):

https://gist.github.com/pjazdzewski1990/861383c24274b78065da

So let’s try to break some things to see how it performs:

Bad syntax:

https://gist.github.com/pjazdzewski1990/4440546ca954a4ad877c

https://gist.github.com/pjazdzewski1990/e50f1d6aec12a6836170

Incorrect type:

https://gist.github.com/pjazdzewski1990/6937ddf701f28d6a74fb

https://gist.github.com/pjazdzewski1990/ece36869c05eb191741c

Quite neat. However, I don’t see myself using this feature anytime soon. Making compilation dependent on a running DB instance and limited IDE support are blockers to me. Also it might hard to get this right if queries create or modify the schema. If you have a different opinion on this I’d very much welcome it in a comment.

Conclusions

That’s all the major changes I wanted to present in this post. I think we can agree that Slick is heading the right direction, not only in following the reactive trend, but also in making the API more expresive and consistent that consequently makes our code look better (it even shows in the imports).

There are of course things to look forward to in subsequent releases. The DSL still has its limitations and generated SQL is far from perfect (see my previous post which is still valid for the latest release). According to Stefan Zeiger query compilation will be improved in Slick 3.1 (see here)

Anyway, at ScalaC, we have already been using Slick 3.0 in some of our projects, and so far no major complaints. Since the query DSL hasn’t changed noticeably the transition is rather easy (that doesn’t necessarily mean migration) which is another reason I definitely recommend it for your next project.

You can check out the code used in this post from our repo.

Do you like this post? Want to stay updated? Follow us on Twitter or subscribe to our Feed.

Read more

Download e-book:

Scalac Case Study Book

Download now

Authors

Radek Tkaczyk

I am a quality-oriented hacker, developing in Scala since 2013

Latest Blogposts

29.04.2024 / By  Matylda Kamińska

Scalendar May 2024

scalendar may 2024

Event-driven Newsletter Welcome to our May 2024 edition of Scalendar! As we move into a bustling spring, this issue brings you a compilation of the most anticipated frontend and software architecture events around the globe. With a particular focus on Scala conferences in May 2024, our newsletter serves as your guide to keep you updated […]

23.04.2024 / By  Bartosz Budnik

Kalix tutorial: Building invoice application

Kalix app building.

Scala is well-known for its great functional scala libraries which enable the building of complex applications designed for streaming data or providing reliable solutions with effect systems. However, there are not that many solutions which we could call frameworks to provide every necessary tool and out-of-the box integrations with databases, message brokers, etc. In 2022, Kalix was […]

17.04.2024 / By  Michał Szajkowski

Mocking Libraries can be your doom

Test Automations

Test automation is great. Nowadays, it’s become a crucial part of basically any software development process. And at the unit test level it is often a necessity to mimic a foreign service or other dependencies you want to isolate from. So in such a case, using a mock library should be an obvious choice that […]

software product development

Need a successful project?

Estimate project