diff --git a/ext/js/data/database.js b/ext/js/data/database.js index 068f4a5f..f44ea1d9 100644 --- a/ext/js/data/database.js +++ b/ext/js/data/database.js @@ -111,29 +111,34 @@ class Database { } } - find(objectStoreName, indexName, query, predicate=null, defaultValue) { + find(objectStoreName, indexName, query, predicate, predicateArg, defaultValue) { return new Promise((resolve, reject) => { const transaction = this.transaction([objectStoreName], 'readonly'); const objectStore = transaction.objectStore(objectStoreName); const objectStoreOrIndex = indexName !== null ? objectStore.index(indexName) : objectStore; - const request = objectStoreOrIndex.openCursor(query, 'next'); - request.onerror = (e) => reject(e.target.error); - request.onsuccess = (e) => { - const cursor = e.target.result; - if (cursor) { - const value = cursor.value; - if (typeof predicate !== 'function' || predicate(value)) { - resolve(value); - } else { - cursor.continue(); - } - } else { - resolve(defaultValue); - } - }; + this.findFirst(objectStoreOrIndex, query, resolve, reject, predicate, predicateArg, defaultValue); }); } + findFirst(objectStoreOrIndex, query, resolve, reject, predicate, predicateArg, defaultValue) { + const noPredicate = (typeof predicate !== 'function'); + const request = objectStoreOrIndex.openCursor(query, 'next'); + request.onerror = (e) => reject(e.target.error); + request.onsuccess = (e) => { + const cursor = e.target.result; + if (cursor) { + const {value} = cursor; + if (noPredicate || predicate(value, predicateArg)) { + resolve(value); + } else { + cursor.continue(); + } + } else { + resolve(defaultValue); + } + }; + } + bulkCount(targets, resolve, reject) { const targetCount = targets.length; if (targetCount <= 0) { diff --git a/ext/js/language/dictionary-database.js b/ext/js/language/dictionary-database.js index 62c22289..40f5362b 100644 --- a/ext/js/language/dictionary-database.js +++ b/ext/js/language/dictionary-database.js @@ -294,9 +294,14 @@ class DictionaryDatabase { return this._findGenericBulk('kanjiMeta', 'character', kanjiList, dictionaries, this._createKanjiMeta.bind(this)); } + findTagMetaBulk(items) { + const predicate = (row, item) => (row.dictionary === item.dictionary); + return this._findFirstBulk('tagMeta', 'name', items, predicate, this._createTagMeta.bind(this)); + } + findTagForTitle(name, title) { const query = IDBKeyRange.only(name); - return this._db.find('tagMeta', 'name', query, (row) => (row.dictionary === title), null); + return this._db.find('tagMeta', 'name', query, (row) => (row.dictionary === title), null, null); } getMedia(targets) { @@ -393,7 +398,7 @@ class DictionaryDatabase { async dictionaryExists(title) { const query = IDBKeyRange.only(title); - const result = await this._db.find('dictionaries', 'title', query); + const result = await this._db.find('dictionaries', 'title', query, null, null, void 0); return typeof result !== 'undefined'; } @@ -437,6 +442,36 @@ class DictionaryDatabase { }); } + _findFirstBulk(objectStoreName, indexName, items, predicate, createResult) { + return new Promise((resolve, reject) => { + const count = items.length; + const results = new Array(count); + if (count === 0) { + resolve(results); + return; + } + + const transaction = this._db.transaction([objectStoreName], 'readonly'); + const terms = transaction.objectStore(objectStoreName); + const index = terms.index(indexName); + + let completeCount = 0; + for (let i = 0; i < count; ++i) { + const itemIndex = i; + const item = items[i]; + const query = IDBKeyRange.only(item.query); + + const onFind = (row) => { + results[itemIndex] = createResult(row, itemIndex); + if (++completeCount >= count) { + resolve(results); + } + }; + this._db.findFirst(index, query, onFind, reject, predicate, item, void 0); + } + }); + } + _createTerm(row, index) { return { index, @@ -466,6 +501,10 @@ class DictionaryDatabase { }; } + _createTagMeta(row, index) { + return {row, index}; + } + _createTermMeta({expression, mode, data, dictionary}, index) { return {expression, mode, data, dictionary, index}; }