添加数据库自动初始化功能

- 创建 db/init.ts 脚本,可自动创建数据库和表
- 更新 db/index.ts,应用启动时自动检查并创建表结构
- 添加 bun run init-db 命令用于初始化数据库
- 更新 README.md 添加数据库初始化说明
This commit is contained in:
ethan.chen
2026-01-08 14:58:04 +08:00
parent 02ebb4c648
commit d296108f67
4 changed files with 155 additions and 2 deletions

View File

@@ -14,6 +14,24 @@ bun run dev
bun run start
```
## 数据库初始化
首次运行前,需要初始化数据库:
```bash
# 方式一:使用初始化脚本(推荐,会自动创建数据库和表)
bun run init-db
# 方式二:手动创建数据库和表
# 1. 创建数据库
createdb media
# 或使用 psql
psql -U postgres -c "CREATE DATABASE media;"
# 2. 创建表结构
psql -U postgres -d media -f db/schema.sql
```
## 环境变量
配置以下环境变量:
@@ -27,3 +45,5 @@ bun run start
- `DB_HOST`: 数据库主机(默认: localhost
- `DB_PORT`: 数据库端口(默认: 5432
- `DB_NAME`: 数据库名称(默认: media
**注意**:应用启动时会自动检查并创建表结构(如果不存在),但不会自动创建数据库。请确保数据库已存在。

View File

@@ -5,6 +5,13 @@
* @FilePath: /my-score/honoback/db/index.ts
*/
import postgres from "postgres";
import { readFileSync } from "fs";
import { join, dirname } from "path";
// 获取当前文件所在目录
const __dirname = typeof import.meta.dir !== 'undefined'
? import.meta.dir
: dirname(new URL(import.meta.url).pathname);
// 从环境变量获取数据库连接信息
const DATABASE_URL =
@@ -18,6 +25,48 @@ const DATABASE_URL =
// 初始化 PostgreSQL 连接
const sql = postgres(DATABASE_URL);
// 自动初始化表结构(如果表不存在)
async function initTables() {
try {
// 检查 media 表是否存在
const tableExists = await sql`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'media'
)
`;
// 如果表不存在,创建表
if (!tableExists[0].exists) {
console.log("Initializing database tables...");
const schemaPath = join(__dirname, "schema.sql");
const schema = readFileSync(schemaPath, "utf-8");
await sql.unsafe(schema);
console.log("Database tables initialized successfully");
}
} catch (error: any) {
// 如果是因为数据库不存在,尝试创建数据库
if (
error.message?.includes("database") &&
error.message?.includes("does not exist")
) {
console.error("Database does not exist. Please create it first:");
console.error(" createdb media");
console.error(" or: psql -U postgres -c 'CREATE DATABASE media;'");
throw error;
}
// 其他错误也抛出
throw error;
}
}
// 在模块加载时初始化表(但不阻塞)
initTables().catch((error) => {
console.error("Failed to initialize tables:", error.message);
// 不抛出错误,让应用继续运行,但会在第一次查询时失败
});
// 将 SQLite 的 ? 占位符转换为 PostgreSQL 的 $1, $2, $3...
function convertQuery(query: string, params: any[]): [string, any[]] {
let pgQuery = query;

83
db/init.ts Normal file
View File

@@ -0,0 +1,83 @@
/*
* 数据库初始化脚本
* 自动创建数据库和表结构
*/
import postgres from "postgres";
import { readFileSync } from "fs";
import { join, dirname } from "path";
// 获取当前文件所在目录
const __dirname =
typeof import.meta.dir !== "undefined"
? import.meta.dir
: dirname(new URL(import.meta.url).pathname);
// 从环境变量获取数据库连接信息(不包含数据库名)
const getBaseConnection = () => {
const user = process.env.DB_USER || "postgres";
const password = process.env.DB_PASSWORD || "postgres";
const host = process.env.DB_HOST || "localhost";
const port = process.env.DB_PORT || "5432";
return `postgresql://${user}:${password}@${host}:${port}`;
};
// 初始化数据库
export async function initDatabase() {
const dbName = process.env.DB_NAME || "media";
const baseUrl = getBaseConnection();
try {
// 连接到 PostgreSQL 服务器(使用默认的 postgres 数据库)
const adminSql = postgres(`${baseUrl}/postgres`);
// 检查数据库是否存在
const dbExists = await adminSql`
SELECT 1 FROM pg_database WHERE datname = ${dbName}
`;
// 如果数据库不存在,创建它
if (dbExists.length === 0) {
console.log(`Creating database: ${dbName}`);
await adminSql.unsafe(`CREATE DATABASE ${dbName}`);
console.log(`Database ${dbName} created successfully`);
} else {
console.log(`Database ${dbName} already exists`);
}
await adminSql.end();
// 连接到新创建的数据库
const sql = postgres(`${baseUrl}/${dbName}`);
// 读取并执行 schema.sql
const schemaPath = join(__dirname, "schema.sql");
const schema = readFileSync(schemaPath, "utf-8");
// 执行 schema 中的 SQL 语句
console.log("Creating tables...");
await sql.unsafe(schema);
console.log("Tables created successfully");
await sql.end();
console.log("Database initialization completed");
} catch (error: any) {
console.error("Database initialization failed:", error.message);
throw error;
}
}
// 如果直接运行此文件,执行初始化
if (
import.meta.main ||
(typeof Bun !== "undefined" && Bun.main === import.meta.path)
) {
initDatabase()
.then(() => {
console.log("Initialization complete");
process.exit(0);
})
.catch((error) => {
console.error("Initialization failed:", error);
process.exit(1);
});
}

View File

@@ -6,7 +6,8 @@
"main": "main.ts",
"scripts": {
"start": "bun run main.ts",
"dev": "bun --watch main.ts"
"dev": "bun --watch main.ts",
"init-db": "bun run db/init.ts"
},
"keywords": [],
"author": "",
@@ -18,4 +19,4 @@
"devDependencies": {
"@types/bun": "latest"
}
}
}