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 will be updated continuously to address problems and omissions.
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, 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 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
Note that the final ANALYZE
comand 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.11.4" // also works with 2.10
resolvers ++= Seq(
"tpolecat" at "http://dl.bintray.com/tpolecat/maven",
"Scalaz Bintray Repo" at "http://dl.bintray.com/scalaz/releases"
)
lazy val doobieVersion = "0.2.0"
libraryDependencies ++= Seq(
"org.tpolecat" %% "doobie-core" % doobieVersion,
"org.tpolecat" %% "doobie-contrib-postgresql" % doobieVersion,
"org.tpolecat" %% "doobie-contrib-specs2" % doobieVersion
)
If you are not using PostgreSQL you can omit doobie-contrib-postgres
and will need to add the appropriate JDBC driver as a dependency. Note that there is a doobie-contrib-h2
add-on if you happen to be using H2.
Conventions
Each page begins with some imports, like this.
import scalaz._, Scalaz._, 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
res0: Person = Person(Bob,12)
scala> nel.tail
res1: List[Person] = List(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>:21: error: not found: value woozle
woozle(nel) // doesn't compile
^
Feedback and Contributions
Feedback of all kinds (especially negative) 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.