rebuild_all.sh 12 KB

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