rebuild_all.sh 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. #!/bin/bash
  2. # ============================================
  3. # 数据库完整重建脚本
  4. # 删除所有表并重新初始化(包含所有迁移)
  5. #
  6. # 更新日志:
  7. # 2026-01-23: 添加 --drop-only, --init-only, --list-migrations 选项
  8. # 2026-01-22: 添加 extract_tables 迁移支持
  9. # ============================================
  10. set -e
  11. # 颜色定义
  12. RED='\033[0;31m'
  13. GREEN='\033[0;32m'
  14. YELLOW='\033[1;33m'
  15. BLUE='\033[0;34m'
  16. CYAN='\033[0;36m'
  17. NC='\033[0m'
  18. # 数据库配置(根据实际情况修改)
  19. DB_HOST=${DB_HOST:-localhost}
  20. DB_PORT=${DB_PORT:-5432}
  21. DB_NAME=${DB_NAME:-lingyue_zhibao}
  22. DB_USER=${DB_USER:-postgres}
  23. DB_PASSWORD=${DB_PASSWORD:-postgres}
  24. log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
  25. log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
  26. log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
  27. log_title() { echo -e "\n${BLUE}========== $1 ==========${NC}\n"; }
  28. log_step() { echo -e "${CYAN}[STEP]${NC} $1"; }
  29. # 获取脚本所在目录
  30. SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  31. PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
  32. SQL_DIR="${SCRIPT_DIR}"
  33. MIGRATIONS_DIR="${PROJECT_ROOT}/database/migrations"
  34. # 删除所有表
  35. drop_all_tables() {
  36. log_title "删除所有表"
  37. if [ "$FORCE" != "yes" ]; then
  38. log_warn "这将删除数据库 ${DB_NAME} 中的所有表和数据!"
  39. read -p "是否继续?(yes/no): " confirm
  40. if [ "$confirm" != "yes" ]; then
  41. log_info "操作已取消"
  42. exit 0
  43. fi
  44. fi
  45. log_info "开始删除表..."
  46. PGPASSWORD=${DB_PASSWORD} psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -d ${DB_NAME} <<EOF
  47. -- 禁用外键约束检查
  48. SET session_replication_role = 'replica';
  49. -- 删除所有表
  50. DO \$\$
  51. DECLARE
  52. r RECORD;
  53. BEGIN
  54. FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = 'public')
  55. LOOP
  56. EXECUTE 'DROP TABLE IF EXISTS public.' || quote_ident(r.tablename) || ' CASCADE';
  57. RAISE NOTICE 'Dropped table: %', r.tablename;
  58. END LOOP;
  59. END
  60. \$\$;
  61. -- 删除所有序列
  62. DO \$\$
  63. DECLARE
  64. r RECORD;
  65. BEGIN
  66. FOR r IN (SELECT sequencename FROM pg_sequences WHERE schemaname = 'public')
  67. LOOP
  68. EXECUTE 'DROP SEQUENCE IF EXISTS public.' || quote_ident(r.sequencename) || ' CASCADE';
  69. END LOOP;
  70. END
  71. \$\$;
  72. -- 删除所有函数
  73. DO \$\$
  74. DECLARE
  75. r RECORD;
  76. BEGIN
  77. FOR r IN (SELECT proname, oidvectortypes(proargtypes) as args
  78. FROM pg_proc
  79. INNER JOIN pg_namespace ns ON (pg_proc.pronamespace = ns.oid)
  80. WHERE ns.nspname = 'public')
  81. LOOP
  82. EXECUTE 'DROP FUNCTION IF EXISTS public.' || quote_ident(r.proname) || '(' || r.args || ') CASCADE';
  83. END LOOP;
  84. END
  85. \$\$;
  86. -- 恢复外键约束检查
  87. SET session_replication_role = 'origin';
  88. SELECT 'Tables remaining:' as status, COUNT(*) as count FROM pg_tables WHERE schemaname = 'public';
  89. EOF
  90. log_info "所有表已删除"
  91. }
  92. # 执行 SQL 文件
  93. execute_sql() {
  94. local file=$1
  95. local desc=$2
  96. if [ -f "$file" ]; then
  97. log_info "执行: ${desc} (${file})"
  98. PGPASSWORD=${DB_PASSWORD} psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -d ${DB_NAME} -f "$file" 2>&1 | grep -v "^NOTICE:" || true
  99. log_info "${desc} 完成"
  100. else
  101. log_warn "文件不存在: ${file}"
  102. fi
  103. }
  104. # 列出迁移脚本
  105. list_migrations() {
  106. log_title "迁移脚本列表"
  107. if [ -d "$MIGRATIONS_DIR" ]; then
  108. local count=0
  109. echo ""
  110. printf " %-5s %-60s %s\n" "序号" "文件名" "大小"
  111. echo " -------------------------------------------------------------------------"
  112. for migration in $(ls -1 "${MIGRATIONS_DIR}"/*.sql 2>/dev/null | sort); do
  113. if [ -f "$migration" ]; then
  114. count=$((count + 1))
  115. local size=$(du -h "$migration" | cut -f1)
  116. printf " %-5s %-60s %s\n" "$count" "$(basename $migration)" "$size"
  117. fi
  118. done
  119. echo ""
  120. log_info "共 ${count} 个迁移脚本"
  121. else
  122. log_warn "迁移目录不存在: ${MIGRATIONS_DIR}"
  123. fi
  124. }
  125. # 初始化所有表
  126. init_all_tables() {
  127. log_title "初始化数据库表"
  128. local step=1
  129. # 1. 基础表(users, documents 等核心表)
  130. log_step "[$step/6] 基础表"
  131. execute_sql "${SQL_DIR}/init.sql" "基础表 (users, documents, elements, etc.)"
  132. step=$((step + 1))
  133. # 2. 图谱表(graph_nodes, graph_relations - 先于 supplement_tables)
  134. log_step "[$step/6] 图谱表"
  135. execute_sql "${SQL_DIR}/graph_tables.sql" "图谱表 (graph_nodes, graph_relations)"
  136. step=$((step + 1))
  137. # 3. 补充表(rules, data_sources, text_storage 等,不含 templates)
  138. log_step "[$step/6] 补充表"
  139. execute_sql "${SQL_DIR}/supplement_tables.sql" "补充表 (rules, data_sources, text_storage)"
  140. step=$((step + 1))
  141. # 4. RAG 表(text_chunks, vector_embeddings - 可能需要 pgvector)
  142. log_step "[$step/6] RAG 表"
  143. execute_sql "${SQL_DIR}/rag_tables_compatible.sql" "RAG 表 (text_chunks, vector_embeddings)"
  144. step=$((step + 1))
  145. # 5. 模板系统表(templates, source_files, variables, generations)
  146. log_step "[$step/6] 模板系统表"
  147. execute_sql "${SQL_DIR}/template_tables.sql" "模板系统表 (templates, source_files, variables, generations)"
  148. step=$((step + 1))
  149. # 6. 执行迁移文件(按文件名排序)
  150. log_step "[$step/6] 迁移脚本"
  151. log_title "执行迁移脚本"
  152. if [ -d "$MIGRATIONS_DIR" ]; then
  153. local migration_count=0
  154. local total_migrations=$(ls -1 "${MIGRATIONS_DIR}"/*.sql 2>/dev/null | wc -l)
  155. for migration in $(ls -1 "${MIGRATIONS_DIR}"/*.sql 2>/dev/null | sort); do
  156. if [ -f "$migration" ]; then
  157. migration_count=$((migration_count + 1))
  158. execute_sql "$migration" "[$migration_count/$total_migrations] $(basename $migration)"
  159. fi
  160. done
  161. log_info "共执行 ${migration_count} 个迁移脚本"
  162. else
  163. log_warn "迁移目录不存在: ${MIGRATIONS_DIR}"
  164. fi
  165. }
  166. # 验证表创建
  167. verify_tables() {
  168. log_title "验证表创建"
  169. PGPASSWORD=${DB_PASSWORD} psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -d ${DB_NAME} <<EOF
  170. SELECT tablename as "表名"
  171. FROM pg_tables
  172. WHERE schemaname = 'public'
  173. ORDER BY tablename;
  174. SELECT COUNT(*) as "表总数" FROM pg_tables WHERE schemaname = 'public';
  175. EOF
  176. }
  177. # 创建测试用户
  178. create_test_user() {
  179. log_title "创建测试用户"
  180. PGPASSWORD=${DB_PASSWORD} psql -h ${DB_HOST} -p ${DB_PORT} -U ${DB_USER} -d ${DB_NAME} <<EOF
  181. -- 插入测试管理员用户(密码: Admin123!)
  182. INSERT INTO users (id, username, email, password_hash, role, create_time, update_time)
  183. VALUES (
  184. '00000000000000000000000000000001',
  185. 'admin',
  186. 'admin@lingyue.com',
  187. '\$2a\$10\$N.zmdr9k7uOCQb376NoUnuTJ8iUtkWBrq.VZbISbAi1L9sNPIiMMi',
  188. 'admin',
  189. CURRENT_TIMESTAMP,
  190. CURRENT_TIMESTAMP
  191. )
  192. ON CONFLICT (id) DO NOTHING;
  193. -- 插入测试普通用户(密码: User1234!)
  194. INSERT INTO users (id, username, email, password_hash, role, create_time, update_time)
  195. VALUES (
  196. '00000000000000000000000000000002',
  197. 'testuser',
  198. 'test@lingyue.com',
  199. '\$2a\$10\$5XvCJaLqDXJz.YqL8TnNKegHH7q6KM7YFzMVxLPNMvJx5f7mxnKQi',
  200. 'user',
  201. CURRENT_TIMESTAMP,
  202. CURRENT_TIMESTAMP
  203. )
  204. ON CONFLICT (id) DO NOTHING;
  205. SELECT id, username, email, role FROM users;
  206. EOF
  207. log_info "测试用户创建完成"
  208. log_info " admin / Admin123!"
  209. log_info " testuser / User1234!"
  210. }
  211. # 显示帮助
  212. show_help() {
  213. cat <<EOF
  214. 数据库完整重建脚本
  215. 用法: ./rebuild_all.sh [选项]
  216. 选项:
  217. -h, --help 显示帮助
  218. -f, --force 跳过确认提示
  219. --no-test-user 不创建测试用户
  220. --drop-only 只删除表,不初始化
  221. --init-only 只初始化,不删除(用于全新数据库)
  222. --list-migrations 列出所有迁移脚本后退出
  223. 环境变量:
  224. DB_HOST 数据库主机 (默认: localhost)
  225. DB_PORT 数据库端口 (默认: 5432)
  226. DB_NAME 数据库名称 (默认: lingyue_zhibao)
  227. DB_USER 数据库用户 (默认: postgres)
  228. DB_PASSWORD 数据库密码 (默认: postgres)
  229. 示例:
  230. # 使用默认配置(删除 + 重建)
  231. ./rebuild_all.sh
  232. # 指定数据库配置
  233. DB_PASSWORD=mypassword ./rebuild_all.sh
  234. # 强制执行(跳过确认)
  235. ./rebuild_all.sh -f
  236. # 只删除所有表
  237. ./rebuild_all.sh --drop-only -f
  238. # 初始化全新数据库(不删除)
  239. ./rebuild_all.sh --init-only
  240. # 查看迁移脚本列表
  241. ./rebuild_all.sh --list-migrations
  242. # 服务器上执行
  243. DB_USER=lingyue DB_PASSWORD=123123 ./rebuild_all.sh
  244. 执行顺序:
  245. 1. 删除所有表、序列、函数
  246. 2. 执行 init.sql(用户、文档、元素等基础表)
  247. 3. 执行 graph_tables.sql(图谱表)
  248. 4. 执行 supplement_tables.sql(补充表,不含 templates)
  249. 5. 执行 rag_tables_compatible.sql(RAG表)
  250. 6. 执行 template_tables.sql(模板系统表 v2.0)
  251. - templates: 报告模板
  252. - source_files: 来源文件定义
  253. - variables: 模板变量
  254. - generations: 生成任务
  255. 7. 执行 database/migrations/*.sql(迁移脚本,按名称排序)
  256. 8. 创建测试用户
  257. 9. 验证表创建
  258. EOF
  259. }
  260. # 主函数
  261. main() {
  262. CREATE_TEST_USER=true
  263. DROP_ONLY=false
  264. INIT_ONLY=false
  265. LIST_MIGRATIONS=false
  266. while [[ $# -gt 0 ]]; do
  267. case $1 in
  268. -h|--help)
  269. show_help
  270. exit 0
  271. ;;
  272. -f|--force)
  273. FORCE=yes
  274. shift
  275. ;;
  276. --no-test-user)
  277. CREATE_TEST_USER=false
  278. shift
  279. ;;
  280. --drop-only)
  281. DROP_ONLY=true
  282. shift
  283. ;;
  284. --init-only)
  285. INIT_ONLY=true
  286. shift
  287. ;;
  288. --list-migrations)
  289. LIST_MIGRATIONS=true
  290. shift
  291. ;;
  292. *)
  293. log_error "未知选项: $1"
  294. show_help
  295. exit 1
  296. ;;
  297. esac
  298. done
  299. log_title "数据库完整重建脚本"
  300. echo "数据库: ${DB_NAME}"
  301. echo "主机: ${DB_HOST}:${DB_PORT}"
  302. echo "用户: ${DB_USER}"
  303. echo "SQL目录: ${SQL_DIR}"
  304. echo "迁移目录: ${MIGRATIONS_DIR}"
  305. echo ""
  306. # 列出迁移脚本模式
  307. if [ "$LIST_MIGRATIONS" = true ]; then
  308. list_migrations
  309. exit 0
  310. fi
  311. # 只删除模式
  312. if [ "$DROP_ONLY" = true ]; then
  313. drop_all_tables
  314. log_title "删除完成"
  315. log_info "所有表已删除,数据库已清空"
  316. exit 0
  317. fi
  318. # 只初始化模式
  319. if [ "$INIT_ONLY" = true ]; then
  320. init_all_tables
  321. if [ "$CREATE_TEST_USER" = true ]; then
  322. create_test_user
  323. fi
  324. verify_tables
  325. log_title "初始化完成"
  326. log_info "所有表已创建并验证"
  327. exit 0
  328. fi
  329. # 完整重建模式
  330. drop_all_tables
  331. init_all_tables
  332. if [ "$CREATE_TEST_USER" = true ]; then
  333. create_test_user
  334. fi
  335. verify_tables
  336. log_title "数据库重建完成"
  337. log_info "所有表已创建并验证"
  338. }
  339. main "$@"