bluefin-postgresql (empty) → 0.1.0.0
raw patch · 7 files changed
+729/−0 lines, 7 filesdep +basedep +bluefindep +postgresql-simple
Dependencies added: base, bluefin, postgresql-simple, unliftio-pool
Files
- CHANGELOG.md +20/−0
- LICENSE +30/−0
- README.md +105/−0
- bluefin-postgresql.cabal +79/−0
- src/Bluefin/PostgreSQL.hs +384/−0
- src/Bluefin/PostgreSQL/Connection.hs +74/−0
- src/Bluefin/PostgreSQL/Connection/Pool.hs +37/−0
+ CHANGELOG.md view
@@ -0,0 +1,20 @@+# Changelog++All notable changes to `bluefin-postgresql` will be documented in this file.++The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),+and this project adheres to [Haskell Package Versioning Policy](https://pvp.haskell.org).++## [Unreleased]++## [0.1.0.0] - 27.02.2026++### Added++- First edition of the package, ready for feedback.+- 100% documentation coverage.+- Reasonably detailed READMEs.+- CI that builds and tests the packages for each version of GHC in the `tested-with` field.++[unreleased]: https://github.com/fpringle/bluefin-postgresql/compare/bluefin-postgresql-0.1.0.0...HEAD+[0.1.0.0]: https://github.com/fpringle/bluefin-postgresql/releases/tag/bluefin-postgresql-0.1.0.0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2025, Frederick Pringle++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Frederick Pringle nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,105 @@+# bluefin-postgresql++This package provides a `bluefin` effect for [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.++For a higher-level effect library using [Opaleye](https://hackage.haskell.org/package/opaleye), see [bluefin-opaleye](https://github.com/fpringle/bluefin-postgresql/blob/main/bluefin-opaleye#readme).++## Effectful functions++In the `WithConnection` effect we can always request a `Connection` and use it as we normally+would:++```haskell+import Bluefin.PostgreSQL as BP+import qualified Database.PostgreSQL.Simple as PSQL++insertAndList ::+ (e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ Eff es [User]+insertAndList wc ioe = BP.withConnection wc $ \conn -> do+ effIO ioe $ PSQL.execute conn "insert into users (first_name) values (?)" ["Nuala"]+ effIO ioe $ PSQL.query conn "select * from users where first_name in ?" $ PSQL.Only $ PSQL.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:++```haskell++import Bluefin.PostgreSQL++insertAndList ::+ (e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ Eff es [User]+insertAndList wc ioe = do+ BP.execute wc ioe "insert into users (first_name) values (?)" ["Nuala"]+ BP.query wc ioe "select * from users where first_name in ?" $ PSQL.Only $ PSQL.In ["Anna", "Boris", "Carla"]+```++The same goes for other functions:++```haskell+-- use a transaction+insertAndListCarefully ::+ (e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ Eff es [User]+insertAndListCarefully wc ioe = BP.withTransaction wc ioe $ insertAndList wc ioe++-- stream + fold over results (in Eff)+countUsersIneffeciently ::+ (e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ Eff es Int+countUsersIneffeciently wc ioe =+ BP.fold_ wc ioe "select * from users" 0 $ \acc (row :: User) -> do+ effIO ioe . putStrLn $ "User: " <> show row+ pure $ acc + 1+```++## Interpreters++The simplest way of running the `WithConnection` effect is by just providing a `Connection`, which we can get in the normal ways:++```haskell+import Bluefin.PostgreSQL as BP+import qualified Database.PostgreSQL.Simple as PSQL++usingConnection :: IO ()+usingConnection =+ runEff $ \ioe ->+ bracket (effIO ioe $ PSQL.connectPostgreSQL "") (effIO ioe . PSQL.close) $ \conn ->+ BP.runWithConnection conn $ \wc -> insertAndListCarefully wc ioe >>= effIO ioe . print++usingConnectInfo :: IO ()+usingConnectInfo =+ runEff $ \ioe ->+ BP.runWithConnectInfo ioe PSQL.defaultConnectInfo $ \wc ->+ insertAndListCarefully wc ioe >>= effIO ioe . print+```++Alternatively, we can use a connection pool (from [resource-pool](https://hackage.haskell.org/package/resource-pool)+and [unliftio-pool](https://hackage.haskell.org/package/unliftio-pool)), which is much better suited to+long-running processes like servers.++```haskell+import Bluefin.PostgreSQL as BP+import qualified Database.PostgreSQL.Simple as PSQL+import qualified UnliftIO.Pool as P++usingConnectionPool :: IO ()+usingConnectionPool = do+ poolCfg <- P.mkDefaultPoolConfig (PSQL.connectPostgreSQL "") PSQL.close 5.0 10+ pool <- P.newPool poolCfg+ runEff $ \ioe ->+ BP.runWithConnectionPool ioe pool $ \wc ->+ insertAndListCarefully wc ioe >>= effIO ioe . print+```
+ bluefin-postgresql.cabal view
@@ -0,0 +1,79 @@+cabal-version: 3.0+name: bluefin-postgresql+version: 0.1.0.0+synopsis:+ bluefin support for mid-level PostgreSQL operations.+description:+ See the README for an overview, or the documentation in 'Bluefin.PostgreSQL'.+license: BSD-3-Clause+license-file: LICENSE+author: Frederick Pringle+maintainer: frederick.pringle@fpringle.com+copyright: Copyright(c) Frederick Pringle 2025+homepage: https://github.com/fpringle/bluefin-postgresql+build-type: Simple+category: Database+extra-doc-files: README.md+ CHANGELOG.md++tested-with:+ GHC == 8.10.7+ , GHC == 9.0.2+ , GHC == 9.2.4+ , GHC == 9.2.8+ , GHC == 9.4.2+ , GHC == 9.4.5+ , GHC == 9.6.1+ , GHC == 9.6.7+ , GHC == 9.8.2+ , GHC == 9.10.2++flag enable-pool+ description: Enable support for connection pools using unliftio-pool.+ You can disable this for a lighter dependency footprint if+ you don't need support for connection pools.+ default: True+ manual: False++common warnings+ ghc-options: -Wall -Wno-unused-do-bind -Wunused-packages++ if flag(enable-pool)+ cpp-options: -DPOOL++common deps+ build-depends:+ , base >= 4 && < 5+ , bluefin >= 0.0.11 && < 0.0.18+ , postgresql-simple >= 0.7 && < 0.8++ if flag(enable-pool)+ build-depends:+ , unliftio-pool >= 0.4.1 && < 0.5++common extensions+ default-extensions:+ DataKinds+ FlexibleContexts+ GADTs+ LambdaCase+ RankNTypes+ ScopedTypeVariables+ TypeApplications+ TypeFamilies+ TypeOperators++library+ import:+ warnings+ , deps+ , extensions+ exposed-modules:+ Bluefin.PostgreSQL+ Bluefin.PostgreSQL.Connection+ if flag(enable-pool)+ exposed-modules:+ Bluefin.PostgreSQL.Connection.Pool+ -- other-extensions:+ hs-source-dirs: src+ default-language: Haskell2010
+ src/Bluefin/PostgreSQL.hs view
@@ -0,0 +1,384 @@+{-# LANGUAGE CPP #-}++module Bluefin.PostgreSQL+ ( -- * Effect+ WithConnection+ , withConnection++ -- ** Interpreters+ , runWithConnection++#if POOL+ , runWithConnectionPool+#endif++ -- * 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+ , withSavepoint+ , begin+ , commit+ , rollback++ -- ** Queries that stream results+ , fold+ , foldWithOptions+ , fold_+ , foldWithOptions_+ , forEach+ , forEach_+ , returning+ , foldWith+ , foldWithOptionsAndParser+ , foldWith_+ , foldWithOptionsAndParser_+ , forEachWith+ , forEachWith_+ , returningWith+ )+where++import Data.Int (Int64)+import qualified Database.PostgreSQL.Simple as PSQL+import qualified Database.PostgreSQL.Simple.FromRow as PSQL+import Bluefin.Eff+import Bluefin.IO+import Bluefin.PostgreSQL.Connection as Conn+import GHC.Stack+#if POOL+import Bluefin.PostgreSQL.Connection.Pool as Pool+#endif++-- | Lifted 'PSQL.query'.+query ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow q, PSQL.FromRow r) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ q ->+ Eff es [r]+query wc ioe q row = withConnection wc $ \conn -> effIO ioe (PSQL.query conn q row)+++-- | Lifted 'PSQL.query_'.+query_ ::+ (HasCallStack, e :> es, e1 :> es, PSQL.FromRow r) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ Eff es [r]+query_ wc ioe row = withConnection wc $ \conn -> effIO ioe (PSQL.query_ conn row)++-- | Lifted 'PSQL.queryWith'.+queryWith ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow q) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.RowParser r ->+ PSQL.Query ->+ q ->+ Eff es [r]+queryWith wc ioe parser q row =+ withConnection wc $ \conn -> effIO ioe (PSQL.queryWith parser conn q row)++-- | Lifted 'PSQL.queryWith_'.+queryWith_ ::+ (HasCallStack, e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.RowParser r ->+ PSQL.Query ->+ Eff es [r]+queryWith_ wc ioe parser row =+ withConnection wc $ \conn -> effIO ioe (PSQL.queryWith_ parser conn row)++-- | Lifted 'PSQL.execute'.+execute ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow q) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ q ->+ Eff es Int64+execute wc ioe q row = withConnection wc $ \conn -> effIO ioe (PSQL.execute conn q row)++-- | Lifted 'PSQL.execute_'.+execute_ ::+ (HasCallStack, e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ Eff es Int64+execute_ wc ioe row = withConnection wc $ \conn -> effIO ioe (PSQL.execute_ conn row)++-- | Lifted 'PSQL.executeMany'.+executeMany ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow q) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ [q] ->+ Eff es Int64+executeMany wc ioe q rows = withConnection wc $ \conn -> effIO ioe (PSQL.executeMany conn q rows)++-- | Lifted 'PSQL.withTransaction'.+withTransaction ::+ (HasCallStack, e :> es, e1 :> es) => + WithConnection e ->+ IOE e1 ->+ Eff es a -> + Eff es a+withTransaction wc ioe f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.withTransaction conn (unlift f)++-- | Lifted 'PSQL.withSavepoint'.+withSavepoint ::+ (HasCallStack, e :> es, e1 :> es) => + WithConnection e ->+ IOE e1 ->+ Eff es a -> Eff es a+withSavepoint wc ioe f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.withSavepoint conn (unlift f)++-- | Lifted 'PSQL.begin'.+begin ::+ (HasCallStack, e :> es, e1 :> es) => + WithConnection e ->+ IOE e1 ->+ Eff es ()+begin wc ioe = withConnection wc $ effIO ioe . PSQL.begin++-- | Lifted 'PSQL.commit'.+commit ::+ (HasCallStack, e :> es, e1 :> es) => + WithConnection e ->+ IOE e1 ->+ Eff es ()+commit wc ioe = withConnection wc $ effIO ioe . PSQL.commit++-- | Lifted 'PSQL.rollback'.+rollback ::+ (HasCallStack, e :> es, e1 :> es) => + WithConnection e ->+ IOE e1 ->+ Eff es ()+rollback wc ioe = withConnection wc $ effIO ioe . PSQL.rollback++(...) :: (a -> b) -> (t1 -> t2 -> a) -> t1 -> t2 -> b+unlift ... f = \a' row -> unlift $ f a' row++unliftWithConn ::+ (HasCallStack, e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ (PSQL.Connection -> (forall b. Eff es b -> IO b) -> IO a) ->+ Eff es a+unliftWithConn wc ioe f =+ withConnection wc $ \conn ->+ withEffToIO_ ioe $ \unlift ->+ f conn unlift+{-# INLINE unliftWithConn #-}++-- | Lifted 'PSQL.fold'.+fold ::+ (HasCallStack, e :> es, e1 :> es, PSQL.FromRow row, PSQL.ToRow params) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ params ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+fold wc ioe q params a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.fold conn q params a (unlift ... f)++-- | Lifted 'PSQL.foldWithOptions'.+foldWithOptions ::+ (HasCallStack, e :> es, e1 :> es, PSQL.FromRow row, PSQL.ToRow params) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.FoldOptions ->+ PSQL.Query ->+ params ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+foldWithOptions wc ioe opts q params a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.foldWithOptions opts conn q params a (unlift ... f)++-- | Lifted 'PSQL.fold_'.+fold_ ::+ (HasCallStack, e :> es, e1 :> es, PSQL.FromRow row) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+fold_ wc ioe q a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.fold_ conn q a (unlift ... f)++-- | Lifted 'PSQL.foldWithOptions_'.+foldWithOptions_ ::+ (HasCallStack, e :> es, e1 :> es, PSQL.FromRow row) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.FoldOptions ->+ PSQL.Query ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+foldWithOptions_ wc ioe opts q a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.foldWithOptions_ opts conn q a (unlift ... f)++-- | Lifted 'PSQL.forEach'.+forEach ::+ (HasCallStack, e :> es, e1 :> es, PSQL.FromRow r, PSQL.ToRow q) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ q ->+ (r -> Eff es ()) ->+ Eff es ()+forEach wc ioe q row forR =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.forEach conn q row (unlift . forR)++-- | Lifted 'PSQL.forEach_'.+forEach_ ::+ (HasCallStack, e :> es, e1 :> es, PSQL.FromRow r) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ (r -> Eff es ()) ->+ Eff es ()+forEach_ wc ioe q forR =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.forEach_ conn q (unlift . forR)++-- | Lifted 'PSQL.returning'.+returning ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow q, PSQL.FromRow r) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.Query ->+ [q] ->+ Eff es [r]+returning wc ioe q rows = withConnection wc $ \conn -> effIO ioe $ PSQL.returning conn q rows++-- | Lifted 'PSQL.foldWith'.+foldWith ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow params) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.RowParser row ->+ PSQL.Query ->+ params ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+foldWith wc ioe parser q params a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.foldWith parser conn q params a (unlift ... f)++-- | Lifted 'PSQL.foldWithOptionsAndParser'.+foldWithOptionsAndParser ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow params) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.FoldOptions ->+ PSQL.RowParser row ->+ PSQL.Query ->+ params ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+foldWithOptionsAndParser wc ioe opts parser q params a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.foldWithOptionsAndParser opts parser conn q params a (unlift ... f)++-- | Lifted 'PSQL.foldWith_'.+foldWith_ ::+ (HasCallStack, e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.RowParser row ->+ PSQL.Query ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+foldWith_ wc ioe parser q a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.foldWith_ parser conn q a (unlift ... f)++-- | Lifted 'PSQL.foldWithOptionsAndParser_'.+foldWithOptionsAndParser_ ::+ (HasCallStack, e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.FoldOptions ->+ PSQL.RowParser row ->+ PSQL.Query ->+ a ->+ (a -> row -> Eff es a) ->+ Eff es a+foldWithOptionsAndParser_ wc ioe opts parser q a f =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.foldWithOptionsAndParser_ opts parser conn q a (unlift ... f)++-- | Lifted 'PSQL.forEachWith'.+forEachWith ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow q) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.RowParser r ->+ PSQL.Query ->+ q ->+ (r -> Eff es ()) ->+ Eff es ()+forEachWith wc ioe parser q row forR =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.forEachWith parser conn q row (unlift . forR)++-- | Lifted 'PSQL.forEachWith_'.+forEachWith_ ::+ (HasCallStack, e :> es, e1 :> es) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.RowParser r ->+ PSQL.Query ->+ (r -> Eff es ()) ->+ Eff es ()+forEachWith_ wc ioe parser row forR =+ unliftWithConn wc ioe $ \conn unlift ->+ PSQL.forEachWith_ parser conn row (unlift . forR)++-- | Lifted 'PSQL.returningWith'.+returningWith ::+ (HasCallStack, e :> es, e1 :> es, PSQL.ToRow q) =>+ WithConnection e ->+ IOE e1 ->+ PSQL.RowParser r ->+ PSQL.Query ->+ [q] ->+ Eff es [r]+returningWith wc ioe parser q rows =+ withConnection wc $ \conn -> effIO ioe $ PSQL.returningWith parser conn q rows
+ src/Bluefin/PostgreSQL/Connection.hs view
@@ -0,0 +1,74 @@+module Bluefin.PostgreSQL.Connection+ ( -- * Effect+ WithConnection (..)+ , withConnection++ -- * Interpret with a single Connection+ , runWithConnection+ , runWithConnectInfo+ )+where++import Bluefin.Compound+import Bluefin.Eff+import Bluefin.IO+import qualified Database.PostgreSQL.Simple as PSQL+import GHC.Stack++{- | A dynamic effect that lets us use a database 'PSQL.Connection',+without specifying __how__ that connection is supplied.++For example, we might want to just provide a connection and let the interpreter+use that for the whole procedure (see 'Bluefin.PostgreSQL.Connection.runWithConnection').++Or, we might want to create a connection pool which provides connections when+the interpreter asks for them (see "Bluefin.PostgreSQL.Connection.Pool").+-}+newtype WithConnection (e :: Effects) = MkWithConnection+ { withConnectionImpl :: forall e' a. (PSQL.Connection -> Eff e' a) -> Eff (e' :& e) a+ -- ^ Use a 'PSQL.Connection' provided by an interpreter.+ }++instance Handle WithConnection where+ mapHandle h =+ MkWithConnection+ { withConnectionImpl = useImplUnder . withConnectionImpl h+ }++-- | Use a 'PSQL.Connection' provided by an interpreter.+withConnection :: (e :> es) => WithConnection e -> (PSQL.Connection -> Eff es a) -> Eff es a+withConnection w f = makeOp (withConnectionImpl (mapHandle w) f)++{- | Run a t'WithConnection' effect by simply supplying a 'PSQL.Connection'.+The connection will be kept alive for the whole duration of the procedure,+which might not be want you want for long-running processes. If so, see+"Bluefin.PostgreSQL.Connection.Pool".+-}+runWithConnection ::+ PSQL.Connection ->+ (forall e. WithConnection e -> Eff (e :& es) a) ->+ Eff es a+runWithConnection conn k =+ useImplIn+ k+ MkWithConnection+ { withConnectionImpl = \f -> useImpl (f conn)+ }++{- | Run a t'WithConnection' effect using a 'PSQL.ConnectInfo'.+The 'PSQL.ConnectInfo' will be used to create a 'PSQL.Connection' which will be+kept alive for the whole duration of the procedure, which might not be want you want+for long-running processes. If so, see "Bluefin.PostgreSQL.Connection.Pool".++'PSQL.withConnect' will handle opening and closing the 'PSQL.Connection'.+-}+runWithConnectInfo ::+ (HasCallStack, e1 :> es) =>+ IOE e1 ->+ PSQL.ConnectInfo ->+ (forall e. WithConnection e -> Eff (e :& es) a) ->+ Eff es a+runWithConnectInfo ioe connInfo k =+ withEffToIO_ ioe $ \unlift ->+ PSQL.withConnect connInfo $ \conn ->+ unlift $ runWithConnection conn k
+ src/Bluefin/PostgreSQL/Connection/Pool.hs view
@@ -0,0 +1,37 @@+module Bluefin.PostgreSQL.Connection.Pool+ ( -- * Interpret with a Connection pool+ runWithConnectionPool++ -- * Re-export+ , module Pool+ )+where++import Bluefin.Compound+import Bluefin.Eff+import Bluefin.IO+import Bluefin.PostgreSQL.Connection+import qualified Database.PostgreSQL.Simple as PSQL+import GHC.Stack+import UnliftIO.Pool as Pool++{- | Rather than keeping one connection alive and re-using it for the whole+process, we might want to create a 'Pool' of connections and only "ask" for+one when we need it. This function uses "UnliftIO.Pool" to do just that.+-}+runWithConnectionPool ::+ (HasCallStack, e1 :> es) =>+ IOE e1 ->+ Pool.Pool PSQL.Connection ->+ (forall e. WithConnection e -> Eff (e :& es) a) ->+ Eff es a+runWithConnectionPool ioe pool k =+ useImplIn+ k+ MkWithConnection+ { withConnectionImpl = \f ->+ runEffReader ioe $+ Pool.withResource pool $+ \conn -> effReader $+ \_ -> useImpl (f conn)+ }