diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-06-28 17:24:06 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-06-28 17:24:06 -0400 |
commit | 441c23bf3be1bc4f14e17ec3956a8c90b1a674e8 (patch) | |
tree | 2ff8aef4f401f333df2d487814b741a005ca35d3 /ext/bg/js/database.js | |
parent | 7590055d4e809ab857b2d491dab256e66f1b34b6 (diff) |
Rename Database to DictionaryDatabase (#633)
Diffstat (limited to 'ext/bg/js/database.js')
-rw-r--r-- | ext/bg/js/database.js | 474 |
1 files changed, 0 insertions, 474 deletions
diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js deleted file mode 100644 index 47f1ebdd..00000000 --- a/ext/bg/js/database.js +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (C) 2016-2020 Yomichan Authors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - */ - -/* global - * GenericDatabase - * dictFieldSplit - */ - -class Database { - constructor() { - this._db = new GenericDatabase(); - this._dbName = 'dict'; - this._schemas = new Map(); - } - - // Public - - async prepare() { - await this._db.open( - this._dbName, - 60, - [ - { - version: 20, - stores: { - terms: { - primaryKey: {keyPath: 'id', autoIncrement: true}, - indices: ['dictionary', 'expression', 'reading'] - }, - kanji: { - primaryKey: {autoIncrement: true}, - indices: ['dictionary', 'character'] - }, - tagMeta: { - primaryKey: {autoIncrement: true}, - indices: ['dictionary'] - }, - dictionaries: { - primaryKey: {autoIncrement: true}, - indices: ['title', 'version'] - } - } - }, - { - version: 30, - stores: { - termMeta: { - primaryKey: {autoIncrement: true}, - indices: ['dictionary', 'expression'] - }, - kanjiMeta: { - primaryKey: {autoIncrement: true}, - indices: ['dictionary', 'character'] - }, - tagMeta: { - primaryKey: {autoIncrement: true}, - indices: ['dictionary', 'name'] - } - } - }, - { - version: 40, - stores: { - terms: { - primaryKey: {keyPath: 'id', autoIncrement: true}, - indices: ['dictionary', 'expression', 'reading', 'sequence'] - } - } - }, - { - version: 50, - stores: { - terms: { - primaryKey: {keyPath: 'id', autoIncrement: true}, - indices: ['dictionary', 'expression', 'reading', 'sequence', 'expressionReverse', 'readingReverse'] - } - } - }, - { - version: 60, - stores: { - media: { - primaryKey: {keyPath: 'id', autoIncrement: true}, - indices: ['dictionary', 'path'] - } - } - } - ] - ); - } - - async close() { - this._db.close(); - } - - isPrepared() { - return this._db.isOpen(); - } - - async purge() { - if (this._db.isOpening()) { - throw new Error('Cannot purge database while opening'); - } - if (this._db.isOpen()) { - this._db.close(); - } - await GenericDatabase.deleteDatabase(this._dbName); - await this.prepare(); - } - - async deleteDictionary(dictionaryName, progressSettings, onProgress) { - const targets = [ - ['dictionaries', 'title'], - ['kanji', 'dictionary'], - ['kanjiMeta', 'dictionary'], - ['terms', 'dictionary'], - ['termMeta', 'dictionary'], - ['tagMeta', 'dictionary'], - ['media', 'dictionary'] - ]; - - const {rate} = progressSettings; - const progressData = { - count: 0, - processed: 0, - storeCount: targets.length, - storesProcesed: 0 - }; - - const filterKeys = (keys) => { - ++progressData.storesProcesed; - progressData.count += keys.length; - onProgress(progressData); - return keys; - }; - const onProgress2 = () => { - const processed = progressData.processed + 1; - progressData.processed = processed; - if ((processed % rate) === 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); - } - await Promise.all(promises); - } - - findTermsBulk(termList, dictionaries, wildcard) { - return new Promise((resolve, reject) => { - const results = []; - const count = termList.length; - if (count === 0) { - resolve(results); - return; - } - - const visited = new Set(); - const useWildcard = !!wildcard; - const prefixWildcard = wildcard === 'prefix'; - - const transaction = this._db.transaction(['terms'], 'readonly'); - const terms = transaction.objectStore('terms'); - const index1 = terms.index(prefixWildcard ? 'expressionReverse' : 'expression'); - const index2 = terms.index(prefixWildcard ? 'readingReverse' : 'reading'); - - const count2 = count * 2; - let completeCount = 0; - for (let i = 0; i < count; ++i) { - const inputIndex = i; - const term = prefixWildcard ? stringReverse(termList[i]) : termList[i]; - const query = useWildcard ? IDBKeyRange.bound(term, `${term}\uffff`, false, false) : IDBKeyRange.only(term); - - const onGetAll = (rows) => { - for (const row of rows) { - if (dictionaries.has(row.dictionary) && !visited.has(row.id)) { - visited.add(row.id); - results.push(this._createTerm(row, inputIndex)); - } - } - if (++completeCount >= count2) { - resolve(results); - } - }; - - this._db.getAll(index1, query, onGetAll, reject); - this._db.getAll(index2, query, onGetAll, reject); - } - }); - } - - findTermsExactBulk(termList, readingList, dictionaries) { - return new Promise((resolve, reject) => { - const results = []; - const count = termList.length; - if (count === 0) { - resolve(results); - return; - } - - const transaction = this._db.transaction(['terms'], 'readonly'); - const terms = transaction.objectStore('terms'); - const index = terms.index('expression'); - - let completeCount = 0; - for (let i = 0; i < count; ++i) { - const inputIndex = i; - const reading = readingList[i]; - const query = IDBKeyRange.only(termList[i]); - - const onGetAll = (rows) => { - for (const row of rows) { - if (row.reading === reading && dictionaries.has(row.dictionary)) { - results.push(this._createTerm(row, inputIndex)); - } - } - if (++completeCount >= count) { - resolve(results); - } - }; - - this._db.getAll(index, query, onGetAll, reject); - } - }); - } - - findTermsBySequenceBulk(sequenceList, mainDictionary) { - return new Promise((resolve, reject) => { - const results = []; - const count = sequenceList.length; - if (count === 0) { - resolve(results); - return; - } - - const transaction = this._db.transaction(['terms'], 'readonly'); - const terms = transaction.objectStore('terms'); - const index = terms.index('sequence'); - - let completeCount = 0; - for (let i = 0; i < count; ++i) { - const inputIndex = i; - const query = IDBKeyRange.only(sequenceList[i]); - - const onGetAll = (rows) => { - for (const row of rows) { - if (row.dictionary === mainDictionary) { - results.push(this._createTerm(row, inputIndex)); - } - } - if (++completeCount >= count) { - resolve(results); - } - }; - - this._db.getAll(index, query, onGetAll, reject); - } - }); - } - - findTermMetaBulk(termList, dictionaries) { - return this._findGenericBulk('termMeta', 'expression', termList, dictionaries, this._createTermMeta.bind(this)); - } - - findKanjiBulk(kanjiList, dictionaries) { - return this._findGenericBulk('kanji', 'character', kanjiList, dictionaries, this._createKanji.bind(this)); - } - - findKanjiMetaBulk(kanjiList, dictionaries) { - return this._findGenericBulk('kanjiMeta', 'character', kanjiList, dictionaries, this._createKanjiMeta.bind(this)); - } - - findTagForTitle(name, title) { - const query = IDBKeyRange.only(name); - return this._db.find('tagMeta', 'name', query, (row) => (row.dictionary === title), null); - } - - getMedia(targets) { - return new Promise((resolve, reject) => { - const count = targets.length; - const results = new Array(count).fill(null); - if (count === 0) { - resolve(results); - return; - } - - let completeCount = 0; - const transaction = this._db.transaction(['media'], 'readonly'); - const objectStore = transaction.objectStore('media'); - const index = objectStore.index('path'); - - for (let i = 0; i < count; ++i) { - const inputIndex = i; - const {path, dictionaryName} = targets[i]; - const query = IDBKeyRange.only(path); - - const onGetAll = (rows) => { - for (const row of rows) { - if (row.dictionary !== dictionaryName) { continue; } - results[inputIndex] = this._createMedia(row, inputIndex); - } - if (++completeCount >= count) { - resolve(results); - } - }; - - this._db.getAll(index, query, onGetAll, reject); - } - }); - } - - getDictionaryInfo() { - return new Promise((resolve, reject) => { - const transaction = this._db.transaction(['dictionaries'], 'readonly'); - const objectStore = transaction.objectStore('dictionaries'); - this._db.getAll(objectStore, null, resolve, reject); - }); - } - - getDictionaryCounts(dictionaryNames, getTotal) { - return new Promise((resolve, reject) => { - const targets = [ - ['kanji', 'dictionary'], - ['kanjiMeta', 'dictionary'], - ['terms', 'dictionary'], - ['termMeta', 'dictionary'], - ['tagMeta', 'dictionary'], - ['media', 'dictionary'] - ]; - const objectStoreNames = targets.map(([objectStoreName]) => objectStoreName); - const transaction = this._db.transaction(objectStoreNames, 'readonly'); - const databaseTargets = targets.map(([objectStoreName, indexName]) => { - const objectStore = transaction.objectStore(objectStoreName); - const index = objectStore.index(indexName); - return {objectStore, index}; - }); - - const countTargets = []; - if (getTotal) { - for (const {objectStore} of databaseTargets) { - countTargets.push([objectStore, null]); - } - } - for (const dictionaryName of dictionaryNames) { - const query = IDBKeyRange.only(dictionaryName); - for (const {index} of databaseTargets) { - countTargets.push([index, query]); - } - } - - const onCountComplete = (results) => { - const resultCount = results.length; - const targetCount = targets.length; - const counts = []; - for (let i = 0; i < resultCount; i += targetCount) { - const countGroup = {}; - for (let j = 0; j < targetCount; ++j) { - countGroup[targets[j][0]] = results[i + j]; - } - counts.push(countGroup); - } - const total = getTotal ? counts.shift() : null; - resolve({total, counts}); - }; - - this._db.bulkCount(countTargets, onCountComplete, reject); - }); - } - - async dictionaryExists(title) { - const query = IDBKeyRange.only(title); - const result = await this._db.find('dictionaries', 'title', query); - return typeof result !== 'undefined'; - } - - bulkAdd(objectStoreName, items, start, count) { - return this._db.bulkAdd(objectStoreName, items, start, count); - } - - // Private - - async _findGenericBulk(objectStoreName, indexName, indexValueList, dictionaries, createResult) { - return new Promise((resolve, reject) => { - const results = []; - const count = indexValueList.length; - 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 inputIndex = i; - const query = IDBKeyRange.only(indexValueList[i]); - - const onGetAll = (rows) => { - for (const row of rows) { - if (dictionaries.has(row.dictionary)) { - results.push(createResult(row, inputIndex)); - } - } - if (++completeCount >= count) { - resolve(results); - } - }; - - this._db.getAll(index, query, onGetAll, reject); - } - }); - } - - _createTerm(row, index) { - return { - index, - expression: row.expression, - reading: row.reading, - definitionTags: dictFieldSplit(row.definitionTags || row.tags || ''), - termTags: dictFieldSplit(row.termTags || ''), - rules: dictFieldSplit(row.rules), - glossary: row.glossary, - score: row.score, - dictionary: row.dictionary, - id: row.id, - sequence: typeof row.sequence === 'undefined' ? -1 : row.sequence - }; - } - - _createKanji(row, index) { - return { - index, - character: row.character, - onyomi: dictFieldSplit(row.onyomi), - kunyomi: dictFieldSplit(row.kunyomi), - tags: dictFieldSplit(row.tags), - glossary: row.meanings, - stats: row.stats, - dictionary: row.dictionary - }; - } - - _createTermMeta({expression, mode, data, dictionary}, index) { - return {expression, mode, data, dictionary, index}; - } - - _createKanjiMeta({character, mode, data, dictionary}, index) { - return {character, mode, data, dictionary, index}; - } - - _createMedia(row, index) { - return Object.assign({}, row, {index}); - } -} |