import Lock from "./lock"; import { DB, openDb, Transaction } from "idb"; export default class IDB { initLock = new Lock(); db: DB; constructor(database: string, private stores: string[]) { let lock = this.initLock.getLock(); lock.then(async l => { let v = localStorage.getItem(database + "_version"); let version = 0; if (v) version = Number(v) let lastStoresS = localStorage.getItem(database + "_stores"); if (!lastStoresS) lastStoresS = ""; let lastStores = lastStoresS.split(",").filter(e => e !== ""); if (!stores.every(e => lastStores.indexOf(e) >= 0) || !lastStores.every(e => stores.indexOf(e) >= 0)) version++; localStorage.setItem(database + "_version", version.toString()); localStorage.setItem(database + "_stores", stores.join(",")); this.db = await openDb(database, version, db => { console.log("IndexedDB need update") stores.forEach(store => { if (!db.objectStoreNames.contains(store)) db.createObjectStore(store); }) }) console.log("Got DATABASE", this.db) l.release(); }) } transaction(...stores: string[] | { name: string }[]) { if (stores.length < 1) stores = this.stores; let s: string[]; if (typeof stores[0] === "string") s = stores else s = (stores).map(e => e.name) return this.db.transaction(s, "readwrite") } getStore(name: string) { return { name: name, transaction: () => { return this.db.transaction(name, "readwrite") }, get: async (key: string, transaction?: Transaction): Promise => { (await this.initLock.getLock()).release() return (transaction || this.db.transaction(name)) .objectStore(name).get(key); }, getAll: async (transaction?: Transaction): Promise => { (await this.initLock.getLock()).release() return (transaction || this.db.transaction(name)) .objectStore(name).getAll(); }, set: async (key: string, val: T, transaction?: Transaction) => { (await this.initLock.getLock()).release() const tx = (transaction || this.db.transaction(name, "readwrite")); tx.objectStore(name).put(val, key); return tx.complete; }, delete: async (key: string, transaction?: Transaction) => { (await this.initLock.getLock()).release() const tx = (transaction || this.db.transaction(name, "readwrite")); tx.objectStore(name).delete(key); return tx.complete; }, clear: async (transaction?: Transaction) => { (await this.initLock.getLock()).release() const tx = (transaction || this.db.transaction(name, "readwrite")); tx.objectStore(name).clear(); return tx.complete; }, keys: async (transaction?: Transaction): Promise => { (await this.initLock.getLock()).release() const tx = (transaction || this.db.transaction(name)); const keys: string[] = []; const store = tx.objectStore(name); // This would be store.getAllKeys(), but it isn't supported by Edge or Safari. // openKeyCursor isn't supported by Safari, so we fall back (store.iterateKeyCursor || store.iterateCursor).call(store, (cursor: any) => { if (!cursor) return; keys.push(cursor.key); cursor.continue(); }); return tx.complete.then(() => keys); } } } }