class Database { private static instance: Database; private db: IDBDatabase | null = null; private dbName: string = '4nk'; private dbVersion: number = 1; private storeDefinitions = { AnkUser: { name: "user", options: {'keyPath': 'pre_id'}, indices: [] }, AnkSession: { name: "session", options: {}, indices: [] }, AnkProcess: { name: "process", options: {'keyPath': 'id'}, indices: [{ name: 'by_name', keyPath: 'name', options: { 'unique': true } }] }, AnkMessages: { name: "messages", options: {'keyPath': 'id'}, indices: [] } } // Private constructor to prevent direct instantiation from outside private constructor() {} // Method to access the singleton instance of Database public static async getInstance(): Promise { if (!Database.instance) { Database.instance = new Database(); await Database.instance.init(); } return Database.instance; } // Initialize the database private async init(): Promise { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.dbVersion); request.onupgradeneeded = () => { const db = request.result; Object.values(this.storeDefinitions).forEach(({name, options, indices}) => { if (!db.objectStoreNames.contains(name)) { let store = db.createObjectStore(name, options); indices.forEach(({name, keyPath, options}) => { store.createIndex(name, keyPath, options); }) } }); }; request.onsuccess = () => { this.db = request.result; resolve(); }; request.onerror = () => { console.error("Database error:", request.error); reject(request.error); }; }); } public async getDb(): Promise { if (!this.db) { await this.init(); } return this.db!; } public getStoreList(): {[key: string]: string} { const objectList: {[key: string]: string} = {}; Object.keys(this.storeDefinitions).forEach(key => { objectList[key] = this.storeDefinitions[key as keyof typeof this.storeDefinitions].name; }); return objectList; } public writeObject(db: IDBDatabase, storeName: string, obj: any, key: IDBValidKey | null): Promise { return new Promise((resolve, reject) => { const transaction = db.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); let request: IDBRequest; if (key) { request = store.add(obj, key); } else { request = store.add(obj); } request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); } public getObject(db: IDBDatabase, storeName: string, key: IDBValidKey): Promise { return new Promise((resolve, reject) => { const transaction = db.transaction(storeName, 'readonly'); const store = transaction.objectStore(storeName); const request = store.get(key); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); } public rmObject(db: IDBDatabase, storeName: string, key: IDBValidKey): Promise { return new Promise((resolve, reject) => { const transaction = db.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); const request = store.delete(key); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); } public getFirstMatchWithIndex(db: IDBDatabase, storeName: string, indexName: string, lookup: string): Promise { return new Promise((resolve, reject) => { const transaction = db.transaction(storeName, 'readonly'); const store = transaction.objectStore(storeName); const index = store.index(indexName); const request = index.openCursor(IDBKeyRange.only(lookup)); request.onerror = () => reject(request.error); request.onsuccess = () => { const cursor = request.result; if (cursor) { resolve(cursor.value); } else { resolve(null) } } }); } public setObject(db: IDBDatabase, storeName: string, obj: any, key: string | null): Promise { return new Promise((resolve, reject) => { const transaction = db.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); let request: IDBRequest; if (key) { request = store.put(obj, key); } else { request = store.put(obj); } request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); } public getAll(db: IDBDatabase, storeName: string): Promise { return new Promise((resolve, reject) => { const transaction = db.transaction(storeName, 'readonly'); const store = transaction.objectStore(storeName); const request = store.getAll(); request.onerror = () => reject(request.error); request.onsuccess = () => resolve(request.result); }); } } export default Database;