tmp-postgres-1.0.0.2: Start and stop a temporary postgres

Safe HaskellNone
LanguageHaskell2010

Database.Postgres.Temp

Contents

Description

This module provides functions creating a temporary postgres instance. By default it will create a temporary directory for the data, a random port for listening and a temporary directory for a UNIX domain socket.

Here is an example using the expection safe with function:

with $ \db -> bracket (connectPostgreSQL (toConnectionString db)) close $ \conn ->
 execute_ conn "CREATE TABLE foo (id int)"

To extend or override the defaults use withPlan (or startWith).

tmp-postgres ultimately calls initdb, postgres and createdb. All of the command line, environment variables and configuration files that are generated by default for the respective executables can be extended or overrided.

All tmp-postgres by default is most useful for creating tests by configuring "tmp-postgres" differently it can be used for other purposes.

  • By disabling initdb and createdb one could run a temporary postgres on a base backup to test a migration.
  • By using the stopPostgres and withRestart functions one can test backup strategies.

The level of custom configuration is extensive but with great power comes ability to screw everything up. `tmp-postgres` doesn't validate any custom configuration and one can easily create a Config that would not allow postgres to start.

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

echo "export PATH=$PATH:/usr/lib/postgresql/VERSION/bin/" >> /home/ubuntu/.bashrc
Synopsis

Main resource handle

data DB Source #

Handle for holding temporary resources, the postgres process handle and postgres connection information. The DB also includes the final Plan that was used to start initdb, createdb and postgres.

Constructors

DB 

Fields

Exception safe interface

postgres is started with a default config with the following options:

  shared_buffers = 12MB
  fsync = off
  synchronous_commit = off
  full_page_writes = off
  log_min_duration_statement = 0
  log_connections = on
  log_disconnections = on
  unix_socket_directories = {DATA_DIRECTORY}
  client_min_messages = ERROR

Additionally if an IP address is provide the following line is added:

  listen_addresses = 'IP_ADDRESS'

If a UNIX domain socket is specified the following is added:

  listen_addresses = ''
  unix_socket_directories = {DATA_DIRECTORY}

To add to "postgresql.conf" file create a custom Config like the following:

 let custom = defaultConfig <> mempty { configPlan = mempty
       { partialPlanConfig = Mappend
           [ "wal_level=replica"
           , "archive_mode=on"
           , "max_wal_senders=2"
           , "fsync=on"
           , "synchronous_commit=on"
           ]
       }
   }

In general you'll want to mappend a config to the defaultConfig. The defaultConfig setups a database and connection options for the created database. However if you want to extend the behavior of createdb you will probably have to create a Config from scratch to ensure the final parameter to createdb is the database name.

with Source #

Arguments

:: (DB -> IO a)

action continuation.

-> IO (Either StartError a) 

Default expectation safe interface. Equivalent to withPlan the defaultConfig

withPlan Source #

Arguments

:: Config

extraConfiguration. Combined with the generated Config. See startWith for more info

-> (DB -> IO a)

action continuation

-> IO (Either StartError a) 

Exception safe default database create. Takes an action continuation which is given a DB it can use to connect to (see toConnectionString or postgresProcessClientConfig). All of the database resources are automatically cleaned up on completion even in the face of exceptions.

Separate start and stop interface.

start :: IO (Either StartError DB) Source #

Default start behavior. Equivalent to calling startWith with the defaultConfig

startWith Source #

Arguments

:: Config

extraConfiguration that is mappended to the generated Config. The extra config is mappended second, e.g. generatedConfig <> extraConfiguration

-> IO (Either StartError DB) 

Create temporary resources and use them to make a Config. The generated Config is combined with the passed in extraConfiguration to create a Plan that is used to create a database. The output DB includes references to the temporary resources for cleanup and the final plan that was used to generate the database and processes

stop :: DB -> IO () Source #

Stop the postgres process and cleanup any temporary directories that might have been created.

defaultConfig :: Config Source #

The default configuration. This will create a database called "test" and create a temporary directory for the data and a temporary directory for a unix socket on a random port. If you would like to customize this behavior you can start with the defaultConfig and overwrite fields or combine the Config with another config using <> (mappend). If you would like complete control over the behavior of initdb, postgres and createdb you can call the internal function initPlan directly although this should not be necessary.

Starting and Stopping postgres without removing the temporary directory

restart :: DB -> IO (Either StartError DB) Source #

Restart the postgres using the Plan from the DB (e.g. resourcesPlan . dbResources)

stopPostgres :: DB -> IO ExitCode Source #

Only stop the postgres process but leave any temporary resources. Useful for testing backup strategies when used in conjunction with restart or withRestart.

