From 97a80276f6ce5834ab1b9ad12309df4f6f2f3ec5 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sun, 5 Sep 2021 20:00:08 -0400 Subject: [PATCH] Database readwrite transaction updates (#1932) * Add _readWriteTransaction helper * Improve deleteDictionary order * Make onProgress event optional * Simplify progress rate parameter --- ext/js/data/database.js | 21 ++++---- ext/js/language/dictionary-database.js | 53 +++++++++++++------- ext/js/language/dictionary-worker-handler.js | 2 +- test/test-database.js | 4 +- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/ext/js/data/database.js b/ext/js/data/database.js index 224233a8..cc4f39f9 100644 --- a/ext/js/data/database.js +++ b/ext/js/data/database.js @@ -76,9 +76,7 @@ class Database { return; } - const transaction = this.transaction([objectStoreName], 'readwrite'); - transaction.onerror = (e) => reject(e.target.error); - transaction.oncomplete = () => resolve(); + const transaction = this._readWriteTransaction([objectStoreName], resolve, reject); const objectStore = transaction.objectStore(objectStoreName); for (let i = start, ii = start + count; i < ii; ++i) { objectStore.add(items[i]); @@ -161,9 +159,7 @@ class Database { delete(objectStoreName, key) { return new Promise((resolve, reject) => { - const transaction = this.transaction([objectStoreName], 'readwrite'); - transaction.onerror = (e) => reject(e.target.error); - transaction.oncomplete = () => resolve(); + const transaction = this._readWriteTransaction([objectStoreName], resolve, reject); const objectStore = transaction.objectStore(objectStoreName); objectStore.delete(key); transaction.commit(); @@ -172,10 +168,7 @@ class Database { bulkDelete(objectStoreName, indexName, query, filterKeys=null, onProgress=null) { return new Promise((resolve, reject) => { - const transaction = this.transaction([objectStoreName], 'readwrite'); - transaction.onerror = (e) => reject(e.target.error); - transaction.oncomplete = () => resolve(); - + const transaction = this._readWriteTransaction([objectStoreName], resolve, reject); const objectStore = transaction.objectStore(objectStoreName); const objectStoreOrIndex = indexName !== null ? objectStore.index(indexName) : objectStore; @@ -317,4 +310,12 @@ class Database { } } } + + _readWriteTransaction(storeNames, resolve, reject) { + const transaction = this.transaction(storeNames, 'readwrite'); + transaction.onerror = (e) => reject(e.target.error); + transaction.onabort = () => reject(new Error('Transaction aborted')); + transaction.oncomplete = () => resolve(); + return transaction; + } } diff --git a/ext/js/language/dictionary-database.js b/ext/js/language/dictionary-database.js index 6b235fb6..50435c51 100644 --- a/ext/js/language/dictionary-database.js +++ b/ext/js/language/dictionary-database.js @@ -139,22 +139,37 @@ class DictionaryDatabase { return result; } - async deleteDictionary(dictionaryName, progressSettings, onProgress) { - const targets = [ - ['dictionaries', 'title'], - ['kanji', 'dictionary'], - ['kanjiMeta', 'dictionary'], - ['terms', 'dictionary'], - ['termMeta', 'dictionary'], - ['tagMeta', 'dictionary'], - ['media', 'dictionary'] + async deleteDictionary(dictionaryName, progressRate, onProgress) { + if (typeof progressRate !== 'number') { + progressRate = 1; + } + if (typeof onProgress !== 'function') { + onProgress = () => {}; + } + + const targetGroups = [ + [ + ['kanji', 'dictionary'], + ['kanjiMeta', 'dictionary'], + ['terms', 'dictionary'], + ['termMeta', 'dictionary'], + ['tagMeta', 'dictionary'], + ['media', 'dictionary'] + ], + [ + ['dictionaries', 'title'] + ] ]; - const {rate} = progressSettings; + let storeCount = 0; + for (const targets of targetGroups) { + storeCount += targets.length; + } + const progressData = { count: 0, processed: 0, - storeCount: targets.length, + storeCount, storesProcesed: 0 }; @@ -167,18 +182,20 @@ class DictionaryDatabase { const onProgress2 = () => { const processed = progressData.processed + 1; progressData.processed = processed; - if ((processed % rate) === 0 || processed === progressData.count) { + if ((processed % progressRate) === 0 || processed === progressData.count) { onProgress(progressData); } }; - const promises = []; - for (const [objectStoreName, indexName] of targets) { - const query = IDBKeyRange.only(dictionaryName); - const promise = this._db.bulkDelete(objectStoreName, indexName, query, filterKeys, onProgress2); - promises.push(promise); + for (const targets of targetGroups) { + const promises = []; + for (const [objectStoreName, indexName] of targets) { + const query = IDBKeyRange.only(dictionaryName); + const promise = this._db.bulkDelete(objectStoreName, indexName, query, filterKeys, onProgress2); + promises.push(promise); + } + await Promise.all(promises); } - await Promise.all(promises); } findTermsBulk(termList, dictionaries, wildcard) { diff --git a/ext/js/language/dictionary-worker-handler.js b/ext/js/language/dictionary-worker-handler.js index 3ce744f9..8aa6a265 100644 --- a/ext/js/language/dictionary-worker-handler.js +++ b/ext/js/language/dictionary-worker-handler.js @@ -84,7 +84,7 @@ class DictionaryWorkerHandler { async _deleteDictionary({dictionaryTitle}, onProgress) { const dictionaryDatabase = await this._getPreparedDictionaryDatabase(); try { - return await dictionaryDatabase.deleteDictionary(dictionaryTitle, {rate: 1000}, onProgress); + return await dictionaryDatabase.deleteDictionary(dictionaryTitle, 1000, onProgress); } finally { dictionaryDatabase.close(); } diff --git a/test/test-database.js b/test/test-database.js index e855f07f..a87a3f72 100644 --- a/test/test-database.js +++ b/test/test-database.js @@ -122,7 +122,7 @@ async function testDatabase1() { let progressEvent = false; await dictionaryDatabase.deleteDictionary( title, - {rate: 1000}, + 1000, () => { progressEvent = true; } @@ -788,7 +788,7 @@ async function testDatabase2() { const dictionaryDatabase = new DictionaryDatabase(); // Error: not prepared - await assert.rejects(async () => await dictionaryDatabase.deleteDictionary(title, {rate: 1000}, () => {})); + await assert.rejects(async () => await dictionaryDatabase.deleteDictionary(title, 1000)); await assert.rejects(async () => await dictionaryDatabase.findTermsBulk(['?'], titles, null)); await assert.rejects(async () => await dictionaryDatabase.findTermsExactBulk([{term: '?', reading: '?'}], titles)); await assert.rejects(async () => await dictionaryDatabase.findTermsBySequenceBulk([{query: 1, dictionary: title}]));