Hacking with doobie and monix
Lambda Ops
Background
In my previous post I have discussed about integrating doobie
and cats-effects
IO monad in Scala applications. In this post I’m gonna discuss about using doobie with Scala Monix
library. All the source codes which related to this post available in gitlab. Please clone the repo and continue the post.
About Monix
Monix is a high-performance Scala library for composing asynchronous, event-based programs. Monix library comes with Monix Task
which represents a specification for lazy or asynchronous computation. Monix Task is similar to cats.effect.IO
. Both of them can use as an alternative for Scala futures
. Scala futures comes with several limitations such as referential transparency
, memoization
, usage of execution context
etc. Read more about these limitations from here. We can use Monix Task as an alternative for Scala futures and get rid of these limitations. Following is the way to use Monix Task in Scala application. It shows the various blocking/non blocking operations that can be peforamned with Monix Task. Unlike Scala futures we don’t need to have ExecutionContext
every where. The ExecutionContext
has been replaced with a Monix global Scheduler
. The Monix Task are not started when they created, so no Scheduler
is needed before we run the task.
In this post I’m gonna use Monix Task with doobie to perform database operations in Scala application. Following are the main steps that I have followed.
Configure database
First I need to run mysql and create a database. Following is the way to do that. I’m running mysql with docker
.
Sbt dependency
Following is the build.sbt
dependency file with doobie, monix and other libraries which I have used in my sbt
application.
DB connection
To connect to the database, I need to create an instance of a Transactor
. A Transactor
knows how to connect to the database, hand out connections and knows how to turn the query
program into an asynchronous effect. doobie query
does not contain any answers from the database, it's a description of a program that needs to be run to obtain these answers. Transactor give a way to run the queries and obtain the answers.
Transactor can be constructed by providing configuration such as database connection string, username, password. In here I’m using HikariTransactor
which built based on HikariCP
database connection pooling library. HikariTransactor wraps with Monix Task. Monix Task is the asynchronous operation that executes the database query(side effect operation). Instead of Monix Task we can use cats.effects.IO
, ZIO
kind of libraries as well.
Queries
doobie queries are written directly in SQL, that’s exactly what’s sent to the database. Following are the queries I have used. As you can see queries are are created with the sql
string interpolator. Complex queries can be made with doobie fragments
.
Execute queries
I can run the queries using .transact(xa)
. To unwrap and run the side-effecting code in the Monix Task I need to invoke runSyncUnsafe()
. runSyncUnsafe()
is a blocking call, we can unwrap and run the task with non blocking call by using runToFuture()
. runToFuture()
will returns a CancelableFuture
. Following are the different queries that I have run and their outputs.
Query type checking
doobie doesn’t provide compile time type checking of the queries(they just map some fields from a SQL query to a case class). But doobie provides a way to type checking the queries during unit testing. When something is wrong with the query, doobie provides extensive feedback on what is going wrong. Following are the type checking tests I have done with the queries. On unit tests I have used h2
in memory database based transactor.
Reference
- https://medium.com/rahasak/doobie-and-cats-effects-d01230be5c38
- http://www.beyondthelines.net/programming/futures-vs-tasks/
- https://godatadriven.com/blog/typechecking-sql-queries-with-doobie/
- https://softwaremill.com/comparing-scala-relational-database-access-libraries/
- https://medium.com/@wiemzin/zio-with-http4s-and-doobie-952fba51d089
- https://www.innoq.com/en/blog/functional-service-in-scala/