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

Commit 22cd5c5

Browse files
authored
Merge pull request #16 from expipiplus1/monoid
Monoid
2 parents f249619 + 5acb8fd commit 22cd5c5

File tree

1 file changed

+50
-17
lines changed

1 file changed

+50
-17
lines changed

src/Database/PostgreSQL/Simple/Migration.hs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ module Database.PostgreSQL.Simple.Migration
2222
(
2323
-- * Migration actions
2424
runMigration
25+
, runMigrations
26+
, sequenceMigrations
2527

2628
-- * Migration types
2729
, MigrationContext(..)
@@ -48,7 +50,7 @@ import Data.Foldable (Foldable)
4850
import Data.Traversable (Traversable)
4951
import Data.List (isPrefixOf, sort)
5052
#if __GLASGOW_HASKELL__ < 710
51-
import Data.Monoid (mconcat)
53+
import Data.Monoid (Monoid (..))
5254
#endif
5355
import Data.Time (LocalTime)
5456
import Database.PostgreSQL.Simple (Connection, Only (..),
@@ -73,28 +75,52 @@ runMigration (MigrationContext cmd verbose con) = case cmd of
7375
MigrationInitialization ->
7476
initializeSchema con verbose >> return MigrationSuccess
7577
MigrationDirectory path ->
76-
executeDirectoryMigration con verbose path
78+
executeDirectoryMigration con verbose path
7779
MigrationScript name contents ->
7880
executeMigration con verbose name contents
7981
MigrationFile name path ->
8082
executeMigration con verbose name =<< BS.readFile path
8183
MigrationValidation validationCmd ->
8284
executeValidation con verbose validationCmd
85+
MigrationCommands commands ->
86+
runMigrations verbose con commands
87+
88+
-- | Execute a sequence of migrations
89+
--
90+
-- Returns 'MigrationSuccess' if all of the provided 'MigrationCommand's
91+
-- execute without error. If an error occurs, execution is stopped and the
92+
-- 'MigrationError' is returned.
93+
--
94+
-- It is recommended to wrap 'runMigrations' inside a database transaction.
95+
runMigrations
96+
:: Bool
97+
-- ^ Run in verbose mode
98+
-> Connection
99+
-- ^ The postgres connection to use
100+
-> [MigrationCommand]
101+
-- ^ The commands to run
102+
-> IO (MigrationResult String)
103+
runMigrations verbose con commands =
104+
sequenceMigrations [runMigration (MigrationContext c verbose con) | c <- commands]
105+
106+
-- | Run a sequence of contexts, stopping on the first failure
107+
sequenceMigrations :: Monad m => [m (MigrationResult e)] -> m (MigrationResult e)
108+
sequenceMigrations = \case
109+
[] -> return MigrationSuccess
110+
c:cs -> do
111+
r <- c
112+
case r of
113+
MigrationError s -> return (MigrationError s)
114+
MigrationSuccess -> sequenceMigrations cs
83115

84116
-- | Executes all SQL-file based migrations located in the provided 'dir'
85117
-- in alphabetical order.
86118
executeDirectoryMigration :: Connection -> Bool -> FilePath -> IO (MigrationResult String)
87119
executeDirectoryMigration con verbose dir =
88120
scriptsInDirectory dir >>= go
89121
where
90-
go [] = return MigrationSuccess
91-
go (f:fs) = do
92-
r <- executeMigration con verbose f =<< BS.readFile (dir ++ "/" ++ f)
93-
case r of
94-
MigrationError _ ->
95-
return r
96-
MigrationSuccess ->
97-
go fs
122+
go fs = sequenceMigrations (executeMigrationFile <$> fs)
123+
executeMigrationFile f = executeMigration con verbose f =<< BS.readFile (dir ++ "/" ++ f)
98124

99125
-- | Lists all files in the given 'FilePath' 'dir' in alphabetical order.
100126
scriptsInDirectory :: FilePath -> IO [String]
@@ -145,6 +171,7 @@ initializeSchema con verbose = do
145171
-- * 'MigrationScript': validate the presence and checksum of the given script.
146172
-- * 'MigrationFile': validate the presence and checksum of the given file.
147173
-- * 'MigrationValidation': always succeeds.
174+
-- * 'MigrationCommands': validates all the sub-commands stopping at the first failure.
148175
executeValidation :: Connection -> Bool -> MigrationCommand -> IO (MigrationResult String)
149176
executeValidation con verbose cmd = case cmd of
150177
MigrationInitialization ->
@@ -159,6 +186,8 @@ executeValidation con verbose cmd = case cmd of
159186
validate name =<< BS.readFile path
160187
MigrationValidation _ ->
161188
return MigrationSuccess
189+
MigrationCommands cs ->
190+
sequenceMigrations (executeValidation con verbose <$> cs)
162191
where
163192
validate name contents =
164193
checkScript con name (md5Hash contents) >>= \case
@@ -172,13 +201,8 @@ executeValidation con verbose cmd = case cmd of
172201
when verbose $ putStrLn $ "Checksum mismatch:\t" ++ name
173202
return (MigrationError $ "Checksum mismatch: " ++ name)
174203

175-
goScripts _ [] = return MigrationSuccess
176-
goScripts path (x:xs) =
177-
(validate x =<< BS.readFile (path ++ "/" ++ x)) >>= \case
178-
e@(MigrationError _) ->
179-
return e
180-
MigrationSuccess ->
181-
goScripts path xs
204+
goScripts path xs = sequenceMigrations (goScript path <$> xs)
205+
goScript path x = validate x =<< BS.readFile (path ++ "/" ++ x)
182206

183207
-- | Checks the status of the script with the given name 'name'.
184208
-- If the script has already been executed, the checksum of the script
@@ -227,8 +251,17 @@ data MigrationCommand
227251
-- ^ Executes a migration based on the provided bytestring.
228252
| MigrationValidation MigrationCommand
229253
-- ^ Validates the provided MigrationCommand.
254+
| MigrationCommands [MigrationCommand]
255+
-- ^ Performs a series of 'MigrationCommand's in sequence.
230256
deriving (Show, Eq, Read, Ord)
231257

258+
instance Monoid MigrationCommand where
259+
mempty = MigrationCommands []
260+
mappend (MigrationCommands xs) (MigrationCommands ys) = MigrationCommands (xs ++ ys)
261+
mappend (MigrationCommands xs) y = MigrationCommands (xs ++ [y])
262+
mappend x (MigrationCommands ys) = MigrationCommands (x : ys)
263+
mappend x y = MigrationCommands [x, y]
264+
232265
-- | A sum-type denoting the result of a single migration.
233266
data CheckScriptResult
234267
= ScriptOk

0 commit comments

Comments
 (0)