tmp-postgres 1.16.1.0 → 1.17.0.0
raw patch · 10 files changed
+269/−84 lines, 10 files
Files
- CHANGELOG.md +5/−0
- README.md +1/−1
- benchmark/Main.hs +54/−7
- src/Database/Postgres/Temp.hs +11/−6
- src/Database/Postgres/Temp/Config.hs +2/−0
- src/Database/Postgres/Temp/Internal.hs +88/−3
- src/Database/Postgres/Temp/Internal/Config.hs +78/−20
- src/Database/Postgres/Temp/Internal/Core.hs +6/−0
- test/Main.hs +22/−46
- tmp-postgres.cabal +2/−1
CHANGELOG.md view
@@ -1,5 +1,10 @@ Changelog for tmp-postgres +1.7.0.0+ #156 Deprecate `NewDb` functions.+ #155 Better monoids for `initDbConfig` and `createDbConfig`.+ #142 Cluster save points.+ 1.16.1.0 #152 Add stopPostgresGracefully function.
README.md view
@@ -40,7 +40,7 @@ WARNING!! Ubuntu's PostgreSQL installation does not put `initdb` on the `PATH`. We need to add it manually.-The necessary binaries are in the `\/usr\/lib\/postgresql\/VERSION\/bin\/` directory, and should be added to the `PATH`+The necessary binaries are in the `/usr/lib/postgresql/VERSION/bin/` directory, and should be added to the `PATH` > echo "export PATH=$PATH:/usr/lib/postgresql/VERSION/bin/" >> /home/ubuntu/.bashrc
benchmark/Main.hs view
@@ -1,18 +1,23 @@ module Main where+import Control.DeepSeq import Control.Exception-import Control.Monad (void, replicateM)+import Control.Monad import Criterion.Main import Data.String import Database.Postgres.Temp.Internal import Database.Postgres.Temp.Internal.Config import qualified Database.PostgreSQL.Simple as PG +data Once a = Once { unOnce :: a }++instance NFData (Once a) where+ rnf x = seq x ()+ defaultConfigDefaultInitDb :: Config defaultConfigDefaultInitDb = mempty { plan = mempty { logger = pure mempty , postgresConfigFile = defaultPostgresConfig- , createDbConfig = Nothing , initDbConfig = pure mempty } }@@ -48,11 +53,35 @@ setupWithCache :: (Config -> Benchmark) -> Benchmark setupWithCache f = envWithCleanup setupCache cleanupInitDbCache $ f . (silentConfig <>) . toCacheConfig +setupCacheAndSP :: IO ((Bool, CompleteDirectoryType), CompleteDirectoryType, Once Config)+setupCacheAndSP = do+ cacheInfo <- setupCache+ let cacheConfig = silentConfig <> toCacheConfig cacheInfo+ sp <- either throwIO pure <=< withConfig cacheConfig $ \db -> do+ migrateDb db+ either throwIO pure =<< takeSnapshot Temporary db++ snapshotConfig <- (silentConfig <>)+ <$> configFromSavePoint (toFilePath sp)+ let theConfig = snapshotConfig <> cacheConfig++ pure (cacheInfo, sp, Once theConfig)++cleanupCacheAndSP :: ((Bool, CompleteDirectoryType), CompleteDirectoryType, Once Config) -> IO ()+cleanupCacheAndSP (x, y, _) = cleanupSnapshot y >> cleanupInitDbCache x++setupWithCacheAndSP :: (Config -> Benchmark) -> Benchmark+setupWithCacheAndSP f = envWithCleanup setupCacheAndSP cleanupCacheAndSP $ \ ~(_, _, Once x) -> f x++setupWithCacheAndSP' :: (CompleteDirectoryType -> Benchmark) -> Benchmark+setupWithCacheAndSP' f = envWithCleanup setupCacheAndSP cleanupCacheAndSP $ \ ~(_, x, _) -> f x+ main :: IO () main = defaultMain [ --bench "with" $ whnfIO $ with $ const $ pure () --, bench "withConfig no --no-sync" $ whnfIO $ -- withConfig defaultConfigDefaultInitDb $ const $ pure ()+{- bench "withConfig silent" $ whnfIO $ withConfig silentConfig $ const $ pure () @@ -65,14 +94,32 @@ , bench "withNewDb migrate 10x" $ whnfIO $ withConfig silentConfig $ \db -> do migrateDb db replicateM 10 $ withNewDb db testQuery+-}+ setupWithCache $ \cacheConfig -> bench "withNewDbConfig migrate 10x and cache" $ whnfIO $ withConfig cacheConfig+ $ \db -> do+ migrateDb db+ replicateM 10 $ withNewDb db testQuery - , setupWithCache $ \cacheConfig -> do+ , setupWithCache $ \cacheConfig -> do bench "with migrate 10x and cache" $ whnfIO $ withConfig cacheConfig $ \_ -> do- replicateM 10 $ withConfig cacheConfig $ \db ->+ replicateM_ 10 $ withConfig cacheConfig $ \db -> migrateDb db >> testQuery db - , setupWithCache $ \cacheConfig -> bench "withNewDbConfig migrate 10x and cache" $ whnfIO $ withConfig cacheConfig- $ \db -> do+ , setupWithCache $ \cacheConfig -> bench "withSnapshot migrate 10x and cache" $ whnfIO $ withConfig cacheConfig $ \db -> do migrateDb db- replicateM 10 $ withNewDb db testQuery+ void $ withSnapshot Temporary db $ \snapshotDir -> do+ snapshotConfig <- (silentConfig <>) <$> configFromSavePoint (toFilePath snapshotDir)+ replicateM_ 10 $ withConfig snapshotConfig testQuery+{-+ , setupWithCacheAndSP $ \theConfig -> bench "withConfig pre-setup with withSnapshot" $ whnfIO $+ void $ withConfig theConfig $ const $ pure ()++ , setupWithCacheAndSP' $ \sp -> bench "configFromSavePoint" $ whnfIO $ void $ configFromSavePoint $ toFilePath sp++ , bench "migrateDb" $ perRunEnvWithCleanup (either throwIO (pure . Once) =<< startConfig silentConfig) (stop . unOnce) $+ \ ~(Once db) -> migrateDb db+-}+ , bench "withSnapshot" $ perRunEnvWithCleanup (either throwIO (pure . Once) =<< startConfig silentConfig) (stop . unOnce) $+ \ ~(Once db) -> void $ withSnapshot Temporary db $ const $ pure ()+ ]
src/Database/Postgres/Temp.hs view
@@ -50,10 +50,9 @@ with , withConfig , withRestart- , withNewDb- , withNewDbConfig- , withDbCacheConfig , withDbCache+ , withDbCacheConfig+ , withSnapshot -- * Separate start and stop interface. , start , startConfig@@ -61,11 +60,10 @@ , restart , stopPostgres , stopPostgresGracefully- , startNewDb- , startNewDbConfig- , stopNewDb , setupInitDbCache , cleanupInitDbCache+ , takeSnapshot+ , cleanupSnapshot -- * Main resource handle , DB -- ** 'DB' accessors@@ -87,10 +85,17 @@ , standardProcessConfig , silentConfig , silentProcessConfig+ , configFromSavePoint -- ** Custom Config builder helpers , optionsToDefaultConfig -- ** Configuration Types , module Database.Postgres.Temp.Config+ -- * Deprecated NewDb Functions. Use 'withSnapshot'.+ , withNewDb+ , withNewDbConfig+ , startNewDb+ , startNewDbConfig+ , stopNewDb ) where import Database.Postgres.Temp.Internal import Database.Postgres.Temp.Internal.Core
src/Database/Postgres/Temp/Config.hs view
@@ -59,6 +59,8 @@ , keyBasedL -- ** 'DirectoryType' , DirectoryType (..)+ -- ** 'Accum'+ , Accum (..) -- ** 'Logger' , Logger -- * Internal events passed to the 'logger' .
src/Database/Postgres/Temp/Internal.hs view
@@ -187,7 +187,6 @@ { plan = mempty { logger = pure mempty , postgresConfigFile = defaultPostgresConfig- , createDbConfig = Nothing , initDbConfig = pure mempty { commandLine = mempty { keyBased = Map.singleton "--no-sync" Nothing@@ -484,7 +483,7 @@ -- in it's connection options. -> IO (Either StartError a) withNewDb = withNewDbConfig mempty-+{-# DEPRECATED withNewDb "Use withSnapshot" #-} {-| Exception safe version of 'startNewDbConfig'. Creates a temporary database using the current database as a template.@@ -507,6 +506,7 @@ withNewDbConfig extra db f = bracket (startNewDbConfig extra db) (either mempty stopNewDb) $ either (pure . Left) (fmap Right . f)+{-# DEPRECATED withNewDbConfig "Use withSnapshot" #-} {-| Use the current database as a template and make a copy. Give the@@ -529,6 +529,7 @@ -- is used as the template for the @generated@ 'ProcessConfig'. -> IO (Either StartError DB) startNewDb = startNewDbConfig mempty+{-# DEPRECATED startNewDb "Use takeSnapshot" #-} {-| Use the current database as a template and make a copy. Give the@@ -607,7 +608,7 @@ terminateConnections oldOptions executeCreateDb final pure newDb-+{-# DEPRECATED startNewDbConfig "Use takeSnapshot" #-} -- | Cleanup the temporary database created by 'startNewDbConfig' -- or 'startNewDb'. --@@ -624,6 +625,7 @@ { Client.dbname = pure "template1" } dropDbIfExists template1Options newDbName+{-# DEPRECATED stopNewDb "Use cleanupSnapshot" #-} ------------------------------------------------------------------------------- -- initdb cache@@ -737,3 +739,86 @@ toCacheConfig cacheInfo = mempty { initDbCache = pure $ pure $ fmap toFilePath cacheInfo }++-------------------------------------------------------------------------------+-- withSnapshot+-------------------------------------------------------------------------------+{- |+Shutdown the database and copy the directory to a folder.++@since 1.17.0.0+-}+takeSnapshot+ :: DirectoryType+ -- ^ Either a 'Temporary' or preexisting 'Permanent' directory.+ -> DB+ -- ^ The handle. The @postgres@ is shutdown and the data directory is copied.+ -> IO (Either StartError CompleteDirectoryType)+takeSnapshot directoryType db = try $ do+ throwIfNotSuccess id =<< stopPostgresGracefully db+ cow <- cacheUseCopyOnWrite <$> createDefaultCacheConfig+ let+#ifdef darwin_HOST_OS+ cpFlags = if cow then "cp -Rc " else "cp -R "+#else+ cpFlags = if cow then "cp -R --reflink=auto " else "cp -R "+#endif+ bracketOnError+ (setupDirectoryType+ (toTemporaryDirectory db)+ "tmp-postgres-snapshot"+ directoryType+ )+ cleanupDirectoryType $ \snapShotDir -> do+ let snapshotCopyCmd = cpFlags <>+ toDataDirectory db <> "/* " <> toFilePath snapShotDir+ throwIfNotSuccess (SnapshotCopyFailed snapshotCopyCmd) =<<+ system snapshotCopyCmd++ pure snapShotDir++{-|+Cleanup any temporary resources used for the snapshot.++@since 1.17.0.0+-}+cleanupSnapshot :: CompleteDirectoryType -> IO ()+cleanupSnapshot = cleanupDirectoryType++{- |+Exception safe method for taking a file system level copy of the database cluster.++Snapshots are useful if you would like to start every test from a migrated database+and the migration process is more time consuming then copying the additional data.++@since 1.17.0.0+-}+withSnapshot+ :: DirectoryType+ -> DB+ -> (CompleteDirectoryType -> IO a)+ -> IO (Either StartError a)+withSnapshot dirType db f = bracket+ (takeSnapshot dirType db)+ (either mempty cleanupSnapshot)+ (either (pure . Left) (fmap Right . f))++{-|+Convert a snapshot into a 'Config' that includes a 'copyConfig' for copying the+snapshot directory to a temporary directory.++@since 1.17.0.0+-}+configFromSavePoint :: FilePath -> IO Config+configFromSavePoint savePointPath = do+ cow <- cacheUseCopyOnWrite <$> createDefaultCacheConfig+ pure mempty+ { plan = mempty+ { copyConfig = pure $ pure CopyDirectoryCommand+ { sourceDirectory = savePointPath+ , destinationDirectory = Nothing+ , useCopyOnWrite = cow+ }+ , initDbConfig = Zlich+ }+ }
src/Database/Postgres/Temp/Internal/Config.hs view
@@ -45,6 +45,49 @@ import System.Process import Text.PrettyPrint.ANSI.Leijen hiding ((<$>)) +{-|++'Accum' is a monoid.++It's '<>' behavior is analogous to 1 and 0 with '*'. Think of 'DontCare'+as 1 and 'Zlich' as 0.++The behavior of 'Merge' is like 'Just's.++@since 1.17.0.0+-}+data Accum a = DontCare | Zlich | Merge a+ deriving stock (Show, Eq, Ord, Functor)++instance Applicative Accum where+ pure = Merge+ af <*> ax = case (af, ax) of+ (Merge f, Merge x) -> Merge $ f x++ (DontCare, _) -> DontCare+ (_, DontCare) -> DontCare++ (Zlich, _) -> Zlich+ (_, Zlich) -> Zlich++instance Semigroup a => Semigroup (Accum a) where+ x <> y = case (x, y) of+ (DontCare, b) -> b+ (a , DontCare ) -> a++ (Zlich , _ ) -> Zlich+ (_ , Zlich) -> Zlich++ (Merge a, Merge b) -> Merge $ a <> b++getAccum :: Accum a -> Maybe a+getAccum = \case+ Merge a -> Just a+ _ -> Nothing++instance Monoid a => Monoid (Accum a) where+ mempty = DontCare+ prettyMap :: (Pretty a, Pretty b) => Map a b -> Doc prettyMap theMap = let xs = Map.toList theMap@@ -395,9 +438,9 @@ -- @since 1.16.0.0 data Plan = Plan { logger :: Last Logger- , initDbConfig :: Maybe ProcessConfig+ , initDbConfig :: Accum ProcessConfig , copyConfig :: Last (Maybe CopyDirectoryCommand)- , createDbConfig :: Maybe ProcessConfig+ , createDbConfig :: Accum ProcessConfig , postgresPlan :: PostgresPlan , postgresConfigFile :: [String] , dataDirectoryString :: Last String@@ -413,11 +456,11 @@ pretty Plan {..} = text "initDbConfig:" <> softline- <> indent 2 (pretty initDbConfig)+ <> indent 2 (pretty $ getAccum initDbConfig) <> hardline <> text "initDbConfig:" <> softline- <> indent 2 (pretty createDbConfig)+ <> indent 2 (pretty $ getAccum createDbConfig) <> text "copyConfig:" <> softline <> indent 2 (pretty (getLast copyConfig))@@ -447,16 +490,16 @@ $ (,,,,,) <$> getOption "logger" logger <*> eitherToErrors (addErrorContext "initDbConfig: " $- traverse (completeProcessConfig envs) initDbConfig)+ traverse (completeProcessConfig envs) $ getAccum initDbConfig) <*> eitherToErrors (addErrorContext "createDbConfig: " $- traverse (completeProcessConfig envs) createDbConfig)+ traverse (completeProcessConfig envs) $ getAccum createDbConfig) <*> eitherToErrors (addErrorContext "postgresPlan: " (completePostgresPlan envs postgresPlan)) <*> getOption "dataDirectoryString" dataDirectoryString <*> getOption "connectionTimeout" connectionTimeout let completePlanConfig = unlines postgresConfigFile- completePlanCopy =completeCopyDirectory completePlanDataDirectory <$>+ completePlanCopy = completeCopyDirectory completePlanDataDirectory <$> join (getLast copyConfig) pure CompletePlan {..}@@ -464,12 +507,12 @@ -- Returns 'True' if the 'Plan' has a -- 'Just' 'initDbConfig'. hasInitDb :: Plan -> Bool-hasInitDb Plan {..} = isJust initDbConfig+hasInitDb Plan {..} = isJust $ getAccum initDbConfig -- Returns 'True' if the 'Plan' has a -- 'Just' 'createDbConfig'. hasCreateDb :: Plan -> Bool-hasCreateDb Plan {..} = isJust createDbConfig+hasCreateDb Plan {..} = isJust $ getAccum createDbConfig -- | The high level options for overriding default behavior. --@@ -672,7 +715,7 @@ -> FilePath -- ^ The @postgres@ data directory. -> Plan-toPlan makeInitDb makeCreateDb port socketDirectory dataDirectoryString = mempty+toPlan _makeInitDb makeCreateDb port socketDirectory dataDirectoryString = mempty { postgresConfigFile = socketDirectoryToConfig socketDirectory , dataDirectoryString = pure dataDirectoryString , connectionTimeout = pure (60 * 1000000) -- 1 minute@@ -701,18 +744,33 @@ ] } }- else Nothing- , initDbConfig = if makeInitDb- then pure $ standardProcessConfig+ else mempty++ , initDbConfig = pure $ standardProcessConfig { commandLine = mempty { keyBased = Map.fromList [("--pgdata=", Just dataDirectoryString)] } }- else Nothing , copyConfig = pure Nothing } ++-- | 'combinePlans' is almost '<>'. However the 'Last' monoid for+-- @createdb@ and @initdb@ plans are not used. Instead something+-- like Lastoid is.+combinePlans :: Plan -> Plan -> Plan+combinePlans x y = Plan+ { logger = logger x <> logger y+ , initDbConfig = initDbConfig x <> initDbConfig y+ , copyConfig = copyConfig x <> copyConfig y+ , createDbConfig = createDbConfig x <> createDbConfig y+ , postgresPlan = postgresPlan x <> postgresPlan y+ , postgresConfigFile = postgresConfigFile x <> postgresConfigFile y+ , dataDirectoryString = dataDirectoryString x <> dataDirectoryString y+ , connectionTimeout = connectionTimeout x <> connectionTimeout y+ }+ -- | Create all the temporary resources from a 'Config'. This also combines the -- 'Plan' from 'toPlan' with the @extra@ 'Config' passed in. setupConfig@@ -734,7 +792,7 @@ thePort (toFilePath resourcesSocketDirectory) (toFilePath resourcesDataDir)- finalPlan = hostAndDir <> plan+ finalPlan = combinePlans hostAndDir plan uncachedPlan <- lift $ either (throwIO . CompletePlanFailed (show $ pretty finalPlan)) pure $ completePlan envs finalPlan@@ -827,7 +885,7 @@ -- Create a 'Plan' given a user. userToPlan :: String -> Plan userToPlan user = mempty- { initDbConfig = pure $ mempty+ { initDbConfig = pure mempty { commandLine = mempty { keyBased = Map.singleton "--username=" $ Just user }@@ -842,7 +900,7 @@ dbnameToPlan muser mpassword dbName | dbName == "template1" || dbName == "postgres" = mempty | otherwise = mempty- { createDbConfig = pure $ mempty+ { createDbConfig = pure mempty { commandLine = mempty { indexBased = Map.singleton 0 dbName , keyBased = maybe mempty (Map.singleton "--username=" . Just) muser@@ -1005,9 +1063,9 @@ -- | Lens for 'createDbConfig'. ----- @since 1.12.0.0+-- @since 1.17.0.0 createDbConfigL ::- Lens' Plan (Maybe ProcessConfig)+ Lens' Plan (Accum ProcessConfig) createDbConfigL f (plan@Plan{..}) = fmap (\x -> plan { createDbConfig = x }) (f createDbConfig)@@ -1034,7 +1092,7 @@ -- | Lens for 'initDbConfig'. -- -- @since 1.12.0.0-initDbConfigL :: Lens' Plan (Maybe ProcessConfig)+initDbConfigL :: Lens' Plan (Accum ProcessConfig) initDbConfigL f (plan@Plan{..}) = fmap (\x -> plan { initDbConfig = x }) (f initDbConfig)
src/Database/Postgres/Temp/Internal/Core.hs view
@@ -86,6 +86,8 @@ | FailedToFindDataDirectory String -- ^ Failed to find a data directory when trying to get -- a cached @initdb@ folder.+ | SnapshotCopyFailed String ExitCode+ -- ^ We tried to copy a data directory to a snapshot folder and it failed deriving (Show, Eq, Typeable) instance Exception StartError@@ -360,6 +362,10 @@ = text "completePlanInitDb:" <> softline <> indent 2 (pretty completePlanInitDb)+ <> hardline+ <> text "completePlanCopy:"+ <> softline+ <> indent 2 (pretty completePlanCopy) <> hardline <> text "completePlanCreateDb:" <> softline
test/Main.hs view
@@ -6,6 +6,7 @@ import Data.Maybe import Data.Monoid import Data.Monoid.Generic+-- import Data.Int import Data.List import qualified Data.Set as Set import Data.String@@ -35,10 +36,6 @@ withConfig' :: Config -> (DB -> IO a) -> IO a withConfig' config = either throwIO pure <=< withConfig config -withNewDbConfig' :: ProcessConfig -> DB -> (DB -> IO a) -> IO a-withNewDbConfig' config db = either throwIO pure <=<- withNewDbConfig config db- countPostgresProcesses :: IO Int countPostgresProcesses = countProcesses "postgres" @@ -158,7 +155,7 @@ expectedPassword = "password" expectedHost = "localhost" - cConfig = optionsToDefaultConfig mempty+ cConfig' = optionsToDefaultConfig mempty { Client.port = pure expectedPort , Client.dbname = pure expectedDbName , Client.user = pure expectedUser@@ -166,6 +163,8 @@ , Client.host = pure expectedHost } + cConfig = cConfig' { plan = (plan cConfig') { logger = pure print }}+ cAssert db = do let Client.Options {..} = toConnectionOptions db port `shouldBe` pure expectedPort@@ -321,7 +320,7 @@ { cConfig = silentConfig { dataDirectory = Permanent dirPath , plan = (plan silentConfig)- { initDbConfig = Nothing+ { initDbConfig = Zlich } } }@@ -472,7 +471,7 @@ let dontTimeout = silentConfig { plan = (plan silentConfig) { connectionTimeout = pure maxBound- , initDbConfig = Nothing+ , initDbConfig = Zlich } } @@ -559,54 +558,31 @@ happyPaths errorPaths --- I nest the db creation to make sure I can do that-withNewDbSpecs :: Spec-withNewDbSpecs = describe "withNewDb" $ do- it "works" $ withConfig' silentConfig $ \db -> do+withSnapshotSpecs :: Spec+withSnapshotSpecs = describe "withSnapshot" $ do+ it "works" $ withConfig' defaultConfig $ \db -> do+ -- TODO create a table withConn db $ \conn -> do- _ <- PG.execute_ conn "CREATE TABLE foo ( id int );"- void $ PG.execute_ conn "INSERT INTO foo (id) VALUES (1);"-- withNewDbConfig' mempty db $ \newDb -> do- one <- fmap (PG.fromOnly . head) $- withConn newDb $ \conn -> PG.query_ conn "SELECT id FROM foo"-- one `shouldBe` (1 :: Int)-- let expectedDbName = "newname"- specificDbName = mempty- { commandLine = mempty- { indexBased =- Map.singleton 0 expectedDbName- }- }-- withNewDbConfig' specificDbName db $ \newerDb -> do- Client.dbname (toConnectionOptions newerDb) `shouldBe`- pure expectedDbName-- oneAgain <- fmap (PG.fromOnly . head) $- withConn newerDb $ \conn -> PG.query_ conn "SELECT id FROM foo"+ _ <- PG.execute_ conn "BEGIN; CREATE TABLE foo ( id int );"+ void $ PG.execute_ conn "INSERT INTO foo (id) VALUES (1); END;" - oneAgain `shouldBe` (1 :: Int)+ either throwIO pure <=< withSnapshot Temporary db $ \snapshotDir -> do+ snapshotConfig <- (defaultConfig <>)+ <$> configFromSavePoint (toFilePath snapshotDir) - let invalidConfig = silentProcessConfig- { commandLine = mempty- { indexBased =- Map.singleton 0 "template1"- }- }+ let snapshotConfigAndAssert = ConfigAndAssertion snapshotConfig $ flip withConn $ \conn -> do+ oneAgain <- fmap (PG.fromOnly . head) $ PG.query_ conn "SELECT id FROM foo"+ oneAgain `shouldBe` (1 :: Int) - withNewDbConfig invalidConfig db (const $ pure ()) >>= \case- Right () -> fail "Should not succeed"- Left (CreateDbFailed {}) -> pure ()- Left err -> fail $ "Wrong type of error " <> show err+ testWithTemporaryDirectory+ snapshotConfigAndAssert+ testSuccessfulConfig spec :: Spec spec = do withConfigSpecs - withNewDbSpecs+ withSnapshotSpecs it "stopPostgres cannot be connected to" $ withConfig' silentConfig $ \db -> do stopPostgres db `shouldReturn` ExitSuccess
tmp-postgres.cabal view
@@ -1,5 +1,5 @@ name: tmp-postgres-version: 1.16.1.0+version: 1.17.0.0 synopsis: Start and stop a temporary postgres description: Start and stop a temporary postgres. See README.md homepage: https://github.com/jfischoff/tmp-postgres#readme@@ -104,6 +104,7 @@ ghc-options: -O2 -Wall build-depends: base , criterion+ , deepseq , postgres-options , postgresql-simple , tmp-postgres