rebuild_all.sh 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/bin/bash
  2. # 数据库完整重建脚本:删除所有表后执行 database/init.sql(单文件初始化)
  3. set -e
  4. RED='\033[0;31m'
  5. GREEN='\033[0;32m'
  6. YELLOW='\033[1;33m'
  7. BLUE='\033[0;34m'
  8. CYAN='\033[0;36m'
  9. NC='\033[0m'
  10. DB_HOST=${DB_HOST:-localhost}
  11. DB_PORT=${DB_PORT:-5432}
  12. DB_NAME=${DB_NAME:-lingyue_zhibao}
  13. DB_USER=${DB_USER:-postgres}
  14. DB_PASSWORD=${DB_PASSWORD:-postgres}
  15. log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
  16. log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
  17. log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
  18. log_title() { echo -e "\n${BLUE}========== $1 ==========${NC}\n"; }
  19. log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
  20. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  21. PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
  22. INIT_SQL="${PROJECT_ROOT}/database/init.sql"
  23. execute_sql() {
  24. local file="$1"
  25. local desc="${2:-$(basename "$file")}"
  26. if [ ! -f "$file" ]; then
  27. log_error "文件不存在: $file"
  28. return 1
  29. fi
  30. log_step "执行: $desc"
  31. PGPASSWORD=${DB_PASSWORD} psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -d ${DB_NAME} -f "$file" || return 1
  32. }
  33. drop_all_tables() {
  34. log_title "删除所有表"
  35. if [ "$FORCE" != "yes" ]; then
  36. log_warn "这将删除数据库 ${DB_NAME} 中的所有表和数据!"
  37. read -p "是否继续?(yes/no): " confirm
  38. if [ "$confirm" != "yes" ]; then
  39. log_info "操作已取消"
  40. exit 0
  41. fi
  42. fi
  43. log_info "开始删除表..."
  44. PGPASSWORD=${DB_PASSWORD} psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -d ${DB_NAME} <<'EOF'
  45. SET session_replication_role = 'replica';
  46. DO $$
  47. DECLARE r RECORD;
  48. BEGIN
  49. FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = 'public')
  50. LOOP
  51. EXECUTE 'DROP TABLE IF EXISTS public.' || quote_ident(r.tablename) || ' CASCADE';
  52. RAISE NOTICE 'Dropped table: %', r.tablename;
  53. END LOOP;
  54. END $$;
  55. DO $$
  56. DECLARE r RECORD;
  57. BEGIN
  58. FOR r IN (SELECT sequencename FROM pg_sequences WHERE schemaname = 'public')
  59. LOOP
  60. EXECUTE 'DROP SEQUENCE IF EXISTS public.' || quote_ident(r.sequencename) || ' CASCADE';
  61. END LOOP;
  62. END $$;
  63. DO $$
  64. DECLARE r RECORD;
  65. BEGIN
  66. FOR r IN (SELECT proname, oidvectortypes(proargtypes) as args FROM pg_proc INNER JOIN pg_namespace ns ON (pg_proc.pronamespace = ns.oid) WHERE ns.nspname = 'public')
  67. LOOP
  68. EXECUTE 'DROP FUNCTION IF EXISTS public.' || quote_ident(r.proname) || '(' || r.args || ') CASCADE';
  69. END LOOP;
  70. END $$;
  71. SET session_replication_role = 'origin';
  72. EOF
  73. log_info "删除完成"
  74. }
  75. init_database() {
  76. log_title "初始化数据库"
  77. execute_sql "${INIT_SQL}" "database/init.sql(全表结构)"
  78. }
  79. create_test_user() {
  80. log_title "创建测试用户"
  81. PGPASSWORD=${DB_PASSWORD} psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -d ${DB_NAME} <<'EOF'
  82. INSERT INTO users (id, username, email, password_hash, role, create_time, update_time)
  83. VALUES ('00000000000000000000000000000001', 'admin', 'admin@lingyue.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iUtkWBrq.VZbISbAi1L9sNPIiMMi', 'admin', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
  84. ON CONFLICT (id) DO NOTHING;
  85. INSERT INTO users (id, username, email, password_hash, role, create_time, update_time)
  86. VALUES ('00000000000000000000000000000002', 'testuser', 'test@lingyue.com', '$2a$10$5XvCJaLqDXJz.YqL8TnNKegHH7q6KM7YFzMVxLPNMvJx5f7mxnKQi', 'user', CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
  87. ON CONFLICT (id) DO NOTHING;
  88. SELECT id, username, email, role FROM users;
  89. EOF
  90. log_info "测试用户: admin/Admin123! testuser/User1234!"
  91. }
  92. show_help() {
  93. cat <<EOF
  94. 用法: ./rebuild_all.sh [选项]
  95. 选项:
  96. -h, --help 显示帮助
  97. -f, --force 跳过确认
  98. --drop-only 只删除表
  99. --init-only 只执行 database/init.sql(不删除)
  100. --no-test-user 不创建测试用户
  101. 环境变量: DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD
  102. EOF
  103. }
  104. CREATE_TEST_USER=true
  105. DROP_ONLY=false
  106. INIT_ONLY=false
  107. while [[ $# -gt 0 ]]; do
  108. case $1 in
  109. -h|--help) show_help; exit 0 ;;
  110. -f|--force) FORCE=yes; shift ;;
  111. --no-test-user) CREATE_TEST_USER=false; shift ;;
  112. --drop-only) DROP_ONLY=true; shift ;;
  113. --init-only) INIT_ONLY=true; shift ;;
  114. *) log_error "未知选项: $1"; show_help; exit 1 ;;
  115. esac
  116. done
  117. log_title "数据库重建"
  118. echo "数据库: ${DB_NAME} @ ${DB_HOST}:${DB_PORT}"
  119. echo "初始化脚本: ${INIT_SQL}"
  120. echo ""
  121. if [ "$DROP_ONLY" = true ]; then
  122. drop_all_tables
  123. exit 0
  124. fi
  125. if [ "$INIT_ONLY" = true ]; then
  126. init_database
  127. [ "$CREATE_TEST_USER" = true ] && create_test_user
  128. log_info "初始化完成"
  129. exit 0
  130. fi
  131. drop_all_tables
  132. init_database
  133. [ "$CREATE_TEST_USER" = true ] && create_test_user
  134. log_info "重建完成"