diff --git a/README.md b/README.md index 02c59d6..87999f1 100644 --- a/README.md +++ b/README.md @@ -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) + +**注意**:应用启动时会自动检查并创建表结构(如果不存在),但不会自动创建数据库。请确保数据库已存在。 diff --git a/db/index.ts b/db/index.ts index e32bb85..c31b803 100644 --- a/db/index.ts +++ b/db/index.ts @@ -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; diff --git a/db/init.ts b/db/init.ts new file mode 100644 index 0000000..4b882c2 --- /dev/null +++ b/db/init.ts @@ -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); + }); +} diff --git a/package.json b/package.json index 18be6a6..7960c31 100644 --- a/package.json +++ b/package.json @@ -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" } -} +} \ No newline at end of file