添加数据库自动初始化功能
- 创建 db/init.ts 脚本,可自动创建数据库和表 - 更新 db/index.ts,应用启动时自动检查并创建表结构 - 添加 bun run init-db 命令用于初始化数据库 - 更新 README.md 添加数据库初始化说明
This commit is contained in:
20
README.md
20
README.md
@@ -14,6 +14,24 @@ bun run dev
|
|||||||
bun run start
|
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_HOST`: 数据库主机(默认: localhost)
|
||||||
- `DB_PORT`: 数据库端口(默认: 5432)
|
- `DB_PORT`: 数据库端口(默认: 5432)
|
||||||
- `DB_NAME`: 数据库名称(默认: media)
|
- `DB_NAME`: 数据库名称(默认: media)
|
||||||
|
|
||||||
|
**注意**:应用启动时会自动检查并创建表结构(如果不存在),但不会自动创建数据库。请确保数据库已存在。
|
||||||
|
|||||||
49
db/index.ts
49
db/index.ts
@@ -5,6 +5,13 @@
|
|||||||
* @FilePath: /my-score/honoback/db/index.ts
|
* @FilePath: /my-score/honoback/db/index.ts
|
||||||
*/
|
*/
|
||||||
import postgres from "postgres";
|
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 =
|
const DATABASE_URL =
|
||||||
@@ -18,6 +25,48 @@ const DATABASE_URL =
|
|||||||
// 初始化 PostgreSQL 连接
|
// 初始化 PostgreSQL 连接
|
||||||
const sql = postgres(DATABASE_URL);
|
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...
|
// 将 SQLite 的 ? 占位符转换为 PostgreSQL 的 $1, $2, $3...
|
||||||
function convertQuery(query: string, params: any[]): [string, any[]] {
|
function convertQuery(query: string, params: any[]): [string, any[]] {
|
||||||
let pgQuery = query;
|
let pgQuery = query;
|
||||||
|
|||||||
83
db/init.ts
Normal file
83
db/init.ts
Normal 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);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -6,7 +6,8 @@
|
|||||||
"main": "main.ts",
|
"main": "main.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "bun run main.ts",
|
"start": "bun run main.ts",
|
||||||
"dev": "bun --watch main.ts"
|
"dev": "bun --watch main.ts",
|
||||||
|
"init-db": "bun run db/init.ts"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user