@@ -8,8 +8,13 @@ Stability: experimental
88This module defines a `Migration` type to safely
99change the schema of your database over time. Let's see an example!
1010
11+First turn on some extensions.
12+
1113>>> :set -XDataKinds -XOverloadedLabels
1214>>> :set -XOverloadedStrings -XFlexibleContexts -XTypeOperators
15+
16+Next, let's define our `TableType`s.
17+
1318>>> :{
1419type UsersTable =
1520 '[ "pk_users" ::: 'PrimaryKey '["id"] ] :=>
@@ -20,7 +25,7 @@ type UsersTable =
2025
2126>>> :{
2227type EmailsTable =
23− '[ "pk_emails" ::: 'PrimaryKey '["id"]
28+ '[ "pk_emails" ::: 'PrimaryKey '["id"]
2429 , "fk_user_id" ::: 'ForeignKey '["user_id"] "users" '["id"]
2530 ] :=>
2631 '[ "id" ::: 'Def :=> 'NotNull 'PGint4
@@ -29,6 +34,8 @@ type EmailsTable =
2934 ]
3035:}
3136
37+Now we can define some `Migration`s to make our tables.
38+
3239>>> :{
3340let
3441 makeUsers :: Migration Definition (Public '[]) '["public" ::: '["users" ::: 'Table UsersTable]]
@@ -36,7 +43,7 @@ let
3643 { name = "make users table"
3744 , up = createTable #users
3845 ( serial `as` #id :*
39− (text & notNullable) `as` #name )
46+ notNullable text `as` #name )
4047 ( primaryKey #id `as` #pk_users )
4148 , down = dropTable #users
4249 }
@@ -50,8 +57,8 @@ let
5057 { name = "make emails table"
5158 , up = createTable #emails
5259 ( serial `as` #id :*
53− (int & notNullable) `as` #user_id :*
54− (text & nullable) `as` #email )
60+ notNullable int `as` #user_id :*
61+ nullable text `as` #email )
5562 ( primaryKey #id `as` #pk_emails :*
5663 foreignKey #user_id #users #id
5764 OnDeleteCascade OnUpdateCascade `as` #fk_user_id )
@@ -59,20 +66,11 @@ let
5966 }
6067:}
6168
62−Now that we have a couple migrations we can chain them together.
69+Now that we have a couple migrations we can chain them together into an `AlignedList`.
6370
6471>>> let migrations = makeUsers :>> makeEmails :>> Done
6572
66−>>> :{
67−let
68− numMigrations
69− :: Has "migrations" schemas MigrationsSchema
70− => PQ schemas schemas IO ()
71− numMigrations = do
72− result <- runQuery (select Star (from (table (#migrations ! #schema_migrations `as` #m))))
73− num <- ntuples result
74− liftIO $ print num
75−:}
73+Now run the migrations.
7674
7775>>> import Control.Monad.IO.Class
7876>>> :{
@@ -117,6 +115,10 @@ Migrations already run:
117115Migrations left to run:
118116 - make users table
119117 - make emails table
118+
119+In addition to enabling `Migration`s using pure SQL `Definition`s for
120+the `up` and `down` instructions, you can also perform impure `IO` actions
121+by using a `Migration`s over the `Terminally` `PQ` `IO` category.
120122-}
121123{-# LANGUAGE
122124 DataKinds
@@ -206,9 +208,9 @@ instance Migratory Definition where
206208 migrateUp = migrateUp . alignedMap pureMigration
207209 migrateDown = migrateDown . alignedMap pureMigration
208210
209−{- | `Terminally` turns an indexed monad transformer into a category by
210−restricting the return type to `()` and permuting the type variables.
211−This is similar to how applying a monad to `()` yields a monoid.
211+{- | `Terminally` turns an indexed monad transformer and the monad it transforms
212+into a category by restricting the return type to @()@ and permuting the type variables.
213+This is similar to how applying a monad to @()@ yields a monoid.
212214Since a `Terminally` action has a trivial return value, the only reason
213215to run one is for the side effects, in particular database effects.
214216-}
@@ -224,8 +226,9 @@ instance
224226 id = Terminally (return ())
225227 Terminally g . Terminally f = Terminally $ pqThen g f
226228
227−-- | terminally ignores the output of a computation, returning `()` and
228−-- wrapping it up in a `Terminally`.
229+-- | `terminally` ignores the output of a computation, returning @()@ and
230+-- wrapping it up into a `Terminally`. You can lift an action in the base monad
231+-- by using @terminally . lift@.
229232terminally
230233 :: Functor (trans x0 x1 monad)
231234 => trans x0 x1 monad ignore