From 4229894af28d134c960fd1a897df70e2c38ca2a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E4=BA=9A=E6=98=95?= <1549469775@qq.com> Date: Fri, 17 Oct 2025 17:42:23 +0800 Subject: [PATCH] feat: Update database schema and migration scripts - Added new migration scripts for the `users` table, replacing the deprecated `users_table`. - Updated `package.json` with new database commands for generating, pushing, and migrating schemas. - Enhanced `README.md` with instructions for database migration and deployment. - Refactored database connection handling to use a connection pool for improved performance. --- README.md | 13 ++++- packages/server/drizzle/0000_damp_rocket_racer.sql | 10 ++++ packages/server/drizzle/0000_thick_may_parker.sql | 8 --- packages/server/drizzle/meta/0000_snapshot.json | 59 ++++++++++++++-------- packages/server/drizzle/meta/_journal.json | 4 +- packages/server/package.json | 6 ++- packages/server/src/db/index.ts | 11 +++- packages/server/src/db/migrate.ts | 19 +++++++ packages/server/src/db/schema.ts | 19 ++++--- 9 files changed, 107 insertions(+), 42 deletions(-) create mode 100644 packages/server/drizzle/0000_damp_rocket_racer.sql delete mode 100644 packages/server/drizzle/0000_thick_may_parker.sql create mode 100644 packages/server/src/db/migrate.ts diff --git a/README.md b/README.md index 0c08638..1c13ac7 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,15 @@ https://www.doubao.com/chat/23869592666505474 ## 要求 -bun < 1.2.0 \ No newline at end of file +bun < 1.2.0 + + +# 1) 生成迁移(根据 schema 变更生成 SQL 到 packages/server/drizzle) +bun run --cwd packages/server db:generate # 生成迁移文件 + +# 2) 推送/迁移(任选其一) +bun run --cwd packages/server db:push # 直接将 schema 同步到 DB(简单场景) +bun run --cwd packages/server db:migrate # 执行已生成的迁移脚本(更可控) + +# 3) 部署阶段(CI/CD) +bun run --cwd packages/server deploy:migrate # 在部署容器/机器执行迁移 \ No newline at end of file diff --git a/packages/server/drizzle/0000_damp_rocket_racer.sql b/packages/server/drizzle/0000_damp_rocket_racer.sql new file mode 100644 index 0000000..951fc0d --- /dev/null +++ b/packages/server/drizzle/0000_damp_rocket_racer.sql @@ -0,0 +1,10 @@ +CREATE TABLE `users` ( + `id` serial AUTO_INCREMENT NOT NULL, + `username` varchar(64) NOT NULL, + `email` varchar(255) NOT NULL, + `password_hash` varchar(255) NOT NULL, + `is_active` boolean NOT NULL DEFAULT true, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `users_id` PRIMARY KEY(`id`) +); diff --git a/packages/server/drizzle/0000_thick_may_parker.sql b/packages/server/drizzle/0000_thick_may_parker.sql deleted file mode 100644 index 64a13c0..0000000 --- a/packages/server/drizzle/0000_thick_may_parker.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE `users_table` ( - `id` serial AUTO_INCREMENT NOT NULL, - `name` varchar(255) NOT NULL, - `age` int NOT NULL, - `email` varchar(255) NOT NULL, - CONSTRAINT `users_table_id` PRIMARY KEY(`id`), - CONSTRAINT `users_table_email_unique` UNIQUE(`email`) -); diff --git a/packages/server/drizzle/meta/0000_snapshot.json b/packages/server/drizzle/meta/0000_snapshot.json index cc53403..e71188b 100644 --- a/packages/server/drizzle/meta/0000_snapshot.json +++ b/packages/server/drizzle/meta/0000_snapshot.json @@ -1,11 +1,11 @@ { "version": "5", "dialect": "mysql", - "id": "3770df0e-b3f2-4223-8e66-2880f634d8b0", + "id": "df298012-0f90-4945-b49b-e9713616dcaf", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { - "users_table": { - "name": "users_table", + "users": { + "name": "users", "columns": { "id": { "name": "id", @@ -14,46 +14,63 @@ "notNull": true, "autoincrement": true }, - "name": { - "name": "name", - "type": "varchar(255)", + "username": { + "name": "username", + "type": "varchar(64)", "primaryKey": false, "notNull": true, "autoincrement": false }, - "age": { - "name": "age", - "type": "int", + "email": { + "name": "email", + "type": "varchar(255)", "primaryKey": false, "notNull": true, "autoincrement": false }, - "email": { - "name": "email", + "password_hash": { + "name": "password_hash", "type": "varchar(255)", "primaryKey": false, "notNull": true, "autoincrement": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" } }, "indexes": {}, "foreignKeys": {}, "compositePrimaryKeys": { - "users_table_id": { - "name": "users_table_id", + "users_id": { + "name": "users_id", "columns": [ "id" ] } }, - "uniqueConstraints": { - "users_table_email_unique": { - "name": "users_table_email_unique", - "columns": [ - "email" - ] - } - }, + "uniqueConstraints": {}, "checkConstraint": {} } }, diff --git a/packages/server/drizzle/meta/_journal.json b/packages/server/drizzle/meta/_journal.json index 3ced3d6..9e3e661 100644 --- a/packages/server/drizzle/meta/_journal.json +++ b/packages/server/drizzle/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "5", - "when": 1760625865036, - "tag": "0000_thick_may_parker", + "when": 1760694111964, + "tag": "0000_damp_rocket_racer", "breakpoints": true } ] diff --git a/packages/server/package.json b/packages/server/package.json index 366e5c3..05a36d1 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -8,7 +8,11 @@ } }, "scripts": { - "db": "bunx --bun drizzle-kit " + "db": "bunx --bun drizzle-kit", + "db:generate": "bunx --bun drizzle-kit generate", + "db:push": "bunx --bun drizzle-kit push", + "db:migrate": "bun run ./src/db/migrate.ts", + "deploy:migrate": "bun run ./src/db/migrate.ts" }, "devDependencies": { "@types/formidable": "^3.4.5", diff --git a/packages/server/src/db/index.ts b/packages/server/src/db/index.ts index ce84de8..9665533 100644 --- a/packages/server/src/db/index.ts +++ b/packages/server/src/db/index.ts @@ -1,4 +1,11 @@ import { drizzle } from "drizzle-orm/mysql2"; +import mysql from "mysql2/promise"; -// You can specify any property from the mysql2 connection options -const db = drizzle({ connection: { uri: process.env.DATABASE_URL } }); +// 使用连接池提升并发能力;支持通过 DATABASE_URL 直连(例:mysql://user:pass@host:3306/db) +// 生产/本地统一从环境变量读取,避免硬编码 +const pool = mysql.createPool(process.env.DATABASE_URL as string); + +// Drizzle 实例,供全局复用;建议在应用层只导入 db,不直接操作 pool +const db = drizzle(pool); + +export { db, pool }; diff --git a/packages/server/src/db/migrate.ts b/packages/server/src/db/migrate.ts new file mode 100644 index 0000000..7b89277 --- /dev/null +++ b/packages/server/src/db/migrate.ts @@ -0,0 +1,19 @@ +import { migrate } from 'drizzle-orm/mysql2/migrator' +import { db, pool } from './index' + +// 运行数据库迁移脚本(部署阶段调用) +// 要求:环境变量 DATABASE_URL 已配置 +// 迁移文件目录:packages/server/drizzle +(async () => { + try { + await migrate(db, { migrationsFolder: new URL('../../drizzle', import.meta.url).pathname }) + console.log('[drizzle] migration completed') + } catch (err) { + console.error('[drizzle] migration failed:', err) + process.exitCode = 1 + } finally { + await pool.end() + } +})() + + diff --git a/packages/server/src/db/schema.ts b/packages/server/src/db/schema.ts index 3ad5b0f..910849c 100644 --- a/packages/server/src/db/schema.ts +++ b/packages/server/src/db/schema.ts @@ -1,8 +1,13 @@ -import { int, mysqlTable, serial, varchar } from 'drizzle-orm/mysql-core'; +import { mysqlTable, serial, varchar, timestamp, boolean } from 'drizzle-orm/mysql-core' +import { sql } from 'drizzle-orm' -export const usersTable = mysqlTable('users_table', { - id: serial().primaryKey(), - name: varchar({ length: 255 }).notNull(), - age: int().notNull(), - email: varchar({ length: 255 }).notNull().unique(), -}); +// 用户表:满足基础登录/鉴权与审计需求 +export const usersTable = mysqlTable('users', { + id: serial('id').primaryKey(), // 自增主键 + username: varchar('username', { length: 64 }).notNull(), // 用户名,登录凭证之一 + email: varchar('email', { length: 255 }).notNull(), // 邮箱,唯一 + passwordHash: varchar('password_hash', { length: 255 }).notNull(), // 密码哈希 + isActive: boolean('is_active').notNull().default(true), // 启用状态 + createdAt: timestamp('created_at').notNull().default(sql`CURRENT_TIMESTAMP`), // 创建时间 + updatedAt: timestamp('updated_at').notNull().default(sql`CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP`), // 更新时间 +})