#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)" ROLLBACK_DIR="${SCRIPT_DIR}/rollback" load_database_url_from_env_file() { local env_file="$1" local line value while IFS= read -r line || [[ -n "${line}" ]]; do line="${line#"${line%%[![:space:]]*}"}" [[ -z "${line}" || "${line}" == \#* ]] && continue line="${line#export }" if [[ "${line}" == DATABASE_URL=* ]]; then value="${line#DATABASE_URL=}" value="${value%$'\r'}" value="${value%\"}" value="${value#\"}" value="${value%\'}" value="${value#\'}" printf '%s' "${value}" return 0 fi done < "${env_file}" return 1 } DATABASE_URL="${DATABASE_URL:-}" if [[ -z "${DATABASE_URL}" && -f "${ROOT_DIR}/.env" ]]; then DATABASE_URL="$(load_database_url_from_env_file "${ROOT_DIR}/.env" || true)" fi if [[ -z "${DATABASE_URL}" ]]; then echo "DATABASE_URL is required (export it, or set it in ${ROOT_DIR}/.env)" exit 1 fi if ! command -v psql >/dev/null 2>&1; then echo "psql not found in PATH" exit 127 fi ROLLBACK_TO_VERSION="${ROLLBACK_TO_VERSION:-}" DRY_RUN="${DRY_RUN:-0}" psql "${DATABASE_URL}" -v ON_ERROR_STOP=1 -c "CREATE TABLE IF NOT EXISTS _sqlx_migrations (version BIGINT PRIMARY KEY, description TEXT NOT NULL, installed_on TIMESTAMPTZ NOT NULL DEFAULT now(), success BOOLEAN NOT NULL, checksum BYTEA NOT NULL, execution_time BIGINT NOT NULL)" >/dev/null if [[ -z "${ROLLBACK_TO_VERSION}" ]]; then echo "ROLLBACK_TO_VERSION is required (e.g. 1 or 0)" exit 1 fi while true; do current="$(psql "${DATABASE_URL}" -At -c "SELECT version FROM _sqlx_migrations WHERE success=true ORDER BY version DESC LIMIT 1" || true)" if [[ -z "${current}" ]]; then echo "No applied migrations found" exit 0 fi if [[ "${current}" -le "${ROLLBACK_TO_VERSION}" ]]; then echo "Rollback completed (current=${current}, target=${ROLLBACK_TO_VERSION})" exit 0 fi file="${ROLLBACK_DIR}/$(printf "%04d" "${current}").down.sql" if [[ ! -f "${file}" ]]; then echo "Rollback file not found for version ${current}: ${file}" exit 1 fi echo "Rolling back version ${current} using $(basename "${file}")" if [[ "${DRY_RUN}" == "1" ]]; then psql "${DATABASE_URL}" -v ON_ERROR_STOP=1 -c "SELECT ${current}" >/dev/null else psql "${DATABASE_URL}" -v ON_ERROR_STOP=1 -f "${file}" psql "${DATABASE_URL}" -v ON_ERROR_STOP=1 -c "DELETE FROM _sqlx_migrations WHERE version=${current}" fi done