迁移数据库从 SQLite 到 PostgreSQL

- 更新 deno.json 添加 postgres 依赖
- 重构 db/index.ts 使用 PostgreSQL 连接和适配器
- 更新所有路由文件支持异步数据库操作
- 将 SQLite 语法转换为 PostgreSQL 语法
- 添加数据库迁移文档和 schema 文件
This commit is contained in:
ethan.chen
2026-01-08 14:26:27 +08:00
parent 32f7b86f28
commit 2b5b2f1d97
7 changed files with 409 additions and 120 deletions

View File

@@ -4,13 +4,93 @@
* @LastEditTime: 2025-06-13 14:23:03
* @FilePath: /my-score/honoback/db/index.ts
*/
import { DatabaseSync } from "node:sqlite"
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import postgres from "postgres";
const __dirname = dirname(fileURLToPath(import.meta.url))
// 从环境变量获取数据库连接信息
const DATABASE_URL =
Deno.env.get("DATABASE_URL") ||
`postgresql://${Deno.env.get("DB_USER") || "postgres"}:${
Deno.env.get("DB_PASSWORD") || "postgres"
}@${Deno.env.get("DB_HOST") || "localhost"}:${
Deno.env.get("DB_PORT") || "5432"
}/${Deno.env.get("DB_NAME") || "media"}`;
// 初始化数据库连接
const db = new DatabaseSync(join(__dirname, 'media.db'))
// 初始化 PostgreSQL 连接
const sql = postgres(DATABASE_URL);
export { db }
// 将 SQLite 的 ? 占位符转换为 PostgreSQL 的 $1, $2, $3...
function convertQuery(query: string, params: any[]): [string, any[]] {
let pgQuery = query;
let paramIndex = 1;
const pgParams: any[] = [];
// 替换 ? 为 $1, $2, $3...
pgQuery = pgQuery.replace(/\?/g, () => {
if (paramIndex <= params.length) {
pgParams.push(params[paramIndex - 1]);
}
return `$${paramIndex++}`;
});
return [pgQuery, pgParams];
}
// 创建一个兼容的数据库接口,模拟 SQLite 的 prepare 方法
class DatabaseAdapter {
private sql: ReturnType<typeof postgres>;
constructor(sql: ReturnType<typeof postgres>) {
this.sql = sql;
}
prepare(query: string) {
return {
// all() 方法用于查询多条记录
all: async (...params: any[]) => {
const [pgQuery, pgParams] = convertQuery(query, params);
const result = await this.sql.unsafe(pgQuery, pgParams);
return result;
},
// get() 方法用于查询单条记录
get: async (...params: any[]) => {
const [pgQuery, pgParams] = convertQuery(query, params);
const result = await this.sql.unsafe(pgQuery, pgParams);
return result[0] || null;
},
// run() 方法用于执行 INSERT/UPDATE/DELETE
run: async (...params: any[]) => {
const [pgQuery, pgParams] = convertQuery(query, params);
const result = await this.sql.unsafe(pgQuery, pgParams);
// 如果是 INSERT 语句,返回类似 SQLite 的 lastInsertRowid
if (query.trim().toUpperCase().startsWith("INSERT")) {
// PostgreSQL 使用 RETURNING 子句获取插入的 ID
if (query.includes("RETURNING")) {
return {
lastInsertRowid: result[0]?.id || null,
changes: result.length,
};
} else {
// 如果没有 RETURNING需要查询最后插入的 ID
// 注意:这需要表有 id 列且是 SERIAL 类型
const lastIdResult = await this.sql.unsafe(
"SELECT lastval() as id"
);
return {
lastInsertRowid: lastIdResult[0]?.id || null,
changes: result.length || 1,
};
}
}
return {
changes: result.length || 0,
};
},
};
}
}
const db = new DatabaseAdapter(sql);
export { db, sql };