igr
igr

Reputation: 10604

Extract liftIO and runSql in separate function (Haskell)

I use Persist and Servant. I have the following definitions in one module:

-- Type alias for convenience
type DbAction m a = ReaderT SqlBackend m a

-- Run database queries with a connection pool
runSql :: DbAction (NoLoggingT (ResourceT IO)) a -> ConnectionPool -> IO a
runSql = runSqlPersistMPool

Now, in my Servant API definition (different module), I have a bunch of these:

    postUser :: UserCreate -> Handler Text
    postUser user = liftIO $ flip runSql pool $ do
      storeUser user

    getUser :: PathUserId -> Handler (Maybe User)
    getUser uid = liftIO $ flip runSql pool $ do
      fetchUser $ extractUserId uid

I want to extract liftIO $ flip runSql pool $ ... in a function so I don't repeat it all over the file.

For some reason I am stuck here and can't figure it out :(

EDIT

Something I tried:

runDbAction :: SqlPersistT IO a -> Handler a
runDbAction action = liftIO $ flip runSql pool $ action

however, SqlPersistT exist only in Sqlite package, and I dont want to depend on it...

SOLUTION

I ended up using

    runDbAction :: SqlPersistM a -> Handler a
    runDbAction action = liftIO $ runSql action pool

Upvotes: 3

Views: 73

Answers (1)

Daniel Wagner
Daniel Wagner

Reputation: 152837

Something like this can be written without depending on particularly specialized libraries:

runDbAction :: MonadIO m => r -> ReaderT r IO a -> m a
runDbAction r = liftIO . flip runReaderT r

We have the following specialized definitions:

type SqlPersistT = ReaderT SqlBackend
newtype Handler a
instance MonadIO Handler

which means that runDbAction can be used as if it had this type:

runDbAction :: SqlBackend -> SqlPersistT IO a -> Handler a

Of course, you can't bake pool into the definition without depending on the package that gives you SqlBackend.


(This answer assumes you are using persistent to provide SqlPersistT and servant-server to provide Handler.)

Upvotes: 2

Related Questions