2.3 KiB
2.3 KiB
opium
An opionated Haskell Postgres library.
Quick Start
We assume that our database contains this table:
CREATE TABLE person (
name TEXT NOT NULL,
age INT NOT NULL,
score DOUBLE PRECISION NOT NULL,
motto TEXT
)
We can use opium
to decode query results into Haskell data types:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
import GHC.Generics (Generic)
import Database.PostgreSQL.LibPQ (Connection)
import qualified Database.PostgreSQL.Opium as Opium
data User = User
{ name :: String
, age :: Int
, score :: Double
} deriving (Eq, Generic, Show)
instance Opium.FromRow User where
getUsers :: Connection -> IO (Either Opium.Error [Users])
getUsers conn = Opium.fetch_ conn "SELECT * FROM user"
The Opium.FromRow
instance is implemented generically for all product types ("records"). It looks up the field name in the query result and decodes the column value using Opium.FromField
.
The intended use case for this library is to enable us to write ad-hoc types for query results without having to manually write instances. For example, if we wanted to figure out how user age influences their score:
data ScoreByAge = ScoreByAge { t :: Double, m :: Double }
deriving (Eq, Generic, Show)
instance Opium.FromRow ScoreByAge where
getScoreByAge :: Connection -> IO ScoreByAge
getScoreByAge conn = do
let query = "SELECT regr_intercept(score, age) AS t, regr_slope(score, age) AS m FROM user"
Right [x] <- Opium.fetch_ conn query
pure x
TO DO
- Implement
String
andText
decoding - Implement
Int
decoding - Implement error reporting i.e. use
Either OpiumError
instead ofMaybe
- Implement
Float
andDouble
decoding - Clean up and document column table stuff
- Implement
fetch
(fetch_
but with parameter passing) - Implement
UTCTime
and zoned time decoding - Implement JSON decoding
- Implement
ByteString
decoding (bytea
)- Can we make the fromField instance choose whether it wants binary or text?
- Implement (anonymous) composite types
- It seems that in order to decode these, we'd need to use binary mode. In order to avoid writing everything twice it would be wise to move the whole
FromField
machinery to decoding from binary first
- It seems that in order to decode these, we'd need to use binary mode. In order to avoid writing everything twice it would be wise to move the whole