BSD-3-Clause licensed by Oliver Charles
Maintained by
This version can be pinned in stack with:rel8-,5023

Module documentation for


Welcome to Rel8! Rel8 is a Haskell library for interacting with PostgreSQL databases, built on top of the fantastic Opaleye library.

The main objectives of Rel8 are:

  • Conciseness: Users using Rel8 should not need to write boiler-plate code. By using expressive types, we can provide sufficient information for the compiler to infer code whenever possible.

  • Inferrable: Despite using a lot of type level magic, Rel8 aims to have excellent and predictable type inference.

  • Familiar: writing Rel8 queries should feel like normal Haskell programming.

Rel8 was presented at ZuriHac 2021. If you want to have a brief overview of what Rel8 is, and a tour of the API - check out the video below:

Rel8 presentation at ZuriHac 2021

For more details, check out the official documentation.

Changes (2021-07-16)

New features

  • You can derive Rel8able for “vanilla” higher-kinded data types - data types that don’t use the Column type family. For example, the following is now possible:

    data MyTable f = MyTable
      { myTableX :: f Int32
      , myTableY :: f Text
      } deriving (Generic, Rel8able)
  • The Projectable and Biprojectable type classes have been introduced. These classes model a type of functors and bifunctors (respectively) on tables, where the mapping function is only able to rearrange columns. For example, the following is now possible:

    x <- project myTableX <$> many ...
  • Insert‘s onConflict field now has a new option - DoUpdate. This maps to PostgreSQL’s ON CONFLICT DO UPDATE syntax, which provides upsert support. (#85)

  • Insert, Update and Delete has all been expanded to work with Querys. In particular:

    • Delete now supports a USING sub-query
    • Update now supports a FROM sub-query
    • Insert can delete the result of any arbitrary Query (providing the types match)
  • The new Rel8.Tabulate module has been added, which gives a Map-esque interface to writing and composing queries. (#70)

  • The new indexed Query -> Query function was added. This function augments each row in a query with it’s 0-based index. (#117)

Breaking changes

  • Insert, Delete and Update have all changed. In particular, for Insert users should now replace rows = xs with rows = values xs. (#85)

  • Rename whereExists and whereNotExists to present and absent respectively. (#57)

  • Simplify evaluate to run directly inside the Query monad, rendering the Evaluate monad unnecessary. (#56)

  • The Labelable type class has been removed as it’s no longer necessary. This class was mostly internal, though was visible in some public API functions. (#76)

  • EitherTable, ListTable, MaybeTable, NonEmptyTable and TheseTable now all have an extra parameter which tracks the context of the table. If you manually specified any types before, you need to provide this parameter - usually Expr will be the correct choice. (#101)

  • We’ve done a lot of work to simplify the internals of Rel8, but some of these are breaking changes. However, most of these API changes shouldn’t affect users as they are mostly types used in type inference, or affect classes where users don’t need to define their own instances.

    • The kind of a Rel8able is now (Type -> Type) -> Type. Previously it was (X -> Type) -> Type.
    • Table has a new associated type - FromExprs. This was previously an open type family.
    • Table has a new associated type - Transpose - and Recontextualise has been renamed to Transposes. This Transposes class now operates in terms of Transpose.
  • select, insert, update and delete now produce Hasql Statements, rather than actually running the statement as IO. This allows Rel8 to be used with transaction/connection-managing monads like hasql-transaction. (#94)

Bug fixes

  • Fixes a bug where cartesian products of queries using catListTable, catNonEmptyTable, catList and catNonEmpty would incorrectly be zipped instead. (#61)

  • Require Opaleye This version has better support for lateral queries, which can improve query plans, especially in optional/LEFT JOIN (#72)

  • Rel8 now compiles with GHC 9. (#97)

Other changes

  • exists is now implemented in terms of the SQL EXISTS keyword. (#69)

  • alignBy no longer requires Tables. (#67) (2021-06-21)

This release contains various fixes for documentation. (2021-06-18)

  • Initial release.