# opium > An opionated Haskell Postgres library. ## Quick Start We assume that our database contains this table: ```sql 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: ```haskell {-# 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: ```haskell 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 - [x] Implement `String` and `Text` decoding - [x] Implement `Int` decoding - [x] Implement error reporting i.e. use `Either OpiumError` instead of `Maybe` - [x] Implement `Float` and `Double` decoding - [x] Clean up and document column table stuff - [x] Decode `LibPQ.Binary` - [x] Implement `date -> Day` decoding - [x] Implement `UTCTime` - [x] Implement `ByteString` decoding (`bytea`) - [x] Test negative integer decoding, especially for `Integer` - [ ] Implement time intervals - [ ] and zoned time decoding - [ ] How about `timezone`? This could prove problematic when the server and application have different time zones - [x] Implement `fetch` (`fetch_` but with parameter passing) - [ ] Implement JSON decoding - [ ] Implement (anonymous) composite types - [ ] Catch [UnicodeException](https://hackage.haskell.org/package/text-2.1/docs/Data-Text-Encoding-Error.html#t:UnicodeException) when decoding text - This might not be necessary if Postgres guarantees us that having a textual OID on a field means that the field is encoded correctly. - [ ] Implement array decoding - [ ] Better docs and structure for `FromRow` module - [ ] Lexer for PostgreSQL that replaces $name by $1, $2, etc. - [ ] Tutorial - [ ] Rationale - [ ] `FromRow` - [ ] Custom `FromField` impls - [ ] Improve type errors when trying to `instance` a type that isn't a record (e.g. sum type)