summaryrefslogtreecommitdiff
path: root/_drafts/temporary-postgresql-server.md
blob: a46cd860980973c31e9ea3e4bc3de7f8c57b5323 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
---
title: "Temporary PostgreSQL server"
description: "A simple shell script to run the PostgreSQL server off a temporary directory."
published: 2020-06-02
---

Sometimes I need to spin up a local PostgreSQL server for one-off purposes.
In these cases, I don't particularly like to either configure PostgreSQL manually or use a pre-configured Docker image because I experience this as overkill and inaccessible respectively.
Instead, I use the simple shell script below to run the PostgreSQL server off a temporary directory until I decide to `kill` it.
The script is inspired by a [blog post](https://www.johbo.com/2017/on-demand-postgresql-for-your-development-environment.html) by Johannes Bornhold that reminded me of Unix' simplicity.

The script essentially performs seven steps:

* Create a temporary directory using `mktemp`
* Initialize the directory using `initdb`
* Serve the directory using `postgres`
* Ensure the server is up using `pg_isready`
* Create a database using `createdb`
* Wait for a `SIGINT`
* Remove the temporary directory

Obviously, you still need to install PostgreSQL to use the script.
However, you may use the [Nix package manager](https://nixos.org/nix/) to install PostgreSQL _on-the-fly_ and have it removed too, if you are into this.
Simply put the following shebang in front of the script.

```sh
#! /usr/bin/env nix-shell
#! nix-shell --pure --packages postgresql -i bash
```

Here is the full script with minimal error handling.

```sh
#! /bin/sh

# temp_postgres runs a PostgreSQL server with a temporary data directory until
# it receives a SIGINT.

set -o nounset

# Remove the temporary directory before exiting
trap 'quit' INT
quit() {
  code="${1:-0}"
  trap '' INT TERM
  kill -TERM 0
  wait
  rm -rf "${tmpdir-}" || {
    >&2 printf "temp_postgres: failed to remove temporary directory \"%s\"\\n" "${tmpdir}"
    [ "${code}" -ne 0 ] || code=1
  }
  exit "${code}"
}

# Parse arguments
[ $# -eq 2 ] || {
  >&2 printf "temp_postgres: invalid arguments\\n"
  printf "Usage: temp_postgres <dbname> <username>\\n"
  quit 1
}
dbname="$1"
username="$2"

# Create a temporary directory
tmpdir="$( mktemp --directory )" || {
  >&2 printf "temp_postgres: failed to create temporary directory\\n"
  quit 1
}

# Initialize the directory
initdb --pgdata="${tmpdir}" --username="${username}" || {
  >&2 printf "temp_postgres: failed to initialize database\\n"
  quit 1
}

# Serve the directory
( postgres -k "${tmpdir}" -D "${tmpdir}" </dev/null ) &

# Test the connection
sleep 1
pg_isready --host="${tmpdir}" --dbname="postgres" --username="${username}" --timeout=10 || {
  >&2 printf "temp_postgres: failed to connect to server\\n"
  quit 1
}

# Create a database
createdb --host="${tmpdir}" --username="${username}" --no-password "${dbname}" || {
  >&2 printf "temp_postgres: failed to create database\\n"
  quit 1
}

printf '
Connect with the following command:

\tpsql --host=localhost "%s" "%s"

' "${dbname}" "${username}"

wait
```
Generated by cgit. See skreutz.com for my tech blog and contact information.