init: add workspace files
This commit is contained in:
200
data/db.js
Normal file
200
data/db.js
Normal file
@@ -0,0 +1,200 @@
|
||||
const Database = require("better-sqlite3");
|
||||
const path = require("path");
|
||||
const fs = require("fs").promises;
|
||||
const crypto = require("crypto");
|
||||
|
||||
const stmtCaches = new Map();
|
||||
|
||||
class SqliteDatabase {
|
||||
db_path = null;
|
||||
constructor() {
|
||||
this.db = null;
|
||||
}
|
||||
|
||||
// 获取预编译语句(带缓存)
|
||||
getStmt(sql) {
|
||||
let stmt = stmtCaches.get(sql);
|
||||
if (!stmt) {
|
||||
stmt = this.db.prepare(sql);
|
||||
stmtCaches.set(sql, stmt);
|
||||
}
|
||||
return stmt;
|
||||
}
|
||||
|
||||
// 初始化数据库
|
||||
async init(db_name) {
|
||||
try {
|
||||
this.db_path = path.join(__dirname, db_name);
|
||||
const fileExists = await this.checkDbFileExists();
|
||||
|
||||
if (!fileExists) {
|
||||
console.log("数据库文件不存在,正在创建...");
|
||||
this.db = new Database(this.db_path);
|
||||
await this.executeDefaultScripts();
|
||||
console.log("数据库初始化完成");
|
||||
} else {
|
||||
console.log("数据库文件已存在,正在连接...");
|
||||
this.db = new Database(this.db_path);
|
||||
await this.executeAlterScripts();
|
||||
console.log("数据库连接成功");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("数据库初始化失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// 检查数据库文件是否存在
|
||||
async checkDbFileExists() {
|
||||
try {
|
||||
await fs.access(this.db_path);
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 执行 ALTER 脚本(数据库已存在时)
|
||||
async executeAlterScripts() {
|
||||
for (let sql of ALTER_SCRIPTS) {
|
||||
try {
|
||||
await this.query(sql);
|
||||
} catch (error) {
|
||||
console.error(sql, "查询失败", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行默认建表脚本(数据库新建时)
|
||||
async executeDefaultScripts() {
|
||||
for (let sql of DEFAULT_TABLE_SCRIPTS) {
|
||||
try {
|
||||
await this.query(sql);
|
||||
} catch (error) {
|
||||
console.error(sql, "查询失败", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 执行 INSERT/UPDATE/DELETE 等操作
|
||||
query(sql, params = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const stmt = this.getStmt(sql);
|
||||
const info = stmt.run(...params);
|
||||
resolve({ lastID: info.lastInsertRowid, changes: info.changes });
|
||||
} catch (err) {
|
||||
console.error("SQL执行错误:", err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 查询单行数据
|
||||
get(sql, params = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const stmt = this.getStmt(sql);
|
||||
const row = stmt.get(...params);
|
||||
resolve(row);
|
||||
} catch (err) {
|
||||
console.error("SQL查询错误:", err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 查询多行数据
|
||||
all(sql, params = []) {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const stmt = this.getStmt(sql);
|
||||
const rows = stmt.all(...params);
|
||||
resolve(rows);
|
||||
} catch (err) {
|
||||
console.error("SQL查询错误:", err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 关闭数据库连接
|
||||
close() {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
if (this.db) {
|
||||
this.db.close();
|
||||
this.db = null;
|
||||
}
|
||||
resolve();
|
||||
} catch (err) {
|
||||
console.error("关闭数据库连接失败:", err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例
|
||||
module.exports = new SqliteDatabase();
|
||||
|
||||
// ---------- 建表及初始脚本 ----------
|
||||
const DEFAULT_TABLE_SCRIPTS = [
|
||||
`CREATE TABLE IF NOT EXISTS users (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(60) NOT NULL,
|
||||
pwd VARCHAR(60) NOT NULL,
|
||||
phone VARCHAR(20),
|
||||
state INTEGER DEFAULT 1,
|
||||
level INTEGER DEFAULT 0,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
UNIQUE (name)
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS servers (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name VARCHAR(60) NOT NULL,
|
||||
ip VARCHAR(60) NOT NULL,
|
||||
port VARCHAR(60) NOT NULL,
|
||||
state INTEGER DEFAULT 1,
|
||||
isdef INTEGER DEFAULT 0,
|
||||
istest INTEGER DEFAULT 0,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
start_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS players (
|
||||
id VARCHAR(40) NOT NULL,
|
||||
name VARCHAR(30) NOT NULL,
|
||||
userid INTEGER NOT NULL,
|
||||
sid INTEGER NOT NULL,
|
||||
level INTEGER DEFAULT 0,
|
||||
title VARCHAR(30) NOT NULL,
|
||||
data TEXT,
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)`,
|
||||
`CREATE TABLE IF NOT EXISTS players_bak (
|
||||
id VARCHAR(40) NOT NULL,
|
||||
name VARCHAR(30) NOT NULL,
|
||||
userid INTEGER NOT NULL,
|
||||
sid INTEGER NOT NULL,
|
||||
level INTEGER DEFAULT 0,
|
||||
title VARCHAR(30) NOT NULL,
|
||||
data TEXT,
|
||||
create_time TIMESTAMP,
|
||||
update_time TIMESTAMP
|
||||
)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS idx_users_name ON users (name)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS idx_players_id ON players (id)`,
|
||||
`CREATE INDEX IF NOT EXISTS idx_players_userid ON players (userid)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS idx_players_name ON players (name)`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS idx_players_bak_id ON players_bak (id)`,
|
||||
`INSERT OR IGNORE INTO users(id,name,pwd,level) VALUES(1,'administrator','${MD5("123456")}',6)`,
|
||||
];
|
||||
|
||||
function MD5(str) {
|
||||
let md5 = crypto.createHash("md5");
|
||||
let result = md5.update(str + process.env.MD5_PREFIX).digest("hex");
|
||||
return result.toUpperCase();
|
||||
}
|
||||
|
||||
const ALTER_SCRIPTS = [];
|
||||
Reference in New Issue
Block a user