#!/usr/bin/env sh # Apply SQL migrations to PostgreSQL (Docker Compose service "postgres" by default). # # By default skips 000001_* (bootstrap + seeds): Docker initdb runs it on first volume # create; re-applying breaks on duplicate INSERTs. Set MIGRATE_INCLUDE_BOOTSTRAP=1 to # include it (empty DB, no initdb hook). # # Usage: # ./scripts/migrate.sh # DB_USER=myuser DB_NAME=mydb ./scripts/migrate.sh # MIGRATE_INCLUDE_BOOTSTRAP=1 ./scripts/migrate.sh set -eu ROOT_DIR="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" MIGRATIONS_DIR="${ROOT_DIR}/backend/migrations" DB_USER="${DB_USER:-autohero}" DB_NAME="${DB_NAME:-autohero}" COMPOSE_FILE="${COMPOSE_FILE:-${ROOT_DIR}/docker-compose.yml}" cd "${ROOT_DIR}" if ! docker compose -f "${COMPOSE_FILE}" exec -T postgres pg_isready -U "${DB_USER}" -d "${DB_NAME}" >/dev/null 2>&1; then echo "migrate.sh: postgres is not ready or container is not running. Start: docker compose up -d postgres" >&2 exit 1 fi apply_file() { f="$1" name="$(basename "$f")" echo "Applying ${name}..." docker compose -f "${COMPOSE_FILE}" exec -T postgres \ psql -v ON_ERROR_STOP=1 -U "${DB_USER}" -d "${DB_NAME}" < "$f" } # Sorted list (000001, 000002, ...); skip 000001 unless MIGRATE_INCLUDE_BOOTSTRAP=1 found=0 for f in $(find "${MIGRATIONS_DIR}" -maxdepth 1 -name '*.sql' | sort); do found=1 base="$(basename "$f")" case "${base}" in 000001_*.sql) if [ "${MIGRATE_INCLUDE_BOOTSTRAP:-0}" != "1" ]; then echo "Skipping ${base} (set MIGRATE_INCLUDE_BOOTSTRAP=1 to apply bootstrap on an empty DB)" continue fi ;; esac apply_file "$f" done if [ "${found}" -eq 0 ]; then echo "migrate.sh: no .sql files in ${MIGRATIONS_DIR}" >&2 exit 1 fi echo "Done."