/** * Sqlite 数据库操作类 * @since Beta v0.9.0 */ import { app } from "@tauri-apps/api"; import Database from "@tauri-apps/plugin-sql"; import TGLogger from "@utils/TGLogger.js"; import initDataSql from "./sql/initData.js"; import { insertAppData } from "./sql/insertData.js"; class Sqlite { private readonly dbPath: string = "sqlite:TeyvatGuide.db"; private readonly tables: Readonly> = [ "Achievements", "AppData", "GachaRecords", "GachaBRecords", "GameAccount", "HardChallenge", "RoleCombat", "SpiralAbyss", "UFCollection", "UFMap", "UFPost", "UserAccount", "UserCharacters", "UserRecord", "UserBagMaterial", ]; private db: Database | null = null; private static instance: Sqlite | null = null; static getInstance(): Sqlite { if (this.instance === null) this.instance = new Sqlite(); return this.instance; } private constructor() {} /** * 获取数据库实例 * @since Beta v0.3.3 * @returns {Promise} */ public async getDB(): Promise { if (this.db === null) this.db = await Database.load(this.dbPath); return this.db; } /** * 检测是否需要创建数据库 * @since Beta v0.6.1 * @returns {Promise} */ public async check(): Promise { try { const db = await this.getDB(); let isVerified = false; const sqlT = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;"; const res: Array<{ name: string }> = await db.select(sqlT); if (this.tables.every((item) => res.map((i) => i.name).includes(item))) { isVerified = true; } return isVerified; } catch (e) { await TGLogger.Error(JSON.stringify(e)); return false; } } /** * 初始化数据库 * @since Beta v0.4.5 * @returns {Promise} */ public async initDB(): Promise { const db = await this.getDB(); const sql = await initDataSql(); for (const item of sql) await db.execute(item); } /** * 获取数据库信息 * @since Beta v0.3.3 * @returns {Promise} */ public async getAppData(): Promise { const db = await this.getDB(); const sql = "SELECT * FROM AppData;"; return await db.select(sql); } /** * 对比数据判断是否需要更新 * @since Beta v0.3.3 * @returns {Promise} */ public async checkUpdate(): Promise { const dbData = await this.getAppData(); const localVersion = await app.getVersion(); const dbVersion = dbData.find((item) => item.key === "appVersion")?.value; if (dbVersion === undefined) return true; return localVersion !== dbVersion; } /** * 保存 appData * @since Beta v0.3.3 * @param {string} key * @param {string} value * @returns {Promise} */ public async saveAppData(key: string, value: string): Promise { const db = await this.getDB(); const sql = insertAppData(key, value); await db.execute(sql); } /** * 已有数据表跟触发器不变的情况下,更新数据库数据 * @since Beta v0.3.3 * @returns {Promise} */ public async update(): Promise { const db = await this.getDB(); const sqlD = await initDataSql(); for (const item of sqlD) await db.execute(item); // 检测是否存在字段 await this.updateAbyss(); } /** * 更新 SpiralAbyss 表 * @since Beta v0.6.1 * @returns {Promise} */ public async updateAbyss(): Promise { const db = await this.getDB(); try { await db.select("SELECT skippedFloor FROM SpiralAbyss;"); } catch (e) { await TGLogger.Error(JSON.stringify(e)); const sql = "ALTER TABLE SpiralAbyss ADD skippedFloor TEXT DEFAULT ''"; await db.execute(sql); } } /** * 重置数据库 * @since Beta v0.4.0 * @returns {Promise} */ public async reset(): Promise { const db = await this.getDB(); for (const item of this.tables) { const sql = `DROP TABLE IF EXISTS ${item};`; await db.execute(sql); } await this.initDB(); } } const TGSqlite = Sqlite.getInstance(); export default TGSqlite;