packages feed

pqi-0.1.0.2: README.md

# pqi

[![Hackage](https://img.shields.io/hackage/v/pqi.svg)](https://hackage.haskell.org/package/pqi)
[![Continuous Haddock](https://img.shields.io/badge/haddock-master-blue)](https://nikita-volkov.github.io/pqi/)

A driver-agnostic interface to the PostgreSQL [libpq][libpq] API.

## Ecosystem

| Package | Description |
|---------|-------------|
| **[pqi](https://github.com/nikita-volkov/pqi)** *(this)* | The interface: `IsConnection` class, shared types, and connection-independent helpers |
| [pqi-ffi](https://github.com/nikita-volkov/pqi-ffi) | FFI adapter backed by `postgresql-libpq` and the C `libpq` library. Battle-tested, production-safe |
| [pqi-native](https://github.com/nikita-volkov/pqi-native) | Pure-Haskell adapter speaking the PostgreSQL wire protocol directly. No C dependency. Alpha — interchangeable with `pqi-ffi` |
| [pqi-conformance](https://github.com/nikita-volkov/pqi-conformance) | Reusable `hspec` conformance suite that differentially tests any adapter against `postgresql-libpq` |

## Motivation

Every major Haskell PostgreSQL driver today depends on
[`postgresql-libpq`][postgresql-libpq], a binding to the C `libpq` library.
This means every user of every driver needs `libpq` installed — on their
development machine, in CI, in production containers, on cross-compilation
targets. There is no way to opt out.

`pqi` solves this by separating the interface from the implementation. It
defines a driver-agnostic type class (`IsConnection`) that mirrors the `libpq`
API surface, then ships two adapters:

- [`pqi-ffi`](https://github.com/nikita-volkov/pqi-ffi) — a thin wrapper
  around `postgresql-libpq`. Battle-tested, production-safe. The default
  choice.
- [`pqi-native`](https://github.com/nikita-volkov/pqi-native) — a from-scratch
  pure-Haskell implementation of the PostgreSQL wire protocol. **Alpha.** It
  produces byte-identical output to `postgresql-libpq` for all
  protocol-derived values (verified by differential testing), but it has not
  yet been exercised in production at scale. Because it implements the same
  `pqi` interface as `pqi-ffi`, the two are fully interchangeable — switching
  between them is a one-line change, so adopting `pqi-native` now carries no
  lock-in. If you adopt it, we want to hear from you.

A driver built against `pqi` gives its users transport choice without any
changes to the driver itself. Each adapter package exports a single
top-level `Adapter` value bundling its connection-establishing functions;
the user picks one at connection time:

```haskell
-- C-backed (safe, requires libpq)
connection <- connectdb Pqi.Ffi.adapter settings

-- Pure Haskell (alpha, no C dependency)
connection <- connectdb Pqi.Native.adapter settings
```

## Testing model

`pqi` comes accompanied by a comprehensive conformance suite isolated into an implementation-agnostic `pqi-conformance` package that covers various edge-cases and error conditions and covers most operations with a precondition that they must behave in exactly the same way that `postgresql-libpq` does.

## Interface

`pqi` reproduces the API surface of the [`postgresql-libpq`][postgresql-libpq]
package, but reifies the connection — and the results and cancellation
handles it produces — as plain records of closures instead of a single
concrete type tied to `libpq`. There is exactly one `Connection`, one
`Result`, and one `Cancel` type in the whole package; each field is an `IO`
action that an adapter has already closed over its own underlying handle
(a C `PGconn` pointer, a native socket, etc.). Code written against this
interface runs unchanged on any adapter:

- [`pqi-ffi`](https://github.com/nikita-volkov/pqi-ffi) — a thin
  adapter backed by the C `libpq` library via `postgresql-libpq`.
- [`pqi-native`](https://github.com/nikita-volkov/pqi-native) — a
  pure-Haskell adapter that speaks the PostgreSQL wire protocol directly.

The interface mirrors `libpq` in semantics, not just shape: every compliant
adapter must produce byte-identical output to `libpq` for all protocol-derived
values. This contract is enforced by
[`pqi-conformance`](https://github.com/nikita-volkov/pqi-conformance), which
runs every operation differentially against [`postgresql-libpq`][postgresql-libpq] and asserts equality.

This package ships only the interface: the `Connection`, `Result`, and
`Cancel` records, the `Adapter` type that adapter packages bundle their
connection-establishing functions under, and the shared type vocabulary
(statuses, field codes, formats, OIDs). It does not itself construct any
connections — that's each adapter package's job, exposed as a single
top-level `adapter :: Adapter` value.

## Relationship to `postgresql-libpq`

The function names, argument order, and semantics mirror
`Database.PostgreSQL.LibPQ`. The deliberate departures are:

- `Connection`, `Result`, and `Cancel` are plain records of closures rather
  than a class-parameterised type and its associated types.
- OIDs are a plain `Word32` and row/column/parameter indices are a plain
  `Int32`, instead of the C-specific newtypes of the original.
- There's no `invalidOid` constant. It's just `0`.
- Ambiguous, rarely-useful helpers (e.g. `resStatus`) are omitted, as is
  `libpqVersion`.
- `unescapeBytea` is a field of `Adapter` rather than a
  connection-independent top-level function, since its implementation is
  adapter-specific.

[libpq]: https://www.postgresql.org/docs/current/libpq.html
[postgresql-libpq]: https://hackage.haskell.org/package/postgresql-libpq