#!/usr/bin/env bash
set -euo pipefail

keeptmp=${KEEP_TMP:-""}

usage() {
  cat << EOF

USAGE: $0 COMMAND

Runs the given COMMAND with the PGRST_DB_URI environment variable
set to a temporary database that is ready for running the PostgREST test suite.

You'll need to have the Postgres binaries 'initdb', 'pg_ctl' and 'psql' on your
PATH.

Example:

    $0 stack test

    # Or, for when inside nix-shell
    $0 cabal v2-test

If KEEP_TMP is set (e.g. to "1"), the temporary directory will not be deleted
after exit. The log files in that directory might be useful for debugging
purposes.

EOF
  exit 1
}

if [ "$#" -lt 1 ]; then
  echo "Please provide a command to be run with the temporary database."
  usage
fi

# All data will be stored in a temporary directory.
tmpdir="$(mktemp -d)"

if [ -n "$keeptmp" ]; then
  echo "The temporary directory at $tmpdir will be preserved after exit."
else
  trap 'rm -rf "$tmpdir"' sigint sigterm exit
fi

dblog="$tmpdir/db.log"
setuplog="$tmpdir/setup.log"

log() {
  echo "$1" >> "$setuplog"
}

mkdir -p "$tmpdir"/{db,socket}

export PGDATA="$tmpdir/db"
export PGHOST="$tmpdir/socket"
export PGUSER=postgrest_test_authenticator
export PGDATABASE=postgres
export DB_URI="postgresql:///$PGDATABASE?host=$PGHOST&user=$PGUSER"
export PGRST_DB_URI="$DB_URI"
export PGRST_DB_SCHEMAS="test"
export PGRST_DB_ANON_ROLE="postgrest_test_anonymous"

log "Initializing database cluster..."
# We try to make the database cluster as independent as possible from the host
# by specifying the timezone, locale and encoding.
PGTZ=UTC initdb --no-locale --encoding=UTF8 --nosync -U "$PGUSER" --auth=trust \
  >> "$setuplog"

log "Starting the database cluster..."
# Instead of listening on a local port, we will listen on a unix domain socket.
pg_ctl -l "$dblog" start -o "-F -c listen_addresses=\"\" -k $PGHOST" \
  >> "$setuplog"

log "Waiting for the database cluster to be ready..."
# Waiting is required for older versions of Postgres (< 10).
until pg_isready >> "$setuplog"; do
  sleep 0.1
done

stopped=0
stop() {
  # cleaning up once is enough; otherwise we get some errors
  if [ $stopped -eq 1 ]; then
    return
  fi
  stopped=1

  log "Stopping the database cluster..."
  pg_ctl stop -m i >> "$setuplog"

  if [ -n "$keeptmp" ]; then
    echo "Keeping the temporary directory at $tmpdir"
  else
    rm -rf "$tmpdir"
  fi
}

trap stop sigint sigterm exit

log "Loading fixtures..."
psql -v ON_ERROR_STOP=1 -f test/fixtures/load.sql >> "$setuplog"

log "Done. Running command..."
# Run the command that was given as an argument. The `exit` trap above will
# make sure that the database is shut down and the temporary directory is
# deleted when the command is done. This is also why we don't `exec` the
# command - our trap would be lost if we did that.
"$@"
