work on etags
This commit is contained in:
parent
961140c167
commit
e55f2ecec0
|
@ -13,20 +13,15 @@ export class Database {
|
|||
}
|
||||
|
||||
async _init () {
|
||||
const emojiBaseData = await (await fetch(this._dataSource)).json()
|
||||
const response = await fetch(this._dataSource)
|
||||
const emojiBaseData = await response.json()
|
||||
if (!emojiBaseData || !Array.isArray(emojiBaseData)) {
|
||||
throw new Error('Expected emojibase data, but data was in wrong format: ' + emojiBaseData)
|
||||
}
|
||||
this._idbEngine = new IndexedDBEngine(`lite-emoji-picker-${this._locale}`)
|
||||
await this._idbEngine.open()
|
||||
}
|
||||
|
||||
async loadData (emojiBaseData) {
|
||||
if (!emojiBaseData || !Array.isArray(emojiBaseData)) {
|
||||
throw new Error('Expected emojibase data, got: ' + emojiBaseData)
|
||||
}
|
||||
await this._readyPromise
|
||||
await this._idbEngine.loadData(emojiBaseData)
|
||||
const etag = response.headers.get('etag') // TODO: use cache-control as well
|
||||
await this._idbEngine.loadData(emojiBaseData, etag)
|
||||
}
|
||||
|
||||
async getEmojiByGroup (group) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { closeDatabase, dbPromise, deleteDatabase, openDatabase } from './databaseLifecycle'
|
||||
import { closeDatabase, dbPromise, deleteDatabase, get, openDatabase } from './databaseLifecycle'
|
||||
import {
|
||||
DATA_VERSION_CURRENT,
|
||||
INDEX_GROUP_AND_ORDER, INDEX_TOKENS,
|
||||
INDEX_GROUP_AND_ORDER, INDEX_TOKENS, KEY_ETAG,
|
||||
KEY_VERSION, MODE_READONLY, MODE_READWRITE,
|
||||
STORE_EMOJI,
|
||||
STORE_META
|
||||
|
@ -18,24 +18,55 @@ export class IndexedDBEngine {
|
|||
this._db = await openDatabase(this._dbName)
|
||||
}
|
||||
|
||||
async loadData (emojiBaseData) {
|
||||
async loadData (emojiBaseData, etag) {
|
||||
const transformedData = transformEmojiBaseData(emojiBaseData)
|
||||
const dataVersion = await dbPromise(this._db, STORE_META, MODE_READONLY, (metaStore, cb) => {
|
||||
metaStore.get(KEY_VERSION).onsuccess = e => cb(e.target.result)
|
||||
})
|
||||
if (dataVersion < DATA_VERSION_CURRENT) {
|
||||
await dbPromise(this._db, [STORE_EMOJI, STORE_META], MODE_READWRITE, ([emojiStore, metaStore]) => {
|
||||
metaStore.get(KEY_VERSION).onsuccess = e => {
|
||||
const dataVersion = e.target.result
|
||||
const existingEtag = await get(this._db, STORE_META, KEY_ETAG)
|
||||
if (existingEtag === etag) {
|
||||
return
|
||||
}
|
||||
await dbPromise(this._db, [STORE_EMOJI, STORE_META], MODE_READWRITE, ([emojiStore, metaStore]) => {
|
||||
|
||||
let existingEtag
|
||||
let gotEtag = false
|
||||
let existingKeys
|
||||
|
||||
function checkHasEtagAndKeys () {
|
||||
if (gotEtag && existingKeys) {
|
||||
onGetEtagAndKeys()
|
||||
}
|
||||
}
|
||||
|
||||
function onGetEtagAndKeys () {
|
||||
if (existingEtag === etag) {
|
||||
// check again within the transaction to guard against concurrency, e.g. multiple browser tabs
|
||||
if (dataVersion < DATA_VERSION_CURRENT) {
|
||||
for (const data of transformedData) {
|
||||
emojiStore.put(data)
|
||||
}
|
||||
return
|
||||
}
|
||||
if (existingKeys.length) {
|
||||
for (const key of existingKeys) {
|
||||
emojiStore.delete(key)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
insertData()
|
||||
}
|
||||
|
||||
function insertData () {
|
||||
for (const data of transformedData) {
|
||||
emojiStore.put(data)
|
||||
}
|
||||
}
|
||||
|
||||
metaStore.get(KEY_ETAG).onsuccess = e => {
|
||||
existingEtag = e.target.result
|
||||
gotEtag = true
|
||||
checkHasEtagAndKeys()
|
||||
}
|
||||
|
||||
emojiStore.getAllKeys().onsuccess = e => {
|
||||
existingKeys = e.target.result
|
||||
checkHasEtagAndKeys()
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
getEmojiByGroup (group) {
|
||||
|
|
|
@ -10,6 +10,6 @@ export const FIELD_UNICODE = 'unicode'
|
|||
export const FIELD_GROUP = 'group'
|
||||
export const FIELD_ORDER = 'order'
|
||||
export const INDEX_GROUP_AND_ORDER = 'group-order'
|
||||
export const KEY_VERSION = 'version'
|
||||
export const KEY_ETAG = 'etag'
|
||||
export const MODE_READONLY = 'readonly'
|
||||
export const MODE_READWRITE = 'readwrite'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { migrations } from './migrations'
|
||||
import { DB_VERSION_CURRENT } from './constants'
|
||||
import { DB_VERSION_CURRENT, KEY_VERSION, MODE_READONLY, STORE_META } from './constants'
|
||||
|
||||
const openReqs = {}
|
||||
const databaseCache = {}
|
||||
|
@ -57,6 +57,12 @@ export async function dbPromise (db, storeName, readOnlyOrReadWrite, cb) {
|
|||
})
|
||||
}
|
||||
|
||||
export function get (db, storeName, key) {
|
||||
return dbPromise(db, storeName, MODE_READONLY, (store, cb) => {
|
||||
store.get(key).onsuccess = e => cb(e.target.result)
|
||||
})
|
||||
}
|
||||
|
||||
export function closeDatabase (dbName) {
|
||||
if (!dbName) {
|
||||
throw new Error('dbName is required')
|
||||
|
|
Loading…
Reference in New Issue