UNPKG

@eka-care/patient-ts-sdk

Version:

TypeScript SDK for Trinity Patient Profile Management System

247 lines (246 loc) 9.94 kB
/** * IndexedDB service for local patient data storage */ export class IndexedDBService { constructor(workspaceId) { this.dbName = 'TrinityProfilesDB'; this.version = 1; this.db = null; this.workspaceId = workspaceId; } /** * Initialize the IndexedDB connection */ async init() { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.version); request.onerror = () => reject(request.error); request.onsuccess = () => { this.db = request.result; // Create object store for patients with workspace-specific naming // const storeName = this.getStoreName(); // if (!this.db.objectStoreNames.contains(storeName)) { // const store = this.db.createObjectStore(storeName, { keyPath: 'oid' }); // // Create indexes for search fields // store.createIndex('fln', 'fln', { unique: false }); // store.createIndex('mobile', 'mobile', { unique: false }); // store.createIndex('username', 'username', { unique: false }); // store.createIndex('u_ate', 'u_ate', { unique: false }); // } resolve(); }; request.onupgradeneeded = (event) => { const db = event.target.result; // Create object store for patients with workspace-specific naming const storeName = this.getStoreName(); if (!db.objectStoreNames.contains(storeName)) { const store = db.createObjectStore(storeName, { keyPath: 'oid' }); // Create indexes for search fields store.createIndex('fln', 'fln', { unique: false }); store.createIndex('mobile', 'mobile', { unique: false }); store.createIndex('username', 'username', { unique: false }); store.createIndex('u_ate', 'u_ate', { unique: false }); } }; }); } /** * Get workspace-specific store name */ getStoreName() { return `patients_${this.workspaceId}`; } /** * Store multiple patients in batch */ async batchStore(patients) { if (!this.db) throw new Error('Database not initialized'); // return new Promise((resolve, reject) => { // const transaction = this.db!.transaction([this.getStoreName()], 'readwrite'); // const store = transaction.objectStore(this.getStoreName()); // transaction.oncomplete = () => resolve(); // transaction.onerror = () => reject(transaction.error); // patients.forEach(patient => { // store.put(patient); // }); // }); const storeName = this.getStoreName(); if (!this.db.objectStoreNames.contains(storeName)) { // Close current connection and reinitialize this.close(); await this.init(); // Check again after reinitialization if (!this.db?.objectStoreNames.contains(storeName)) { throw new Error(`Object store '${storeName}' still not found after reinitialization`); } } return new Promise((resolve, reject) => { try { const transaction = this.db.transaction([this.getStoreName()], 'readwrite'); const store = transaction.objectStore(this.getStoreName()); transaction.oncomplete = () => { console.log('Batch store transaction completed successfully'); resolve(); }; transaction.onerror = () => { console.error('Batch store transaction error:', transaction.error); reject(transaction.error); }; patients.forEach(patient => { store.put(patient); }); } catch (error) { console.error('Error creating transaction:', error); reject(error); } }); } /** * Search patients by prefix with field-specific logic */ async searchByPrefix(prefix, limit = 50) { if (!this.db) throw new Error('Database not initialized'); const results = []; const isNumeric = /^\d+$/.test(prefix); const lowerPrefix = prefix.toLowerCase(); return new Promise((resolve, reject) => { const transaction = this.db.transaction([this.getStoreName()], 'readonly'); const store = transaction.objectStore(this.getStoreName()); const request = store.openCursor(); request.onsuccess = (event) => { const cursor = event.target.result; if (cursor && results.length < limit) { const patient = cursor.value; let match = false; if (isNumeric) { // Search in mobile and username fields for numeric prefix if (patient.mobile?.startsWith(prefix) || patient.username?.toLowerCase().startsWith(lowerPrefix)) { match = true; } } else { // Search in fln and username fields for alphabetic prefix if (patient.fln?.toLowerCase().startsWith(lowerPrefix) || patient.username?.toLowerCase().startsWith(lowerPrefix)) { match = true; } } if (match) { results.push(patient); } cursor.continue(); } else { resolve(results); } }; request.onerror = () => reject(request.error); }); } /** * Get patient by OID (primary key) */ async getByOid(oid) { if (!this.db) throw new Error('Database not initialized'); return new Promise((resolve, reject) => { const transaction = this.db.transaction([this.getStoreName()], 'readonly'); const store = transaction.objectStore(this.getStoreName()); const request = store.get(oid); request.onsuccess = () => resolve(request.result || null); request.onerror = () => reject(request.error); }); } /** * Update single patient by OID */ async updatePatient(patient) { if (!this.db) throw new Error('Database not initialized'); return new Promise((resolve, reject) => { const transaction = this.db.transaction([this.getStoreName()], 'readwrite'); const store = transaction.objectStore(this.getStoreName()); const request = store.put(patient); request.onsuccess = () => resolve(); request.onerror = () => reject(request.error); }); } /** * Check if any data exists */ async hasData() { if (!this.db) throw new Error('Database not initialized'); return new Promise((resolve, reject) => { const transaction = this.db.transaction([this.getStoreName()], 'readonly'); const store = transaction.objectStore(this.getStoreName()); const request = store.count(); request.onsuccess = () => resolve(request.result > 0); request.onerror = () => reject(request.error); }); } /** * Get all patients (for internal use) */ async getAllPatients() { if (!this.db) throw new Error('Database not initialized'); return new Promise((resolve, reject) => { const transaction = this.db.transaction([this.getStoreName()], 'readonly'); const store = transaction.objectStore(this.getStoreName()); const request = store.getAll(); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } /** * Get the latest update timestamp */ async getLatestUpdateTime() { if (!this.db) throw new Error('Database not initialized'); return new Promise((resolve, reject) => { const transaction = this.db.transaction([this.getStoreName()], 'readonly'); const store = transaction.objectStore(this.getStoreName()); const index = store.index('u_ate'); const request = index.openCursor(null, 'prev'); request.onsuccess = () => { const cursor = request.result; if (cursor) { resolve(cursor.value.u_ate); } else { resolve(0); } }; request.onerror = () => reject(request.error); }); } /** * Clear all data for the current workspace */ async clearData() { if (!this.db) throw new Error('Database not initialized'); return new Promise((resolve, reject) => { const transaction = this.db.transaction([this.getStoreName()], 'readwrite'); const store = transaction.objectStore(this.getStoreName()); const request = store.clear(); request.onsuccess = () => resolve(); request.onerror = () => reject(request.error); }); } /** * Close the database connection */ close() { if (this.db) { this.db.close(); this.db = null; } } }