Piggy is a tiny little Haskell library that makes Database.PostgreSQL.Simple just a tiny bit easier to work with. It also facilitates easier unit testing.
It uses the Operational monad and a simple typeclass:
class Monad m => MonadPG m where
interpret :: PGDSL a -> m a
withTransaction :: m a -> m a
withTransaction t = t
A default interpreter — interpg
— that talks to a Postgres database is provided, as is PG
, a default implementation of MonadPG
that actually talks to a database using interpg
.
instance MonadPG PG where
interpret = interpg
withTransaction transact = withPostgresTransaction $ flip withPG transact
In unit tests, it's relatively straightforward to replace actual database access with stubs.
getPatients :: MonadPG m => m [Patient]
getPatients = interpret $ singleton (Query_ "SELECT * FROM patients")
patients :: [Patient]
-- etc.
interstubs :: Monad m => PGDSL a -> m a
interstubs m = case view m of
(Query_ "SELECT * FROM patients") :>>= k -> return patients >>= interstubs . k
-- etc.
newtype PGStub a = PGStub a deriving (Functor, Applicative, Monad)
-- If `getPatients` is called with `PGStub`, it will be interpreted with
-- interstubs and no actual database access will occur. In fact, the
-- function is actually pure because it does not require `MonadIO`.
instance MonadPG PGStub where
interpret = interstubs