TL;DR: I’m writing a Postgres driver in pure Clojure. In general, works! Now I proceed with the most miserable part of the project: writing documentation. I decided to do it step by step and share it on my blog.

ToC

About

This project is a set of libraries related to the PostgreSQL database. The primary library called pg-client is a driver for Postgres written in pure Clojure. By purity I mean, neither JDBC nor any other third-party Java libraries are involved. Everything is driven by a TCP socket and implementation of the Posrgres Wire protocol. Fun!

Besides the client, the project provides such various additions as a connection pool (see pg-pool). The pg-types library holds the encoding and decoding logic which determines how to write and read Clojure data from and into the database. You can use this library separately in pair with JDBC.next and COPY for efficient data transcoding in binary format.

The question you would probably ask is, why would create a Postgres client from scratch? JDBC has been around for decades, and there are also good clojure.java.jdbc and jdbc.next wrappers on top of it?

The answer is: that although these two libraries are amazing, they don’t disclose all Postgres features. JDBC is an abstraction whose main goal is to satisfy all the DB engines. A general library that works with MS SQL, MySQL, and Postgres at the same time would reduce the variety of features each backend is capable of.

Postgres is a great database that brings an enormous amount of features. I’ve been working with Postgres a lot and in each project, I had to invent a wheel from scratch: add JSON support, type mapping, smart ResultSet processing, and so on. I strongly believe there should be a client that pairs Clojure with Postgres seamlessly when all the features are available out of the box.

Here is a brief list of the benefits of this project:

  • Written in pure Clojure and thus is completely transparent for users and developers;

  • Supports a lot of Clojure and Java types including java.time.* (see the dedicated section in the documentation);

  • Extendable encoding and decoding: adding a new type means just extending a multimethod;

  • Implements both Simple and Extended Postgres Wire protocols;

  • Implements both text and binary content encoding and decoding;

  • Easy to debug what goes through the wire;

  • Reducing the result on the fly, custom reducers; various ways to process the data;

  • SAML authentication out from the box; JDBC still fails when handling it (“unknown auth code 10”);

  • Tested with Postgres 11, 12, 13, 14, 15, and 16-beta (integration tests with multiple Docker images);

  • And more.

Installation

General Notes

Although PG is a set of modules, they all have the same version when deployed to Clojars. For example:

Lein:

[com.github.igrishaev/pg-client "0.1.6"]
[com.github.igrishaev/pg-pool "0.1.6"]

Deps:

{com.github.igrishaev/pg-client {:mvn/version "0.1.6"}

Lein users may specify a global pg-version variable on top of the project.clj and reference it as follows:

;; project.clj
(def pg-version "0.1.6")

(defproject ...
  :dependencies
  [...
   [com.github.igrishaev/pg-client ~pg-version]
   [com.github.igrishaev/pg-pool ~pg-version]])

Usually, you don’t need to specify more than one package because they depend on each other and will be download automatically.

Client

The pg-client module ships a client access to Postgres. Since the connection pool depends on logging facility, it’s shipped in a separate package.

[com.github.igrishaev/pg-client "0.1.6"]

Deps:

{com.github.igrishaev/pg-client {:mvn/version "0.1.6"}

Connection Pool

The client depends on pool so there is no need to specify it explicitly.

[com.github.igrishaev/pg-pool "0.1.6"]

Deps:

{com.github.igrishaev/pg-pool {:mvn/version "0.1.6"}

JSON extension

A package that extends the client with reading and writing JSON objects.

[com.github.igrishaev/pg-json "0.1.6"]

Deps:

{com.github.igrishaev/pg-json {:mvn/version "0.1.6"}

Joda Time extension

Extends the client with Joda Time support.

[com.github.igrishaev/pg-joda-time "0.1.6"]

Deps:

{com.github.igrishaev/pg-joda-time {:mvn/version "0.1.6"}