@@ -1,51 +1,119 @@
1{-# LANGUAGE
1{-# LANGUAGE
2 ScopedTypeVariables
2 ScopedTypeVariables
3 , OverloadedStrings
3 , OverloadedStrings
6module Squeal.PostgreSQL.Migration
13module Squeal.PostgreSQL.Migration
7− ( Migration
14+ ( Migration (..)
9− , MigrationResult
16+ , skip
12import Control.Category
22import Control.Category
13−import Control.Exception.Lifted
14import Control.Monad
23import Control.Monad
24+import Control.Monad.Base
25+import Control.Monad.Trans.Control
15import Data.Function ((&))
26import Data.Function ((&))
17import Prelude hiding (id, (.))
27import Prelude hiding (id, (.))
19−import qualified Database.PostgreSQL.LibPQ as LibPQ
29+import Squeal.PostgreSQL.Definition
20−
30+import Squeal.PostgreSQL.Expression
31+import Squeal.PostgreSQL.Manipulation
21import Squeal.PostgreSQL.PQ
32import Squeal.PostgreSQL.PQ
33+import Squeal.PostgreSQL.Schema
22import Squeal.PostgreSQL.Transaction
34import Squeal.PostgreSQL.Transaction
24−data Migration schema0 schema1 = Migration
36+data Step io schema0 schema1 = Step
25− { migrateUp :: PQ schema0 schema1 IO MigrationResult
37+ { up :: PQ schema0 schema1 io ()
26− , migrateDown :: PQ schema1 schema0 IO MigrationResult
38+ , down :: PQ schema1 schema0 io ()
41+skip :: Monad io => Step io schema schema -> Step io schema schema
42+skip _ = Step (return ()) (return ())
44+data Migration io schema0 schema1 where
45+ Done :: Migration io schema schema
47+ :: Step io schema0 schema1
48+ -> Migration io schema1 schema2
49+ -> Migration io schema0 schema2
29−instance Category Migration where
51+instance Category (Migration io) where
30− id = Migration (return MigrationSuccess) (return MigrationSuccess)
52+ id = Done
31− migration1 . migration0 = Migration
53+ (.) migration = \case
32− { migrateUp = migrateUp migration0 & pqThen (migrateUp migration1)
54+ Done -> migration
33− , migrateDown = migrateDown migration1 & pqThen (migrateDown migration0)
55+ step :>> steps -> step :>> (steps >>> migration)
36−up
58+ :: MonadBaseControl IO io
37− :: Migration schema0 schema1
59+ => Migration io schema0 schema1
38− -> K Connection schema0
60+ -> PQ schema0 schema1 io ()
39− -> IO (K MigrationResult schema1)
61+migrateUp migration = start & pqThen (upSteps migration & pqBind end)
40−up (Migration mUp _) = runPQ $
62+
64+ :: MonadBaseControl IO io
65+ => Migration io schema0 schema1
66+ -> PQ schema1 schema0 io ()
67+migrateDown migration = start & pqThen (downSteps migration & pqBind end)
69+type MigrationTable = "schema_migrations" :::
70+ '[ "unique_name" ::: 'Unique '["name"]] :=>
71+ '[ "name" ::: 'NoDef :=> 'NotNull 'PGtext
72+ , "executed_at" ::: 'Def :=> 'NotNull 'PGtimestamptz
75+createMigrations :: Definition '[] '[MigrationTable]
76+createMigrations = UnsafeDefinition $ renderDefinition $
77+ createTableIfNotExists #schema_migrations
78+ ( (text & notNull) `As` #name :*
79+ (timestampWithTimeZone & notNull) `As` #executed_at :* Nil )
80+ ( unique (Column #name :* Nil) `As` #unique_name :* Nil )
82+insertMigration :: Manipulation '[MigrationTable] '[ 'NotNull 'PGtext] '[]
83+insertMigration = insertRow_ #schema_migrations
84+ ( Set (param @1) `As` #name :*
85+ Default `As` #executed_at :* Nil )
87+deleteMigration :: Manipulation '[MigrationTable] '[ 'NotNull 'PGtext] '[]
88+deleteMigration = deleteFrom_ #schema_migrations (#name .== param @1)
90+start :: MonadBase IO io => PQ schema schema io ()
91+start = define createMigrations_
41− begin (TransactionMode RepeatableRead ReadWrite)
92+ & pqThen (begin (TransactionMode RepeatableRead ReadWrite) & void)
42− & pqThen (restorably mUp)
43− & pqBind ( \ result ->
44− commit >> return result
47− restorably u = PQ $ \ conn -> mask $ \ restore ->
94+ createMigrations_ :: Definition schema schema
48− restore (runPQ u conn) `onException` LibPQ.exec (unK conn) "ROLLBACK"
95+ createMigrations_ = UnsafeDefinition $
96+ renderDefinition createMigrations
99+ :: MonadBaseControl IO io
100+ => Migration io schema0 schema1
101+ -> PQ schema0 schema1 io ()
105+ onExceptionRollback (up step)
106+ & pqThen (upSteps steps)
109+ :: MonadBaseControl IO io
110+ => Migration io schema0 schema1
111+ -> PQ schema1 schema0 io ()
116+ & pqThen (onExceptionRollback (down step))
50−data MigrationResult
118+end :: MonadBase IO io => result -> PQ schema schema io result
51− = MigrationSuccess
119+end result = commit >> return result