Files
cms-service/scripts/db/rollback.sh
2026-02-02 14:27:56 +08:00

80 lines
2.5 KiB
Bash
Executable File

#!/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