Utilizing Scala Cats to improve database access code

senjinhajrulahovic

Senjin Hajrulahovic

Posted on March 23, 2022

Utilizing Scala Cats to improve database access code

Let start with something familiar. If you worked with scala for some time you most likely came across scala.concurrent.Future#sequence and scala.concurrent.Future#traverse.

Here is a simplified method signature of these two methods:

def traverse[A, B](items: Seq[A])(f: A => Future[B]): Future[Seq[B]]
def sequence[A](items: Seq[Future[A]]): Future[Seq[A]]
Enter fullscreen mode Exit fullscreen mode

cats.Traverse is an abstraction which embodies the operation scala.concurrent.Future#traverse but is more general. Since in addition to the function argument type A and return type B, the context type of both Seq and Future further generalized:

trait Traverse[F[_]] {
  def traverse[G[_], A, B](fa: F[A])(f: A => G[B]): G[F[B]]
}
Enter fullscreen mode Exit fullscreen mode

If you're using a newer version of slick for database access you're most likely familiar with DBIO. There are often cases when you have a collection of some sort and want to execute a database action for each of the elements in the collection.
Since DBIO is somewhat similar to Future we could write:

def f[A](a:A): DBIO[B] = ???

val b: DBIO[Seq[B]] = DBIO.sequence(items.map(f))
Enter fullscreen mode Exit fullscreen mode

or if we lack documentation awareness we could event end up writing:

items.foldLeft(DBIO.successful(Seq()) {
  (acc, next) => acc.flatMap(a => f(next).map(i => acc :+ i)
}
Enter fullscreen mode Exit fullscreen mode

But if we utilize slickcats we can simply write:

items.traverse(f)
Enter fullscreen mode Exit fullscreen mode

But if you try to use this approach without the proper dependencies you'll see that the compilers complains about missing implicit instances for DBIO.

In order to fix that you have to add following dependency:
https://github.com/RMSone/slick-cats
and add following import to your class:

import com.rms.miu.slickcats.DBIOInstances._
Enter fullscreen mode Exit fullscreen mode

Depending on how far you are in you functional programming journey you'll know that cats.Traverse is a special kind of functor which requires a type constructor with a single type argument.

If the methods you want to use together with slickcats return DBIOAction[+R, +S <: NoStream, -E <: Effect] or some other related type which has more than one type parameter the compiler will complain. In these situation you'll have to help the compiler a bit by either changing the method signature to DBIO or you'll have to cast it to DBIO explicitly.

This is just an example. slickcats has typeclass instances which can help you to write more readable database access code.

💖 💪 🙅 🚩
senjinhajrulahovic
Senjin Hajrulahovic

Posted on March 23, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related