167 lines
4.4 KiB
JavaScript
167 lines
4.4 KiB
JavaScript
/**
|
|
* @module lib/idb
|
|
*/
|
|
|
|
/* eslint-env browser */
|
|
|
|
import * as globals from './globals.js'
|
|
|
|
/*
|
|
* IDB Request to Promise transformer
|
|
*/
|
|
export const rtop = request => globals.createPromise((resolve, reject) => {
|
|
request.onerror = event => reject(new Error(event.target.error))
|
|
request.onblocked = () => location.reload()
|
|
request.onsuccess = event => resolve(event.target.result)
|
|
})
|
|
|
|
/**
|
|
* @param {string} name
|
|
* @param {Function} initDB Called when the database is first created
|
|
* @return {Promise<IDBDatabase>}
|
|
*/
|
|
export const openDB = (name, initDB) => globals.createPromise((resolve, reject) => {
|
|
let request = indexedDB.open(name)
|
|
/**
|
|
* @param {any} event
|
|
*/
|
|
request.onupgradeneeded = event => initDB(event.target.result)
|
|
/**
|
|
* @param {any} event
|
|
*/
|
|
request.onerror = event => reject(new Error(event.target.error))
|
|
request.onblocked = () => location.reload()
|
|
/**
|
|
* @param {any} event
|
|
*/
|
|
request.onsuccess = event => {
|
|
const db = event.target.result
|
|
db.onversionchange = () => { db.close() }
|
|
addEventListener('unload', () => db.close())
|
|
resolve(db)
|
|
}
|
|
})
|
|
|
|
export const deleteDB = name => rtop(indexedDB.deleteDatabase(name))
|
|
|
|
export const createStores = (db, definitions) => definitions.forEach(d =>
|
|
db.createObjectStore.apply(db, d)
|
|
)
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {String | number | ArrayBuffer | Date | Array } key
|
|
* @return {Promise<ArrayBuffer>}
|
|
*/
|
|
export const get = (store, key) =>
|
|
rtop(store.get(key))
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {String | number | ArrayBuffer | Date | IDBKeyRange | Array } key
|
|
*/
|
|
export const del = (store, key) =>
|
|
rtop(store.delete(key))
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {String | number | ArrayBuffer | Date | boolean} item
|
|
* @param {String | number | ArrayBuffer | Date | Array} [key]
|
|
*/
|
|
export const put = (store, item, key) =>
|
|
rtop(store.put(item, key))
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {String | number | ArrayBuffer | Date | boolean} item
|
|
* @param {String | number | ArrayBuffer | Date | Array} [key]
|
|
* @return {Promise<ArrayBuffer>}
|
|
*/
|
|
export const add = (store, item, key) =>
|
|
rtop(store.add(item, key))
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {String | number | ArrayBuffer | Date} item
|
|
* @return {Promise<number>}
|
|
*/
|
|
export const addAutoKey = (store, item) =>
|
|
rtop(store.add(item))
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {IDBKeyRange} [range]
|
|
*/
|
|
export const getAll = (store, range) =>
|
|
rtop(store.getAll(range))
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {IDBKeyRange} [range]
|
|
*/
|
|
export const getAllKeys = (store, range) =>
|
|
rtop(store.getAllKeys(range))
|
|
|
|
/**
|
|
* @typedef KeyValuePair
|
|
* @type {Object}
|
|
* @property {any} k key
|
|
* @property {any} v Value
|
|
*/
|
|
|
|
/**
|
|
* @param {IDBObjectStore} store
|
|
* @param {IDBKeyRange} [range]
|
|
* @return {Promise<Array<KeyValuePair>>}
|
|
*/
|
|
export const getAllKeysValues = (store, range) =>
|
|
globals.pall([getAllKeys(store, range), getAll(store, range)]).then(([ks, vs]) => ks.map((k, i) => ({ k, v: vs[i] })))
|
|
|
|
/**
|
|
* Iterate on keys and values
|
|
* @param {IDBObjectStore} store
|
|
* @param {IDBKeyRange?} keyrange
|
|
* @param {Function} f Return true in order to continue the cursor
|
|
*/
|
|
export const iterate = (store, keyrange, f) => globals.createPromise((resolve, reject) => {
|
|
const request = store.openCursor(keyrange)
|
|
request.onerror = reject
|
|
/**
|
|
* @param {any} event
|
|
*/
|
|
request.onsuccess = event => {
|
|
const cursor = event.target.result
|
|
if (cursor === null) {
|
|
return resolve()
|
|
}
|
|
f(cursor.value, cursor.key)
|
|
cursor.continue()
|
|
}
|
|
})
|
|
|
|
/**
|
|
* Iterate on the keys (no values)
|
|
*
|
|
* @param {IDBObjectStore} store
|
|
* @param {IDBKeyRange} keyrange
|
|
* @param {function} f Call `idbcursor.continue()` to iterate further
|
|
*/
|
|
export const iterateKeys = (store, keyrange, f) => {
|
|
/**
|
|
* @param {any} event
|
|
*/
|
|
store.openKeyCursor(keyrange).onsuccess = event => f(event.target.result)
|
|
}
|
|
|
|
/**
|
|
* Open store from transaction
|
|
* @param {IDBTransaction} t
|
|
* @param {String} store
|
|
* @returns {IDBObjectStore}
|
|
*/
|
|
export const getStore = (t, store) => t.objectStore(store)
|
|
|
|
export const createIDBKeyRangeBound = (lower, upper, lowerOpen, upperOpen) => IDBKeyRange.bound(lower, upper, lowerOpen, upperOpen)
|
|
export const createIDBKeyRangeUpperBound = (upper, upperOpen) => IDBKeyRange.upperBound(upper, upperOpen)
|
|
export const createIDBKeyRangeLowerBound = (lower, lowerOpen) => IDBKeyRange.lowerBound(lower, lowerOpen)
|