haskellhaskell-persistent

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

Solution

  • 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.)