diff --git a/effectful-postgresql/CHANGELOG.md b/effectful-postgresql/CHANGELOG.md index 7ab0a9f..1ed7c19 100644 --- a/effectful-postgresql/CHANGELOG.md +++ b/effectful-postgresql/CHANGELOG.md @@ -7,6 +7,9 @@ and this project adheres to [Haskell Package Versioning Policy](https://pvp.hask ## [Unreleased] +### Changed +- Dynamic `PostgreSQL` effect in [#15](https://github.com/fpringle/effectful-postgresql/pull/15) + ### Added - Support `withTransactionX` functions from `postgresql-simple` in [#13](https://github.com/fpringle/effectful-postgresql/pulls/13) diff --git a/effectful-postgresql/README.md b/effectful-postgresql/README.md index 4d63c4b..1833112 100644 --- a/effectful-postgresql/README.md +++ b/effectful-postgresql/README.md @@ -1,8 +1,10 @@ # effectful-postgresql -This package provides an `effectful` effect for [postgresql-simple](https://hackage.haskell.org/package/postgresql-simple)'s `Connection` type. +This package provides `effectful` effects for using [postgresql-simple](https://hackage.haskell.org/package/postgresql-simple)'s `Connection` type. -It defines a dynamic effect to allow effectful functions to use a `Connection`, without worrying about where that `Connection` comes from. +It defines: +- a dynamic `WithConnection` effect to allow effectful functions to use a `Connection`, without worrying about where that `Connection` comes from. +- a dynamic `PostgreSQL` effect ro run database operations from `postgresql-simple`. For a higher-level effect library using [Opaleye](https://hackage.haskell.org/package/opaleye), see [effectful-opaleye](https://github.com/fpringle/effectful-postgresql/blob/main/effectful-opaleye#readme). @@ -15,20 +17,19 @@ would: import Effectful.PostgreSQL as EP import qualified Database.PostgreSQL.Simple as PSQL -insertAndList :: (EP.WithConnection :> es, IOE :> es) => Eff es [User] +insertAndList :: (WithConnection :> es, IOE :> es) => Eff es [User] insertAndList = EP.withConnection $ \conn -> do - PSQL.execute conn "insert into users (first_name) values (?)" ["Nuala"] - PSQL.query conn "select * from users where first_name in ?" $ Only $ In ["Anna", "Boris", "Carla"] + liftIO $ PSQL.execute conn "insert into users (first_name) values (?)" ["Nuala"] + liftIO $ PSQL.query conn "select * from users where first_name in ?" $ Only $ In ["Anna", "Boris", "Carla"] ``` -In fact, for convenience we also define lifted versions of all of the query/execute -functions from `postgresql-simple`, so we can completely forget about `Connection` and rewrite the above to: +The `PostgreSQL` effect lets us completely forget about `Connection` and rewrite the above to: ```haskell import Effectful.PostgreSQL -insertAndList :: (EP.WithConnection :> es, IOE :> es) => Eff es [User] +insertAndList :: (PostgreSQL :> es) => Eff es [User] insertAndList = do EP.execute "insert into users (first_name) values (?)" ["Nuala"] EP.query "select * from users where first_name in ?" $ Only $ In ["Anna", "Boris", "Carla"] @@ -38,19 +39,26 @@ The same goes for other functions: ```haskell -- use a transaction -insertAndListCarefully :: (EP.WithConnection :> es, IOE :> es) => Eff es [User] +insertAndListCarefully :: (PostgreSQL :> es) => Eff es [User] insertAndListCarefully = EP.withTransaction insertAndList -- stream + fold over results (in Eff) -countUsersIneffeciently :: (EP.WithConnection :> es, IOE :> es, Log :> es) => Eff es Int +countUsersIneffeciently :: (PostgreSQL :> es, Log :> es) => Eff es Int countUsersIneffeciently = - EP.fold_ "select * from users" 0 $ \acc row -> + EP.fold_ "select * from users" 0 $ \acc row -> do log $ "User: " <> show row pure $ acc + 1 ``` ## Interpreters +In order to discharge the `PostgreSQL` effect we use the `WithConnection` effect: + +```haskell +dischargePostgreSQL :: (WithConnection :> es, IOE :> es) => Eff es [User] +dischargePostgreSQL = runPostgreSQL insertAndListCarefully +``` + The simplest way of running the `WithConnection` effect is by just providing a `Connection`, which we can get in the normal ways: ```haskell @@ -59,12 +67,12 @@ import qualified Database.PostgreSQL.Simple as PSQL usingConnection :: IO () usingConnection = - bracket (PSQL.connectPostgreSQL "") PSQL.close $ \conn -> - runEff . EP.runWithconnection conn $ insertAndListCarefully + void $ bracket (PSQL.connectPostgreSQL "") PSQL.close $ \conn -> + runEff . runWithConnection conn $ runPostgreSQL insertAndListCarefully usingConnectInfo :: IO () usingConnectInfo = - runEff . EP.runWithconnectInfo PSQL.defaultConnectInfo $ insertAndListCarefully + void . runEff . runWithConnectInfo PSQL.defaultConnectInfo $ runPostgreSQL insertAndListCarefully ``` Alternatively, we can use a connection pool (from [resource-pool](https://hackage.haskell.org/package/resource-pool) @@ -80,5 +88,5 @@ usingConnectionPool :: IO () usingConnectionPool = do poolCfg <- P.mkDefaultPoolConfig (PSQL.connectPostgreSQL "") PSQL.close 5.0 10 pool <- P.newPool poolCfg - runEff . EP.runWithconnectionPool pool $ insertAndListCarefully + void . runEff . runWithConnectionPool pool $ runPostgreSQL insertAndListCarefully ``` diff --git a/effectful-postgresql/effectful-postgresql.cabal b/effectful-postgresql/effectful-postgresql.cabal index 02f8738..cdf0b26 100644 --- a/effectful-postgresql/effectful-postgresql.cabal +++ b/effectful-postgresql/effectful-postgresql.cabal @@ -72,6 +72,7 @@ library , extensions exposed-modules: Effectful.PostgreSQL + Effectful.PostgreSQL.Effect Effectful.PostgreSQL.Connection if flag(enable-pool) exposed-modules: diff --git a/effectful-postgresql/src/Effectful/PostgreSQL.hs b/effectful-postgresql/src/Effectful/PostgreSQL.hs index c1fab33..0cc71f6 100644 --- a/effectful-postgresql/src/Effectful/PostgreSQL.hs +++ b/effectful-postgresql/src/Effectful/PostgreSQL.hs @@ -1,9 +1,10 @@ {-# LANGUAGE CPP #-} module Effectful.PostgreSQL - ( -- * Effect + ( -- * Effects WithConnection , withConnection + , PostgreSQL -- ** Interpreters , runWithConnection @@ -12,6 +13,8 @@ module Effectful.PostgreSQL , runWithConnectionPool #endif + , runPostgreSQL + -- * Lifted versions of functions from Database.PostgreSQL.Simple -- ** Queries that return results @@ -64,326 +67,9 @@ module Effectful.PostgreSQL ) where -import qualified Control.Exception as E -import Data.Int (Int64) -import qualified Database.PostgreSQL.Simple as PSQL import qualified Database.PostgreSQL.Simple.Transaction as PSQL -import qualified Database.PostgreSQL.Simple.FromRow as PSQL -import Effectful import Effectful.PostgreSQL.Connection as Conn -import GHC.Stack +import Effectful.PostgreSQL.Effect #if POOL import Effectful.PostgreSQL.Connection.Pool as Pool #endif - --- | Lifted 'PSQL.query'. -query :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow q, PSQL.FromRow r) => - PSQL.Query -> - q -> - Eff es [r] -query q row = withConnection $ \conn -> liftIO (PSQL.query conn q row) - --- | Lifted 'PSQL.query_'. -query_ :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.FromRow r) => - PSQL.Query -> - Eff es [r] -query_ row = withConnection $ \conn -> liftIO (PSQL.query_ conn row) - --- | Lifted 'PSQL.queryWith'. -queryWith :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow q) => - PSQL.RowParser r -> - PSQL.Query -> - q -> - Eff es [r] -queryWith parser q row = - withConnection $ \conn -> liftIO (PSQL.queryWith parser conn q row) - --- | Lifted 'PSQL.queryWith_'. -queryWith_ :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.RowParser r -> - PSQL.Query -> - Eff es [r] -queryWith_ parser row = - withConnection $ \conn -> liftIO (PSQL.queryWith_ parser conn row) - --- | Lifted 'PSQL.execute'. -execute :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow q) => - PSQL.Query -> - q -> - Eff es Int64 -execute q row = withConnection $ \conn -> liftIO (PSQL.execute conn q row) - --- | Lifted 'PSQL.execute_'. -execute_ :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.Query -> - Eff es Int64 -execute_ row = withConnection $ \conn -> liftIO (PSQL.execute_ conn row) - --- | Lifted 'PSQL.executeMany'. -executeMany :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow q) => - PSQL.Query -> - [q] -> - Eff es Int64 -executeMany q rows = withConnection $ \conn -> liftIO (PSQL.executeMany conn q rows) - --- | Lifted 'PSQL.withTransaction'. -withTransaction :: - (HasCallStack, WithConnection :> es, IOE :> es) => Eff es a -> Eff es a -withTransaction f = - unliftWithConn $ \conn unlift -> - PSQL.withTransaction conn (unlift f) - --- | Lifted 'PSQL.withTransactionLevel'. -withTransactionLevel :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.IsolationLevel -> - Eff es a -> - Eff es a -withTransactionLevel level f = - unliftWithConn $ \conn unlift -> - PSQL.withTransactionLevel level conn (unlift f) - --- | Lifted 'PSQL.withTransactionMode'. -withTransactionMode :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.TransactionMode -> - Eff es a -> - Eff es a -withTransactionMode mode f = - unliftWithConn $ \conn unlift -> - PSQL.withTransactionMode mode conn (unlift f) - --- | Lifted 'PSQL.withTransactionModeRetry'. -withTransactionModeRetry :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.TransactionMode -> - (PSQL.SqlError -> Bool) -> - Eff es a -> - Eff es a -withTransactionModeRetry mode shouldRetry f = - unliftWithConn $ \conn unlift -> - PSQL.withTransactionModeRetry mode shouldRetry conn (unlift f) - --- | Lifted 'PSQL.withTransactionModeRetry''. -withTransactionModeRetry' :: - (HasCallStack, WithConnection :> es, IOE :> es, E.Exception e) => - PSQL.TransactionMode -> - (e -> Bool) -> - Eff es a -> - Eff es a -withTransactionModeRetry' mode shouldRetry f = - unliftWithConn $ \conn unlift -> - PSQL.withTransactionModeRetry' mode shouldRetry conn (unlift f) - --- | Lifted 'PSQL.withTransactionSerializable'. -withTransactionSerializable :: - (HasCallStack, WithConnection :> es, IOE :> es) => Eff es a -> Eff es a -withTransactionSerializable f = - unliftWithConn $ \conn unlift -> - PSQL.withTransactionSerializable conn (unlift f) - --- | British alias of 'withTransactionSerializable'. -withTransactionSerialisable :: - (HasCallStack, WithConnection :> es, IOE :> es) => Eff es a -> Eff es a -withTransactionSerialisable = withTransactionSerializable -{-# INLINE withTransactionSerialisable #-} - --- | Lifted 'PSQL.withSavepoint'. -withSavepoint :: (HasCallStack, WithConnection :> es, IOE :> es) => Eff es a -> Eff es a -withSavepoint f = - unliftWithConn $ \conn unlift -> - PSQL.withSavepoint conn (unlift f) - --- | Lifted 'PSQL.begin'. -begin :: (HasCallStack, WithConnection :> es, IOE :> es) => Eff es () -begin = withConnection $ liftIO . PSQL.begin - --- | Lifted 'PSQL.commit'. -commit :: (HasCallStack, WithConnection :> es, IOE :> es) => Eff es () -commit = withConnection $ liftIO . PSQL.commit - --- | Lifted 'PSQL.rollback'. -rollback :: (HasCallStack, WithConnection :> es, IOE :> es) => Eff es () -rollback = withConnection $ liftIO . PSQL.rollback - -(...) :: (a -> b) -> (t1 -> t2 -> a) -> t1 -> t2 -> b -unlift ... f = \a' row -> unlift $ f a' row - -unliftWithConn :: - (HasCallStack, WithConnection :> es, IOE :> es) => - (PSQL.Connection -> (forall b. Eff es b -> IO b) -> IO a) -> - Eff es a -unliftWithConn f = - withConnection $ \conn -> - withSeqEffToIO $ \unlift -> - liftIO $ f conn unlift -{-# INLINE unliftWithConn #-} - --- | Lifted 'PSQL.fold'. -fold :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.FromRow row, PSQL.ToRow params) => - PSQL.Query -> - params -> - a -> - (a -> row -> Eff es a) -> - Eff es a -fold q params a f = - unliftWithConn $ \conn unlift -> - PSQL.fold conn q params a (unlift ... f) - --- | Lifted 'PSQL.foldWithOptions'. -foldWithOptions :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.FromRow row, PSQL.ToRow params) => - PSQL.FoldOptions -> - PSQL.Query -> - params -> - a -> - (a -> row -> Eff es a) -> - Eff es a -foldWithOptions opts q params a f = - unliftWithConn $ \conn unlift -> - PSQL.foldWithOptions opts conn q params a (unlift ... f) - --- | Lifted 'PSQL.fold_'. -fold_ :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.FromRow row) => - PSQL.Query -> - a -> - (a -> row -> Eff es a) -> - Eff es a -fold_ q a f = - unliftWithConn $ \conn unlift -> - PSQL.fold_ conn q a (unlift ... f) - --- | Lifted 'PSQL.foldWithOptions_'. -foldWithOptions_ :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.FromRow row) => - PSQL.FoldOptions -> - PSQL.Query -> - a -> - (a -> row -> Eff es a) -> - Eff es a -foldWithOptions_ opts q a f = - unliftWithConn $ \conn unlift -> - PSQL.foldWithOptions_ opts conn q a (unlift ... f) - --- | Lifted 'PSQL.forEach'. -forEach :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.FromRow r, PSQL.ToRow q) => - PSQL.Query -> - q -> - (r -> Eff es ()) -> - Eff es () -forEach q row forR = - unliftWithConn $ \conn unlift -> - PSQL.forEach conn q row (unlift . forR) - --- | Lifted 'PSQL.forEach_'. -forEach_ :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.FromRow r) => - PSQL.Query -> - (r -> Eff es ()) -> - Eff es () -forEach_ q forR = - unliftWithConn $ \conn unlift -> - PSQL.forEach_ conn q (unlift . forR) - --- | Lifted 'PSQL.returning'. -returning :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow q, PSQL.FromRow r) => - PSQL.Query -> - [q] -> - Eff es [r] -returning q rows = withConnection $ \conn -> liftIO $ PSQL.returning conn q rows - --- | Lifted 'PSQL.foldWith'. -foldWith :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow params) => - PSQL.RowParser row -> - PSQL.Query -> - params -> - a -> - (a -> row -> Eff es a) -> - Eff es a -foldWith parser q params a f = - unliftWithConn $ \conn unlift -> - PSQL.foldWith parser conn q params a (unlift ... f) - --- | Lifted 'PSQL.foldWithOptionsAndParser'. -foldWithOptionsAndParser :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow params) => - PSQL.FoldOptions -> - PSQL.RowParser row -> - PSQL.Query -> - params -> - a -> - (a -> row -> Eff es a) -> - Eff es a -foldWithOptionsAndParser opts parser q params a f = - unliftWithConn $ \conn unlift -> - PSQL.foldWithOptionsAndParser opts parser conn q params a (unlift ... f) - --- | Lifted 'PSQL.foldWith_'. -foldWith_ :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.RowParser row -> - PSQL.Query -> - a -> - (a -> row -> Eff es a) -> - Eff es a -foldWith_ parser q a f = - unliftWithConn $ \conn unlift -> - PSQL.foldWith_ parser conn q a (unlift ... f) - --- | Lifted 'PSQL.foldWithOptionsAndParser_'. -foldWithOptionsAndParser_ :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.FoldOptions -> - PSQL.RowParser row -> - PSQL.Query -> - a -> - (a -> row -> Eff es a) -> - Eff es a -foldWithOptionsAndParser_ opts parser q a f = - unliftWithConn $ \conn unlift -> - PSQL.foldWithOptionsAndParser_ opts parser conn q a (unlift ... f) - --- | Lifted 'PSQL.forEachWith'. -forEachWith :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow q) => - PSQL.RowParser r -> - PSQL.Query -> - q -> - (r -> Eff es ()) -> - Eff es () -forEachWith parser q row forR = - unliftWithConn $ \conn unlift -> - PSQL.forEachWith parser conn q row (unlift . forR) - --- | Lifted 'PSQL.forEachWith_'. -forEachWith_ :: - (HasCallStack, WithConnection :> es, IOE :> es) => - PSQL.RowParser r -> - PSQL.Query -> - (r -> Eff es ()) -> - Eff es () -forEachWith_ parser row forR = - unliftWithConn $ \conn unlift -> - PSQL.forEachWith_ parser conn row (unlift . forR) - --- | Lifted 'PSQL.returningWith'. -returningWith :: - (HasCallStack, WithConnection :> es, IOE :> es, PSQL.ToRow q) => - PSQL.RowParser r -> - PSQL.Query -> - [q] -> - Eff es [r] -returningWith parser q rows = - withConnection $ \conn -> liftIO $ PSQL.returningWith parser conn q rows diff --git a/effectful-postgresql/src/Effectful/PostgreSQL/Effect.hs b/effectful-postgresql/src/Effectful/PostgreSQL/Effect.hs new file mode 100644 index 0000000..d954652 --- /dev/null +++ b/effectful-postgresql/src/Effectful/PostgreSQL/Effect.hs @@ -0,0 +1,295 @@ +{-# LANGUAGE TemplateHaskell #-} + +module Effectful.PostgreSQL.Effect + ( -- * Effect + PostgreSQL (..) + + -- ** Interpreters + , runPostgreSQL + + -- * Lifted versions of functions from Database.PostgreSQL.Simple + + -- ** Queries that return results + , query + , query_ + , queryWith + , queryWith_ + + -- ** Statements that do not return results + , execute + , execute_ + , executeMany + + -- ** Transaction handling + , withTransaction + , withTransactionLevel + , PSQL.IsolationLevel (..) + , withTransactionMode + , PSQL.TransactionMode (..) + , PSQL.ReadWriteMode (..) + , withTransactionModeRetry + , withTransactionModeRetry' + , withTransactionSerializable + , withTransactionSerialisable + , withSavepoint + , begin + , commit + , rollback + + -- ** Queries that stream results + , fold + , foldWithOptions + , fold_ + , foldWithOptions_ + , forEach + , forEach_ + , returning + , foldWith + , foldWithOptionsAndParser + , foldWith_ + , foldWithOptionsAndParser_ + , forEachWith + , forEachWith_ + , returningWith + ) +where + +import qualified Control.Exception as E +import Data.Int (Int64) +import qualified Database.PostgreSQL.Simple as PSQL +import qualified Database.PostgreSQL.Simple.Transaction as PSQL +import qualified Database.PostgreSQL.Simple.FromRow as PSQL +import Effectful +import Effectful.Dispatch.Dynamic +import Effectful.PostgreSQL.Connection +import Effectful.TH + +-- | Dynamic effect representing all the Postgres operations we want to perform. +data PostgreSQL :: Effect where + -- | Lifted 'PSQL.query'. + Query :: (PSQL.ToRow q, PSQL.FromRow r) => PSQL.Query -> q -> PostgreSQL m [r] + -- | Lifted 'PSQL.queryWith'. + QueryWith :: (PSQL.ToRow q) => PSQL.RowParser r -> PSQL.Query -> q -> PostgreSQL m [r] + -- | Lifted 'PSQL.query_'. + Query_ :: (PSQL.FromRow r) => PSQL.Query -> PostgreSQL m [r] + -- | Lifted 'PSQL.queryWith_'. + QueryWith_ :: PSQL.RowParser r -> PSQL.Query -> PostgreSQL m [r] + -- + + -- | Lifted 'PSQL.execute'. + Execute :: (PSQL.ToRow q) => PSQL.Query -> q -> PostgreSQL m Int64 + -- | Lifted 'PSQL.execute_'. + Execute_ :: PSQL.Query -> PostgreSQL m Int64 + -- | Lifted 'PSQL.executeMany'. + ExecuteMany :: (PSQL.ToRow q) => PSQL.Query -> [q] -> PostgreSQL m Int64 + -- + + -- | Lifted 'PSQL.withTransaction'. + WithTransaction :: m a -> PostgreSQL m a + -- | Lifted 'PSQL.withTransactionLevel'. + WithTransactionLevel :: PSQL.IsolationLevel -> m a -> PostgreSQL m a + -- | Lifted 'PSQL.withTransactionMode'. + WithTransactionMode :: PSQL.TransactionMode -> m a -> PostgreSQL m a + -- | Lifted 'PSQL.withTransactionModeRetry'. + WithTransactionModeRetry :: PSQL.TransactionMode -> (PSQL.SqlError -> Bool) -> m a -> PostgreSQL m a + -- | Lifted 'PSQL.withTransactionModeRetry''. + WithTransactionModeRetry' :: E.Exception e => PSQL.TransactionMode -> (e -> Bool) -> m a -> PostgreSQL m a + -- | Lifted 'PSQL.withTransactionSerializable'. + WithTransactionSerializable :: m a -> PostgreSQL m a + -- | Lifted 'PSQL.withSavepoint'. + WithSavepoint :: m a -> PostgreSQL m a + -- | Lifted 'PSQL.begin'. + Begin :: PostgreSQL m () + -- | Lifted 'PSQL.commit'. + Commit :: PostgreSQL m () + -- | Lifted 'PSQL.rollback'. + Rollback :: PostgreSQL m () + -- + + -- | Lifted 'PSQL.fold'. + Fold :: + (PSQL.FromRow row, PSQL.ToRow params) => + PSQL.Query -> + params -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.fold_'. + Fold_ :: + (PSQL.FromRow row) => + PSQL.Query -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.foldWithOptions'. + FoldWithOptions :: + (PSQL.FromRow row, PSQL.ToRow params) => + PSQL.FoldOptions -> + PSQL.Query -> + params -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.foldWithOptions_'. + FoldWithOptions_ :: + (PSQL.FromRow row) => + PSQL.FoldOptions -> + PSQL.Query -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.forEach'. + ForEach :: + (PSQL.FromRow r, PSQL.ToRow q) => + PSQL.Query -> + q -> + (r -> m ()) -> + PostgreSQL m () + -- | Lifted 'PSQL.forEach_'. + ForEach_ :: + (PSQL.FromRow r) => + PSQL.Query -> + (r -> m ()) -> + PostgreSQL m () + -- | Lifted 'PSQL.returning'. + Returning :: (PSQL.ToRow q, PSQL.FromRow r) => PSQL.Query -> [q] -> PostgreSQL m [r] + -- | Lifted 'PSQL.foldWith'. + FoldWith :: + (PSQL.ToRow params) => + PSQL.RowParser row -> + PSQL.Query -> + params -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.foldWithOptionsAndParser'. + FoldWithOptionsAndParser :: + (PSQL.ToRow params) => + PSQL.FoldOptions -> + PSQL.RowParser row -> + PSQL.Query -> + params -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.foldWith_'. + FoldWith_ :: + () => + PSQL.RowParser row -> + PSQL.Query -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.foldWithOptionsAndParser_'. + FoldWithOptionsAndParser_ :: + () => + PSQL.FoldOptions -> + PSQL.RowParser row -> + PSQL.Query -> + a -> + (a -> row -> m a) -> + PostgreSQL m a + -- | Lifted 'PSQL.forEachWith'. + ForEachWith :: + (PSQL.ToRow q) => + PSQL.RowParser r -> + PSQL.Query -> + q -> + (r -> m ()) -> + PostgreSQL m () + -- | Lifted 'PSQL.forEachWith_'. + ForEachWith_ :: + () => + PSQL.RowParser r -> + PSQL.Query -> + (r -> m ()) -> + PostgreSQL m () + -- | Lifted 'PSQL.returningWith'. + ReturningWith :: (PSQL.ToRow q) => PSQL.RowParser r -> PSQL.Query -> [q] -> PostgreSQL m [r] + +makeEffect ''PostgreSQL + +-- | British alias of 'withTransactionSerializable'. +withTransactionSerialisable :: + (HasCallStack, PostgreSQL :> es) => Eff es a -> Eff es a +withTransactionSerialisable = withTransactionSerializable +{-# INLINE withTransactionSerialisable #-} + +localUnliftWithConn :: + (HasCallStack, WithConnection :> es, IOE :> es) => + LocalEnv localEs es -> + (PSQL.Connection -> (forall b. Eff localEs b -> IO b) -> IO a) -> + Eff es a +localUnliftWithConn env f = + withConnection $ \conn -> + localSeqUnliftIO env $ \unlift -> + liftIO $ f conn unlift +{-# INLINE localUnliftWithConn #-} + +(...) :: (a -> b) -> (t1 -> t2 -> a) -> t1 -> t2 -> b +unlift ... f = \a' row -> unlift $ f a' row + +{- | Obvious interepreter for 'PostgreSQL'. Just gets a 'PSQL.Connection' from 'WithConnection' and calls the +corresponding function from "Database.PostgreSQL.Simple". +-} +runPostgreSQL :: forall es a. (HasCallStack, WithConnection :> es, IOE :> es) => Eff (PostgreSQL : es) a -> Eff es a +runPostgreSQL = interpret $ \env -> \case + Query q row -> + withConnection $ \conn -> liftIO (PSQL.query conn q row) + QueryWith parser q row -> + withConnection $ \conn -> liftIO (PSQL.queryWith parser conn q row) + Query_ row -> + withConnection $ \conn -> liftIO (PSQL.query_ conn row) + QueryWith_ parser row -> + withConnection $ \conn -> liftIO (PSQL.queryWith_ parser conn row) + Execute q row -> withConnection $ \conn -> liftIO (PSQL.execute conn q row) + Execute_ q -> withConnection $ \conn -> liftIO (PSQL.execute_ conn q) + ExecuteMany q row -> withConnection $ \conn -> liftIO (PSQL.executeMany conn q row) + WithTransaction f -> localUnliftWithConn env $ \conn unlift -> PSQL.withTransaction conn (unlift f) + WithTransactionLevel level f -> localUnliftWithConn env $ \conn unlift -> PSQL.withTransactionLevel level conn (unlift f) + WithTransactionMode mode f -> localUnliftWithConn env $ \conn unlift -> PSQL.withTransactionMode mode conn (unlift f) + WithTransactionModeRetry mode shouldRetry f -> localUnliftWithConn env $ \conn unlift -> PSQL.withTransactionModeRetry mode shouldRetry conn (unlift f) + WithTransactionModeRetry' mode shouldRetry f -> localUnliftWithConn env $ \conn unlift -> PSQL.withTransactionModeRetry' mode shouldRetry conn (unlift f) + WithTransactionSerializable f -> localUnliftWithConn env $ \conn unlift -> PSQL.withTransactionSerializable conn (unlift f) + WithSavepoint f -> localUnliftWithConn env $ \conn unlift -> PSQL.withSavepoint conn (unlift f) + Begin -> withConnection $ liftIO . PSQL.begin + Commit -> withConnection $ liftIO . PSQL.commit + Rollback -> withConnection $ liftIO . PSQL.rollback + Fold q params a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.fold conn q params a (unlift ... f) + Fold_ q a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.fold_ conn q a (unlift ... f) + FoldWithOptions opts q params a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.foldWithOptions opts conn q params a (unlift ... f) + FoldWithOptions_ opts q a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.foldWithOptions_ opts conn q a (unlift ... f) + ForEach q row forR -> + localUnliftWithConn env $ \conn unlift -> + PSQL.forEach conn q row (unlift . forR) + ForEach_ q forR -> + localUnliftWithConn env $ \conn unlift -> + PSQL.forEach_ conn q (unlift . forR) + Returning q rows -> withConnection $ \conn -> liftIO $ PSQL.returning conn q rows + FoldWith parser q params a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.foldWith parser conn q params a (unlift ... f) + FoldWithOptionsAndParser opts parser q params a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.foldWithOptionsAndParser opts parser conn q params a (unlift ... f) + FoldWith_ parser q a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.foldWith_ parser conn q a (unlift ... f) + FoldWithOptionsAndParser_ opts parser q a f -> + localUnliftWithConn env $ \conn unlift -> + PSQL.foldWithOptionsAndParser_ opts parser conn q a (unlift ... f) + ForEachWith parser q row forR -> + localUnliftWithConn env $ \conn unlift -> + PSQL.forEachWith parser conn q row (unlift . forR) + ForEachWith_ parser q forR -> + localUnliftWithConn env $ \conn unlift -> + PSQL.forEachWith_ parser conn q (unlift . forR) + ReturningWith parser q rows -> withConnection $ \conn -> liftIO $ PSQL.returningWith parser conn q rows diff --git a/nix/nixpkgs.nix b/nix/nixpkgs.nix index df24ba0..346197d 100644 --- a/nix/nixpkgs.nix +++ b/nix/nixpkgs.nix @@ -20,6 +20,7 @@ let # When we pin specific versions of Haskell packages, they'll go here using callCabal2Nix. packageOverrides = { postgresql-operation-counting = hfinal.callCabal2nix "postgresql-operation-counting" "${sources.postgresql-operation-counting}" { }; + effectful-th = hprev.effectful-th_1_0_0_3; }; makePackage = name: path: