1. Introduction

This is a very short book about doobie, which is a pure-functional JDBC layer for Scala.

doobie provides low-level access to everything in java.sql (as of JDK 1.6, JDBC 4.0), allowing you to write any JDBC program in a pure functional style. However the focus of this book is the high-level API, which is where most users will spend their time.

This book is organized cookbook-style: we demonstrate a common task and then explain how it works, perhaps in more detail than you want right now. The goal is to get you up and running quickly, but give you a handle on the deeper stuff if you need it later.

Target Audience

This library is designed for people who are interested in typed, pure functional programming. If you are not a scalaz user or are not familiar with functional I/O and monadic effects, you may need to go slowly and may want to spend some time reading Functional Programming in Scala, which introduces all of the ideas that you will find when exploring doobie.

Having said this, if you find yourself confused or frustrated by this documentation or the doobie API, please ask a question on Gitter, file an issue or find tpolecat on Twitter or #scala (FreeNode IRC) and ask for help. Both the library and the documentation are young and are changing quickly, and it is inevitable that some things will be unclear. Accordingly, this book is updated for each release to address problems and omissions.

Please take a moment to check the banner in the upper-right corner to ensure that you are reading the right version of this book! If not, use the versions menu above to select the one you want.

The Setup

This book is compiled as part of the build using the tut tutorial generator, so the code examples are guaranteed to compile (and with luck should also work correctly). Each page stands on its own: if you copy and paste code samples starting from the top, it will work in your REPL as long as you have the proper setup, described here.

Sample Database Setup

The example code assumes a local PostgreSQL server with a postgres user with no password, PostGIS extensions (optional), and the sample world database loaded up. If you’re on a Mac you might check out the excellent Postgres.app if you don’t want to install PostgreSQL as a service. You can set up the user and sample database (and an enum we use in a few examples) as follows:

$ curl -O https://raw.githubusercontent.com/tpolecat/doobie/master/world.sql
$ psql -c 'create user postgres createdb'
$ psql -c 'create database world;' -U postgres
$ psql -c '\i world.sql' -d world -U postgres
$ psql -d world -c "create type myenum as enum ('foo', 'bar')" -U postgres
$ psql -d world -c "create extension postgis" -U postgres

Skip the last statement if you don’t have PostGIS installed. Note that the final ANALYZE comand in the import will emit a few errors for system tables. This is expected and is fine. Try a query or two to double-check your setup:

$ psql -d world -U postgres
psql (9.3.5)
Type "help" for help.

world=> select name, continent, population from country where name like 'U%';
                 name                 |   continent   | population
--------------------------------------+---------------+------------
 United Arab Emirates                 | Asia          |    2441000
 United Kingdom                       | Europe        |   59623400
 Uganda                               | Africa        |   21778000
 Ukraine                              | Europe        |   50456000
 Uruguay                              | South America |    3337000
 Uzbekistan                           | Asia          |   24318000
 United States                        | North America |  278357000
 United States Minor Outlying Islands | Oceania       |          0
(8 rows)

world=> \q
$

You can of course change this setup if you like, but you will need to adjust your JDBC connection information accordingly. Most examples will work with any compliant database, but in a few cases (noted in the text) we rely on vendor-specific behavior.

Scala Setup

On the Scala side you just need a console with the proper dependencies. A minimal build.sbt would look something like this.

scalaVersion := "2.12.2" // or scala 2.11.11

lazy val doobieVersion = "0.4.2"

libraryDependencies ++= Seq(
  "org.tpolecat" %% "doobie-core"       % doobieVersion,
  "org.tpolecat" %% "doobie-postgres"   % doobieVersion,
  "org.tpolecat" %% "doobie-specs2"     % doobieVersion
)

If you are not using PostgreSQL you can omit doobie-postgres and will need to add the appropriate JDBC driver as a dependency. Note that there is a doobie-h2 add-on if you happen to be using H2.

Conventions

Each page begins with some imports, like this.

import scalaz._, Scalaz._
import doobie.imports._

After that there is text interspersed with code examples. Sometimes definitions will stand alone.


case class Person(name: String, age: Int)

val nel = NonEmptyList(Person("Bob", 12), Person("Alice", 14))

And sometimes they will appear as a REPL interaction.

scala> nel.head
res2: Person = Person(Bob,12)

scala> nel.tail
res3: scalaz.IList[Person] = [Person(Alice,14)]

Sometimes we demonstrate that something doesn’t compile. In such cases it will be clear from the context that this is expected, and not a problem with the documentation.

scala> woozle(nel) // doesn't compile
<console>:23: error: not found: value woozle
       woozle(nel) // doesn't compile
       ^

Feedback and Contributions

Feedback on doobie or this book is genuinely welcome. Please feel free to file a pull request if you have a contribution, or file an issue, or find and chat with tpolecat as mentioned above.