迁移数据库从 SQLite 到 PostgreSQL
- 更新 deno.json 添加 postgres 依赖 - 重构 db/index.ts 使用 PostgreSQL 连接和适配器 - 更新所有路由文件支持异步数据库操作 - 将 SQLite 语法转换为 PostgreSQL 语法 - 添加数据库迁移文档和 schema 文件
This commit is contained in:
94
db/index.ts
94
db/index.ts
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user