Hacking Persistent
August 2, 2015I’m a big fan of persistent
as it offers compile time integrity checks for your database.
Whenever I need to model a new schema, I usually use this tool to come
up with the design. As I model and typecheck the code, I usually use
the printMigration
function to see the translated SQL queries. The
code looks something like this:
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Logger (runStderrLoggingT)
import Database.Persist
import Database.Persist.Postgresql
import Database.Persist.TH
"migrateAll"]
share [mkPersist sqlSettings, mkMigrate
[persistLowerCase|
Person
name String
age Int Maybe
address Int
deriving Show
BlogPost
title String
authorId PersonId
deriving Show
|]
= "host=localhost dbname=test user=test password=test port=5432"
connStr
main :: IO ()
= runStderrLoggingT $ withPostgresqlPool connStr 10 $
main -> liftIO $ do
\pool flip runSqlPersistMPool pool $ do
printMigration migrateAll
But there is a slight problem with this code. For the program to
run successfully, It needs an actual database to be present in the
system. With that being in mind, I filed an
issue hoping
it would be fixed. After around 10 months and with a little push from
Michael Snoyman,
I finally started working on the patch. As I studied the code, I sent
a series
of
cleanup
patches. Finally I
figured out the problem with the actual issue and wrote a patch
for
PostgreSQL driver
for it. Right now it is merged and lives in the master. So for the
above code to run properly without the actual database being present,
make use of the mockMigration
function:
main :: IO ()
= mockMigration migrateAll main
And that will print the migration for your designed database. And today I have sent a pull request for the MySQL backend. Once it gets merged, you can also use this functionality for designing schemas using MySQL too. And yes, this is the first time I’m doing the development of Haskell packages using Nix.