Files
ai-showcase-platform/lib/database.ts

213 lines
6.2 KiB
TypeScript

import mysql from 'mysql2/promise';
// 資料庫配置
const dbConfig = {
host: process.env.DB_HOST || 'mysql.theaken.com',
port: parseInt(process.env.DB_PORT || '33306'),
user: process.env.DB_USER || 'AI_Platform',
password: process.env.DB_PASSWORD || 'Aa123456',
database: process.env.DB_NAME || 'db_AI_Platform',
charset: 'utf8mb4',
timezone: '+08:00',
// 連接池配置
connectionLimit: 10,
acquireTimeout: 60000,
timeout: 60000,
reconnect: true
};
// 創建連接池
let pool: mysql.Pool | null = null;
export class Database {
private static instance: Database;
private constructor() {}
public static getInstance(): Database {
if (!Database.instance) {
Database.instance = new Database();
}
return Database.instance;
}
// 獲取連接池
public async getPool(): Promise<mysql.Pool> {
if (!pool) {
pool = mysql.createPool(dbConfig);
// 測試連接
try {
const connection = await pool.getConnection();
console.log('✅ 資料庫連接池建立成功');
connection.release();
} catch (error) {
console.error('❌ 資料庫連接池建立失敗:', error);
throw error;
}
}
return pool;
}
// 執行查詢
public async query<T = any>(sql: string, params?: any[]): Promise<T[]> {
const pool = await this.getPool();
try {
const [rows] = await pool.execute(sql, params);
return rows as T[];
} catch (error) {
console.error('查詢執行失敗:', error);
throw error;
}
}
// 執行單一查詢 (返回第一筆結果)
public async queryOne<T = any>(sql: string, params?: any[]): Promise<T | null> {
const results = await this.query<T>(sql, params);
return results.length > 0 ? results[0] : null;
}
// 執行插入
public async insert(table: string, data: Record<string, any>): Promise<number> {
const columns = Object.keys(data);
const values = Object.values(data);
const placeholders = columns.map(() => '?').join(', ');
const sql = `INSERT INTO ${table} (${columns.join(', ')}) VALUES (${placeholders})`;
const pool = await this.getPool();
try {
const [result] = await pool.execute(sql, values);
return (result as any).insertId;
} catch (error) {
console.error('插入執行失敗:', error);
throw error;
}
}
// 執行更新
public async update(table: string, data: Record<string, any>, where: Record<string, any>): Promise<number> {
const setColumns = Object.keys(data).map(col => `${col} = ?`).join(', ');
const whereColumns = Object.keys(where).map(col => `${col} = ?`).join(' AND ');
const sql = `UPDATE ${table} SET ${setColumns} WHERE ${whereColumns}`;
const values = [...Object.values(data), ...Object.values(where)];
const pool = await this.getPool();
try {
const [result] = await pool.execute(sql, values);
return (result as any).affectedRows;
} catch (error) {
console.error('更新執行失敗:', error);
throw error;
}
}
// 執行刪除
public async delete(table: string, where: Record<string, any>): Promise<number> {
const whereColumns = Object.keys(where).map(col => `${col} = ?`).join(' AND ');
const sql = `DELETE FROM ${table} WHERE ${whereColumns}`;
const values = Object.values(where);
const pool = await this.getPool();
try {
const [result] = await pool.execute(sql, values);
return (result as any).affectedRows;
} catch (error) {
console.error('刪除執行失敗:', error);
throw error;
}
}
// 開始事務
public async beginTransaction(): Promise<mysql.PoolConnection> {
const pool = await this.getPool();
const connection = await pool.getConnection();
await connection.beginTransaction();
return connection;
}
// 提交事務
public async commitTransaction(connection: mysql.PoolConnection): Promise<void> {
await connection.commit();
connection.release();
}
// 回滾事務
public async rollbackTransaction(connection: mysql.PoolConnection): Promise<void> {
await connection.rollback();
connection.release();
}
// 關閉連接池
public async close(): Promise<void> {
if (pool) {
await pool.end();
pool = null;
console.log('🔌 資料庫連接池已關閉');
}
}
// 健康檢查
public async healthCheck(): Promise<boolean> {
try {
const result = await this.queryOne('SELECT 1 as health');
return result?.health === 1;
} catch (error) {
console.error('資料庫健康檢查失敗:', error);
return false;
}
}
// 獲取資料庫統計
public async getDatabaseStats(): Promise<{
tables: number;
users: number;
competitions: number;
apps: number;
judges: number;
}> {
try {
const tablesResult = await this.queryOne(`
SELECT COUNT(*) as count
FROM information_schema.tables
WHERE table_schema = ?
`, [dbConfig.database]);
const usersResult = await this.queryOne('SELECT COUNT(*) as count FROM users');
const competitionsResult = await this.queryOne('SELECT COUNT(*) as count FROM competitions');
const appsResult = await this.queryOne('SELECT COUNT(*) as count FROM apps');
const judgesResult = await this.queryOne('SELECT COUNT(*) as count FROM judges');
return {
tables: tablesResult?.count || 0,
users: usersResult?.count || 0,
competitions: competitionsResult?.count || 0,
apps: appsResult?.count || 0,
judges: judgesResult?.count || 0
};
} catch (error) {
console.error('獲取資料庫統計失敗:', error);
throw error;
}
}
}
// 導出單例實例
export const db = Database.getInstance();
import bcrypt from 'bcrypt';
// 工具函數
export const generateId = (): string => {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
};
export const hashPassword = async (password: string): Promise<string> => {
const saltRounds = 12;
return bcrypt.hash(password, saltRounds);
};
export const comparePassword = async (password: string, hash: string): Promise<boolean> => {
return bcrypt.compare(password, hash);
};