diff options
Diffstat (limited to 'ext/bg/js/database.js')
-rw-r--r-- | ext/bg/js/database.js | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/ext/bg/js/database.js b/ext/bg/js/database.js new file mode 100644 index 00000000..19e3228f --- /dev/null +++ b/ext/bg/js/database.js @@ -0,0 +1,219 @@ +/* + * Copyright (C) 2016 Alex Yatskov <alex@foosoft.net> + * Author: Alex Yatskov <alex@foosoft.net> + * + * 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 <http://www.gnu.org/licenses/>. + */ + + +class Database { + constructor() { + this.db = null; + this.dbVer = 6; + this.entities = null; + } + + init() { + if (this.db !== null) { + return Promise.reject('database already initialized'); + } + + this.db = new Dexie('dict'); + this.db.version(1).stores({ + terms: '++id, dictionary, expression, reading', + kanji: '++, dictionary, character', + entities: '++, dictionary', + dictionaries: '++, title, version', + meta: 'name, value', + }); + } + + prepare() { + this.init(); + + return this.db.meta.get('version').then(row => { + return row ? row.value : 0; + }).catch(() => { + return 0; + }).then(version => { + if (this.dbVer === version) { + return true; + } + + const db = this.db; + this.db.close(); + this.db = null; + + return db.delete().then(() => { + this.init(); + return false; + }); + }); + } + + seal() { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + return this.db.meta.put({name: 'version', value: this.dbVer}); + } + + findTerm(term) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + const results = []; + return this.db.terms.where('expression').equals(term).or('reading').equals(term).each(row => { + results.push({ + expression: row.expression, + reading: row.reading, + tags: splitField(row.tags), + glossary: row.glossary, + id: row.id + }); + }).then(() => { + return this.getEntities(); + }).then(entities => { + for (const result of results) { + result.entities = entities; + } + + return results; + }); + } + + findKanji(kanji) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + const results = []; + return this.db.kanji.where('character').equals(kanji).each(row => { + results.push({ + character: row.character, + onyomi: splitField(row.onyomi), + kunyomi: splitField(row.kunyomi), + tags: splitField(row.tags), + glossary: row.meanings + }); + }).then(() => results); + } + + getEntities(tags) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + if (this.entities !== null) { + return Promise.resolve(this.entities); + } + + return this.db.entities.toArray(rows => { + this.entities = {}; + for (const row of rows) { + this.entities[row.name] = row.value; + } + + return this.entities; + }); + } + + getDictionaries() { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + return this.db.dictionaries.toArray(); + } + + deleteDictionary(title) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + return this.db.terms.where('dictionary').equals(title).delete().then(() => { + return this.db.kanji.where('dictionary').equals(title).delete(); + }).then(() => { + return this.db.entities.where('dictionary').equals(title).delete(); + }).then(() => { + return this.db.dictionaries.where('title').equals(title).delete(); + }); + } + + importDictionary(indexUrl, callback) { + if (this.db === null) { + return Promise.reject('database not initialized'); + } + + const indexLoaded = (title, version, entities, hasTerms, hasKanji) => { + return this.db.dictionaries.add({title, version, hasTerms, hasKanji}).then(() => { + this.entities = entities || {}; + + const rows = []; + for (const name in entities || {}) { + rows.push({ + name, + value: entities[name], + dictionary: title + }); + } + + return this.db.entities.bulkAdd(rows); + }); + }; + + const termsLoaded = (title, entries, total, current) => { + const rows = []; + for (const [expression, reading, tags, ...glossary] of entries) { + rows.push({ + expression, + reading, + tags, + glossary, + dictionary: title + }); + } + + return this.db.terms.bulkAdd(rows).then(() => { + if (callback) { + callback(total, current, indexUrl); + } + }); + }; + + const kanjiLoaded = (title, entries, total, current) => { + const rows = []; + for (const [character, onyomi, kunyomi, tags, ...meanings] of entries) { + rows.push({ + character, + onyomi, + kunyomi, + tags, + meanings, + dictionary: title + }); + } + + return this.db.kanji.bulkAdd(rows).then(() => { + if (callback) { + callback(total, current, indexUrl); + } + }); + }; + + return importJsonDb(indexUrl, indexLoaded, termsLoaded, kanjiLoaded); + } +} |