withRestart :: DB -> (DB -> IO a) -> IO (Either StartError a) Source #

Exception safe version of restart

Reloading the config

reloadConfig :: DB -> IO () Source #

Reload the configuration file without shutting down. Calls pg_reload_conf().

DB manipulation

toConnectionString :: DB -> ByteString Source #

Convert a DB to a connection string. Alternatively one can access the Options using postgresProcessClientConfig . dbPostgresProcess

Errors

data StartError Source #

A list of failures that can occur when starting. This is not and exhaustive list but covers the errors that the system catches for the user.

Constructors

StartPostgresFailed ExitCode

postgres failed before a connection succeeded. Most likely this is due to invalid configuration

InitDbFailed ExitCode

initdb failed. This can be from invalid configuration or using a non-empty data directory

CreateDbFailed ExitCode

createdb failed. This can be from invalid configuration or the database might already exist.

CompletePlanFailed [String]

The PartialPlan was missing info and a complete Plan could not be created.

Configuration Types

data Config Source #

The high level options for overriding default behavior.

Constructors

Config 

Fields

Instances
Generic Config Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Associated Types

type Rep Config :: Type -> Type #

Methods

from :: Config -> Rep Config x #

to :: Rep Config x -> Config #

Semigroup Config Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Monoid Config Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep Config Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep Config = D1 (MetaData "Config" "Database.Postgres.Temp.Internal.Partial" "tmp-postgres-1.0.0.2-DvnOuejNnGN1mXJO2kDkWd" False) (C1 (MetaCons "Config" PrefixI True) ((S1 (MetaSel (Just "configPlan") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 PartialPlan) :*: S1 (MetaSel (Just "configSocket") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 PartialSocketClass)) :*: (S1 (MetaSel (Just "configDataDir") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 PartialDirectoryType) :*: S1 (MetaSel (Just "configPort") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Last (Maybe Int))))))

General extend or override monoid

data Lastoid a Source #

Lastoid is helper for overriding configuration values. It's Semigroup instance let's one either combine the a of two Lastoids using <> via the Mappend constructor or one can wholly replace the value with the last value using the Replace constructor. Roughly

  x <> Replace y = Replace y
  Replace x <> Mappend y = Replace (x <> y)
  Mappend x <> Mappend y = Mappend (x <> y)

Constructors

Replace a 
Mappend a 
Instances
Functor Lastoid Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Methods

fmap :: (a -> b) -> Lastoid a -> Lastoid b #

(<$) :: a -> Lastoid b -> Lastoid a #

Eq a => Eq (Lastoid a) Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Methods

(==) :: Lastoid a -> Lastoid a -> Bool #

(/=) :: Lastoid a -> Lastoid a -> Bool #

Show a => Show (Lastoid a) Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Methods

showsPrec :: Int -> Lastoid a -> ShowS #

show :: Lastoid a -> String #

showList :: [Lastoid a] -> ShowS #

Semigroup a => Semigroup (Lastoid a) Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Methods

(<>) :: Lastoid a -> Lastoid a -> Lastoid a #

sconcat :: NonEmpty (Lastoid a) -> Lastoid a #

stimes :: Integral b => b -> Lastoid a -> Lastoid a #

Monoid a => Monoid (Lastoid a) Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Methods

mempty :: Lastoid a #

mappend :: Lastoid a -> Lastoid a -> Lastoid a #

mconcat :: [Lastoid a] -> Lastoid a #

Directory configuration

data PartialDirectoryType Source #

The monoidial version of DirectoryType. Used to combine overrides with defaults when creating a DirectoryType. The monoid instance treats PTemporary as mempty and takes the last PPermanent value.

Constructors

PPermanent FilePath

A permanent file that should not be generated.

PTemporary

A temporary file that needs to generated.

Instances
Eq PartialDirectoryType Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Ord PartialDirectoryType Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Show PartialDirectoryType Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Semigroup PartialDirectoryType Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Monoid PartialDirectoryType Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Listening socket configuration

data SocketClass Source #

A type for configuring the listening address of the postgres process. postgres can listen on several types of sockets simulatanously but we don't support that behavior. One can either listen on a IP based socket or a UNIX domain socket.

Constructors

IpSocket String

IP socket type. The String is either an IP address or a host that will resolve to an IP address.

UnixSocket DirectoryType

UNIX domain socket

Instances
Eq SocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Ord SocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Show SocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Generic SocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Associated Types

type Rep SocketClass :: Type -> Type #

type Rep SocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep SocketClass = D1 (MetaData "SocketClass" "Database.Postgres.Temp.Internal.Partial" "tmp-postgres-1.0.0.2-DvnOuejNnGN1mXJO2kDkWd" False) (C1 (MetaCons "IpSocket" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 String)) :+: C1 (MetaCons "UnixSocket" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 DirectoryType)))

