Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions effectful-postgresql/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
38 changes: 23 additions & 15 deletions effectful-postgresql/README.md
Original file line number Diff line number Diff line change
@@ -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).

Expand All @@ -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"]
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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
```
1 change: 1 addition & 0 deletions effectful-postgresql/effectful-postgresql.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ library
, extensions
exposed-modules:
Effectful.PostgreSQL
Effectful.PostgreSQL.Effect
Effectful.PostgreSQL.Connection
if flag(enable-pool)
exposed-modules:
Expand Down
Loading
Loading