diff --git a/web/database/utils/store.js b/web/database/utils/store.js index 12199b1bd..fc519eb99 100644 --- a/web/database/utils/store.js +++ b/web/database/utils/store.js @@ -1,81 +1,92 @@ // @flow import { reportStoreOpsHandlers } from 'lib/ops/report-store-ops.js'; import { threadStoreOpsHandlers } from 'lib/ops/thread-store-ops.js'; import { canUseDatabaseOnWeb } from 'lib/shared/web-database.js'; import type { ClientStore, StoreOperations, } from 'lib/types/store-ops-types.js'; import { workerRequestMessageTypes } from '../../types/worker-types.js'; import { getDatabaseModule } from '../database-module-provider.js'; async function getClientStore(): Promise { const databaseModule = await getDatabaseModule(); let result: ClientStore = { currentUserID: null, drafts: [], messages: null, threadStore: null, messageStoreThreads: null, reports: null, users: null, }; const data = await databaseModule.schedule({ type: workerRequestMessageTypes.GET_CLIENT_STORE, }); if (data?.store?.drafts) { result = { ...result, drafts: data.store.drafts, }; } if (data?.store?.reports) { result = { ...result, reports: reportStoreOpsHandlers.translateClientDBData(data.store.reports), }; } if (data?.store?.threads && data.store.threads.length > 0) { result = { ...result, threadStore: { threadInfos: threadStoreOpsHandlers.translateClientDBData( data.store.threads, ), }, }; } return result; } async function processDBStoreOperations( storeOperations: StoreOperations, userID: ?string, ): Promise { const { draftStoreOperations, threadStoreOperations, reportStoreOperations } = storeOperations; - const convertedThreadStoreOperations = canUseDatabaseOnWeb(userID) + const canUseDatabase = canUseDatabaseOnWeb(userID); + + const convertedThreadStoreOperations = canUseDatabase ? threadStoreOpsHandlers.convertOpsToClientDBOps(threadStoreOperations) : []; const convertedReportStoreOperations = reportStoreOpsHandlers.convertOpsToClientDBOps(reportStoreOperations); const databaseModule = await getDatabaseModule(); const isSupported = await databaseModule.isDatabaseSupported(); if (!isSupported) { return; } - await databaseModule.schedule({ - type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, - storeOperations: { - draftStoreOperations, - reportStoreOperations: convertedReportStoreOperations, - threadStoreOperations: convertedThreadStoreOperations, - }, - }); + try { + await databaseModule.schedule({ + type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, + storeOperations: { + draftStoreOperations, + reportStoreOperations: convertedReportStoreOperations, + threadStoreOperations: convertedThreadStoreOperations, + }, + }); + } catch (e) { + console.log(e); + if (canUseDatabase) { + window.alert(e.message); + await databaseModule.init({ clearDatabase: true }); + location.reload(); + } + } } export { getClientStore, processDBStoreOperations }; diff --git a/web/database/worker/process-operations.js b/web/database/worker/process-operations.js index a4d9422fe..b4541c23d 100644 --- a/web/database/worker/process-operations.js +++ b/web/database/worker/process-operations.js @@ -1,118 +1,144 @@ // @flow import type { ClientDBReportStoreOperation } from 'lib/ops/report-store-ops.js'; import type { ClientDBThreadStoreOperation } from 'lib/ops/thread-store-ops.js'; import type { ClientDBDraftStoreOperation, DraftStoreOperation, } from 'lib/types/draft-types.js'; import type { ClientDBStore, ClientDBStoreOperations, } from 'lib/types/store-ops-types.js'; +import { getMessageForException } from 'lib/utils/errors.js'; import { clientDBThreadInfoToWebThread, webThreadToClientDBThreadInfo, } from '../types/entities.js'; import type { SQLiteQueryExecutor } from '../types/sqlite-query-executor.js'; function processDraftStoreOperations( sqliteQueryExecutor: SQLiteQueryExecutor, operations: $ReadOnlyArray, ) { for (const operation: DraftStoreOperation of operations) { - if (operation.type === 'remove_all') { - sqliteQueryExecutor.removeAllDrafts(); - } else if (operation.type === 'update') { - const { key, text } = operation.payload; - sqliteQueryExecutor.updateDraft(key, text); - } else if (operation.type === 'move') { - const { oldKey, newKey } = operation.payload; - sqliteQueryExecutor.moveDraft(oldKey, newKey); - } else { - throw new Error('Unsupported draft operation'); + try { + if (operation.type === 'remove_all') { + sqliteQueryExecutor.removeAllDrafts(); + } else if (operation.type === 'update') { + const { key, text } = operation.payload; + sqliteQueryExecutor.updateDraft(key, text); + } else if (operation.type === 'move') { + const { oldKey, newKey } = operation.payload; + sqliteQueryExecutor.moveDraft(oldKey, newKey); + } else { + throw new Error('Unsupported draft operation'); + } + } catch (e) { + throw new Error( + `Error while processing draft operation: ${operation.type}: ${ + getMessageForException(e) ?? 'unknown error' + }`, + ); } } } function processReportStoreOperations( sqliteQueryExecutor: SQLiteQueryExecutor, operations: $ReadOnlyArray, ) { for (const operation: ClientDBReportStoreOperation of operations) { - if (operation.type === 'remove_all_reports') { - sqliteQueryExecutor.removeAllReports(); - } else if (operation.type === 'remove_reports') { - const { ids } = operation.payload; - sqliteQueryExecutor.removeReports(ids); - } else if (operation.type === 'replace_report') { - const { id, report } = operation.payload; - sqliteQueryExecutor.replaceReport({ id, report }); - } else { - throw new Error('Unsupported report operation'); + try { + if (operation.type === 'remove_all_reports') { + sqliteQueryExecutor.removeAllReports(); + } else if (operation.type === 'remove_reports') { + const { ids } = operation.payload; + sqliteQueryExecutor.removeReports(ids); + } else if (operation.type === 'replace_report') { + const { id, report } = operation.payload; + sqliteQueryExecutor.replaceReport({ id, report }); + } else { + throw new Error('Unsupported report operation'); + } + } catch (e) { + throw new Error( + `Error while processing report operation: ${operation.type}: ${ + getMessageForException(e) ?? 'unknown error' + }`, + ); } } } function processThreadStoreOperations( sqliteQueryExecutor: SQLiteQueryExecutor, operations: $ReadOnlyArray, ) { for (const operation: ClientDBThreadStoreOperation of operations) { - if (operation.type === 'remove_all') { - sqliteQueryExecutor.removeAllThreads(); - } else if (operation.type === 'remove') { - const { ids } = operation.payload; - sqliteQueryExecutor.removeThreads(ids); - } else if (operation.type === 'replace') { - sqliteQueryExecutor.replaceThreadWeb( - clientDBThreadInfoToWebThread(operation.payload), + try { + if (operation.type === 'remove_all') { + sqliteQueryExecutor.removeAllThreads(); + } else if (operation.type === 'remove') { + const { ids } = operation.payload; + sqliteQueryExecutor.removeThreads(ids); + } else if (operation.type === 'replace') { + sqliteQueryExecutor.replaceThreadWeb( + clientDBThreadInfoToWebThread(operation.payload), + ); + } else { + throw new Error('Unsupported thread operation'); + } + } catch (e) { + throw new Error( + `Error while processing thread operation: ${operation.type}: ${ + getMessageForException(e) ?? 'unknown error' + }`, ); - } else { - throw new Error('Unsupported thread operation'); } } } function processDBStoreOperations( sqliteQueryExecutor: SQLiteQueryExecutor, storeOperations: ClientDBStoreOperations, ) { const { draftStoreOperations, reportStoreOperations, threadStoreOperations } = storeOperations; try { sqliteQueryExecutor.beginTransaction(); if (draftStoreOperations && draftStoreOperations.length > 0) { processDraftStoreOperations(sqliteQueryExecutor, draftStoreOperations); } if (reportStoreOperations && reportStoreOperations.length > 0) { processReportStoreOperations(sqliteQueryExecutor, reportStoreOperations); } if (threadStoreOperations && threadStoreOperations.length > 0) { processThreadStoreOperations(sqliteQueryExecutor, threadStoreOperations); } sqliteQueryExecutor.commitTransaction(); } catch (e) { sqliteQueryExecutor.rollbackTransaction(); console.log('Error while processing store ops: ', e); + throw e; } } function getClientStore( sqliteQueryExecutor: SQLiteQueryExecutor, ): ClientDBStore { return { drafts: sqliteQueryExecutor.getAllDrafts(), messages: [], threads: sqliteQueryExecutor .getAllThreadsWeb() .map(t => webThreadToClientDBThreadInfo(t)), messageStoreThreads: [], reports: sqliteQueryExecutor.getAllReports(), users: [], }; } export { processDBStoreOperations, getClientStore };