data PartialSocketClass Source #

The monoidial version of SocketClass. Used to combine overrides with defaults when creating a SocketClass. The monoid instance treats 'PUnixSocket mempty' as mempty and combines the

Constructors

PIpSocket (Last String)

The monoid for combining IP address configuration

PUnixSocket PartialDirectoryType

The monoid for combining UNIX socket configuration

Instances
Eq PartialSocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Ord PartialSocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Show PartialSocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Generic PartialSocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Associated Types

type Rep PartialSocketClass :: Type -> Type #

Semigroup PartialSocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Monoid PartialSocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep PartialSocketClass Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep PartialSocketClass = D1 (MetaData "PartialSocketClass" "Database.Postgres.Temp.Internal.Partial" "tmp-postgres-1.0.0.2-DvnOuejNnGN1mXJO2kDkWd" False) (C1 (MetaCons "PIpSocket" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Last String))) :+: C1 (MetaCons "PUnixSocket" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 PartialDirectoryType)))

Process configuration

data PartialProcessConfig Source #

The monoidial version of ProcessConfig. Used to combine overrides with defaults when creating a ProcessConfig.

Constructors

PartialProcessConfig 

Fields

Instances
Generic PartialProcessConfig Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Associated Types

type Rep PartialProcessConfig :: Type -> Type #

Semigroup PartialProcessConfig Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Monoid PartialProcessConfig Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep PartialProcessConfig Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep PartialProcessConfig = D1 (MetaData "PartialProcessConfig" "Database.Postgres.Temp.Internal.Partial" "tmp-postgres-1.0.0.2-DvnOuejNnGN1mXJO2kDkWd" False) (C1 (MetaCons "PartialProcessConfig" PrefixI True) ((S1 (MetaSel (Just "partialProcessConfigEnvVars") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Lastoid [(String, String)])) :*: S1 (MetaSel (Just "partialProcessConfigCmdLine") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Lastoid [String]))) :*: (S1 (MetaSel (Just "partialProcessConfigStdIn") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Last Handle)) :*: (S1 (MetaSel (Just "partialProcessConfigStdOut") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Last Handle)) :*: S1 (MetaSel (Just "partialProcessConfigStdErr") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Last Handle))))))

data ProcessConfig Source #

ProcessConfig contains the configuration necessary for starting a process. It is essentially a stripped down CreateProcess.

Constructors

ProcessConfig 

Fields

postgres process configuration

data PartialPostgresPlan Source #

PartialPostgresPlan

Constructors

PartialPostgresPlan 

Fields

data PostgresPlan Source #

PostgresPlan is used be startPostgresProcess to start the postgres and then attempt to connect to it.

Constructors

PostgresPlan 

Fields

postgres process handle. Includes the client options for connecting

data PostgresProcess Source #

The output of calling startPostgresProcess.

Constructors

PostgresProcess 

Fields

Database plans. This is used to call initdb, postgres and createdb

data PartialPlan Source #

The monoidial version of Plan. Used to combine overrides with defaults when creating a plan.

Instances
Generic PartialPlan Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Associated Types

type Rep PartialPlan :: Type -> Type #

Semigroup PartialPlan Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

Monoid PartialPlan Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep PartialPlan Source # 
Instance details

Defined in Database.Postgres.Temp.Internal.Partial

type Rep PartialPlan = D1 (MetaData "PartialPlan" "Database.Postgres.Temp.Internal.Partial" "tmp-postgres-1.0.0.2-DvnOuejNnGN1mXJO2kDkWd" False) (C1 (MetaCons "PartialPlan" PrefixI True) ((S1 (MetaSel (Just "partialPlanLogger") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Last Logger)) :*: (S1 (MetaSel (Just "partialPlanInitDb") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Lastoid (Maybe PartialProcessConfig))) :*: S1 (MetaSel (Just "partialPlanCreateDb") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Lastoid (Maybe PartialProcessConfig))))) :*: (S1 (MetaSel (Just "partialPlanPostgres") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 PartialPostgresPlan) :*: (S1 (MetaSel (Just "partialPlanConfig") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Lastoid [String])) :*: S1 (MetaSel (Just "partialPlanDataDirectory") NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (Last String))))))

data Plan Source #

Plan is the low level configuration necessary for creating a database starting postgres and creating a database. There is no validation done on the Plan. It is recommend that one use the higher level functions such as start which will generate plans that are valid. Plans are used internally but are exposed if the higher level plan generation is not sufficent.

Top level configuration