preql: safe PostgreSQL queries using Quasiquoters

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

Before you Post(gres)QL, preql.

Eventually preql quasiquoters will provide syntax checking & optional schema checking. We're not there yet. You may be interested in reading the quickstart or the vision


[Skip to Readme]

Properties

Versions 0.1, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6
Change log CHANGELOG.md
Dependencies aeson (>=1.4.6.0 && <1.5), array (>=0.5.4.0 && <0.6), base (>=4.13.0.0 && <4.14), binary-parser (>=0.5.5 && <0.6), bytestring (>=0.10.10.0 && <0.11), bytestring-strict-builder (>=0.4.5.3 && <0.5), contravariant (>=1.5.2 && <1.6), free (>=5.1.3 && <5.2), mtl (>=2.2.2 && <2.3), postgresql-binary (>=0.12.2 && <0.13), postgresql-libpq (>=0.9.4.2 && <0.10), scientific (>=0.3.6.2 && <0.4), syb (>=0.7.1 && <0.8), template-haskell (>=2.15.0.0 && <2.16), text (>=1.2.4.0 && <1.3), th-lift-instances (>=0.1.14 && <0.2), time (>=1.9.3 && <1.10), transformers (>=0.5.6.2 && <0.6), uuid (>=1.3.13 && <1.4), vector (>=0.12.1.2 && <0.13) [details]
License BSD-3-Clause
Author Daniel Bergey
Maintainer bergey@teallabs.org
Category Database, PostgreSQL
Home page https://github.com/bergey/preql#readme
Bug tracker https://github.com/bergey/preql/issues
Source repo head: git clone https://github.com/bergey/preql
Uploaded by bergey at 2020-03-27T18:09:39Z

Modules

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees


Readme for preql-0.1

[back to package description]

PreQL

Before you Post(gres)QL, preql.

  1. Quickstart
  2. Vision

Current Status

preql provides a low-level interface to PostgreSQL and a quasiquoter that converts inline variable names to SQL parameters. Higher-level interfaces, checking SQL syntax & schema, are planned.

Quickstart

    import Preql -- The `Preql` module re-exports the interface useful to typical applications.
    import Control.Monad.Trans.Reader (runReaderT)

    main :: IO ()
    main = do
        conn <- connectdb "" -- Get a database connection with default connection string

        -- You can write a SQL instance to replace this ReaderT with
        -- your own application state, logging, error handling
        flip runReaderT conn $
            -- A simple query with no parameters
            cats <- query [sql| SELECT name, age FROM cats |]
            for_ cats \(cat :: (Text, Int)) -> print cat

            -- A query with parameters
            let minAge = 10
            oldCats <- query [sql| SELECT name, age FROM cats where age > ${minAge}|]
            for_ oldCats \(cat :: (Text, Int)) -> print cat

            -- A query that doesn't return rows
            query_ [sql| UPDATE cats SET age = 0 where age < 1 |]

            -- Two queries in a transaction
            moreOldCats <- runTransaction $ do
                maxAge <- V.head <$> query [sql| SELECT max(age) FROM cats |]
                query [sql| SELECT name FROM cats WHERE age = ${maxAge} |]
                -- Just an example; you could make this one DB roundtrip
            traverse_ putStrLn moreOldCats

Vision: Parsing SQL in Haskell Quasiquotes

Can GHC check that a query is sytactically correct at compile time, without having Postgres run it?

Can we teach GHC to do type inference for SQL queries? That is, given the schema of the database, and a SQL query written in the usual SQL syntax, can GHC check at compile time that the query gets the right number & types of parameters, and returns the right number & types of results? This should be augmented by validating the actual schema when first connecting to the database.

Given a table like

CREATE TABLE users (id uuid, email text, last_login timestamptz);

I'd like to write Haskell like

staleUsers = do
    now <- getCurrentTime
    query [sql|SELECT uuid, email FROM users WHERE last_login > ${now}|]

and have GHC infer staleUsers :: SQL m => m [(UUID, Text)] or something similar.

As an intermediate stage, also useful to application authors migrating from other libraries, I'd like to check syntax but not schema.

Prior Art

The most similar design that I've found in Haskell is hasql-th.

postgresql-typed also occupies a similar point in the design space. It provides a quasiquoter, and connects to Postgres at compile time to validate the queries. I haven't tried it out yet, but it seems like a very promising approach.

If you know of other libraries with similar ambitions, please let me know.

Haskell libraries that I've used in production seem to fall into 3 categories:

I'm delighted that so many people are exploring this design space, but I'm not entirely satisfied with any of these.