Skip to content
This repository was archived by the owner on Sep 20, 2021. It is now read-only.

Commit cc24ac6

Browse files
committed
Better transaction handling in the standalone binary and more documentation
1 parent 7263533 commit cc24ac6

File tree

5 files changed

+38
-22
lines changed

5 files changed

+38
-22
lines changed

Readme.markdown

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,8 @@ main :: IO ()
7272
main = do
7373
let url = "host=$host dbname=$db user=$user password=$pw"
7474
con <- connectPostgreSQL (BS8.pack url)
75-
void $ runMigration $ MigrationContext MigrationInitialization True con
75+
withTransaction con $ runMigration $
76+
MigrationContext MigrationInitialization True con
7677
```
7778

7879
For file-based migrations, the following snippet can be used:
@@ -83,7 +84,8 @@ main = do
8384
let url = "host=$host dbname=$db user=$user password=$pw"
8485
let dir = "."
8586
con <- connectPostgreSQL (BS8.pack url)
86-
void $ runMigration $ MigrationContext (MigrationDirectory dir) True con
87+
withTransaction con $ runMigration $
88+
MigrationContext (MigrationDirectory dir) True con
8789
```
8890

8991
To run Haskell-based migrations, use this:
@@ -95,8 +97,8 @@ main = do
9597
let name = "my script"
9698
let script = "create table users (email varchar not null)";
9799
con <- connectPostgreSQL (BS8.pack url)
98-
void $ runMigration $ MigrationContext
99-
(MigrationScript name script) True con
100+
withTransaction con $ runMigration $
101+
MigrationContext (MigrationScript name script) True con
100102
```
101103

102104
Validations wrap _MigrationCommands_. This means that you can re-use all
@@ -110,10 +112,21 @@ main :: IO ()
110112
main = do
111113
let url = "host=$host dbname=$db user=$user password=$pw"
112114
con <- connectPostgreSQL (BS8.pack url)
113-
void $ runMigration $ MigrationContext
114-
(MigrationValidation (MigrationDirectory dir)) verbose con
115+
withTransaction con $ runMigration $ MigrationContext
116+
(MigrationValidation (MigrationDirectory dir)) True con
115117
```
116118

119+
Database migrations should always be performed in a transactional context.
120+
121+
The standalone binary takes care of proper transaction handling automatically.
122+
123+
The library does not make any assumptions about the current transactional state
124+
of the system. This way you can execute multiple migration-commands or
125+
validations in sequence while still staying in the same transaction.
126+
127+
The tests work in a similar way. After executing all migration-tests, the
128+
transaction is rolled back.
129+
117130
## Compilation and Tests
118131
The program is built with the _cabal_ build system. The following command
119132
builds the library, the standalone binary and the test package.

src/Database/PostgreSQL/Simple/Migration.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ import Database.PostgreSQL.Simple.Util (existsTable)
4949
import System.Directory (getDirectoryContents)
5050

5151
-- | Executes migrations inside the provided 'MigrationContext'.
52-
--
52+
--
5353
-- Returns 'MigrationSuccess' if the provided 'MigrationCommand' executes
5454
-- without error. If an error occurs, execution is stopped and
5555
-- a 'MigrationError' is returned.

src/Database/PostgreSQL/Simple/Util.hs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,23 @@
1111

1212
module Database.PostgreSQL.Simple.Util
1313
( existsTable
14+
, withTransactionRolledBack
1415
) where
1516

17+
import Control.Exception (finally)
1618
import Control.Monad (liftM)
17-
import Database.PostgreSQL.Simple (Connection, Only (..), query)
19+
import Database.PostgreSQL.Simple (Connection, Only (..), begin,
20+
query, rollback)
1821

1922
-- | Checks if the table with the given name exists in the database.
2023
existsTable :: Connection -> String -> IO Bool
2124
existsTable con table =
2225
liftM (not . null) (query con q (Only table) :: IO [[Int]])
2326
where
2427
q = "select count(relname) from pg_class where relname = ?"
28+
29+
-- | Executes the given IO monad inside a transaction and performs a roll-back
30+
-- afterwards (even if exceptions occur).
31+
withTransactionRolledBack :: Connection -> IO a -> IO a
32+
withTransactionRolledBack con f =
33+
begin con >> finally f (rollback con)

src/Main.hs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ module Main (
1515

1616
import Control.Monad (void)
1717
import qualified Data.ByteString.Char8 as BS8 (pack)
18-
import Database.PostgreSQL.Simple (connectPostgreSQL)
18+
import Database.PostgreSQL.Simple (connectPostgreSQL,
19+
withTransaction)
1920
import Database.PostgreSQL.Simple.Migration (MigrationCommand (..),
2021
MigrationContext (..),
2122
runMigration)
@@ -37,15 +38,15 @@ run (Just cmd) verbose =
3738
void $ case cmd of
3839
Initialize url -> do
3940
con <- connectPostgreSQL (BS8.pack url)
40-
runMigration $ MigrationContext
41+
withTransaction con $ runMigration $ MigrationContext
4142
MigrationInitialization verbose con
4243
Migrate url dir -> do
4344
con <- connectPostgreSQL (BS8.pack url)
44-
runMigration $ MigrationContext
45+
withTransaction con $ runMigration $ MigrationContext
4546
(MigrationDirectory dir) verbose con
4647
Validate url dir -> do
4748
con <- connectPostgreSQL (BS8.pack url)
48-
runMigration $ MigrationContext
49+
withTransaction con $ runMigration $ MigrationContext
4950
(MigrationValidation (MigrationDirectory dir)) verbose con
5051

5152
parseCommand :: [String] -> Maybe Command

test/Main.hs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,12 @@ module Main
1313
( main
1414
) where
1515

16-
import Control.Exception (finally)
17-
import Database.PostgreSQL.Simple (begin,
18-
connectPostgreSQL,
19-
rollback)
16+
import Database.PostgreSQL.Simple (connectPostgreSQL)
2017
import Database.PostgreSQL.Simple.MigrationTest (migrationSpec)
18+
import Database.PostgreSQL.Simple.Util (withTransactionRolledBack)
2119
import Test.Hspec (hspec)
2220

2321
main :: IO ()
2422
main = do
2523
con <- connectPostgreSQL "dbname=test"
26-
begin con
27-
finally
28-
(hspec (migrationSpec con))
29-
(rollback con)
30-
31-
24+
withTransactionRolledBack con (hspec (migrationSpec con))

0 commit comments

Comments
 (0)