diff options
Diffstat (limited to 'src/db.ts')
-rw-r--r-- | src/db.ts | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/src/db.ts b/src/db.ts new file mode 100644 index 000000000..0916ef145 --- /dev/null +++ b/src/db.ts @@ -0,0 +1,122 @@ +import { Stores, WALLET_DB_VERSION } from "./dbTypes"; +import { Store, Index } from "./query"; + +const DB_NAME = "taler"; + +/** + * Return a promise that resolves + * to the taler wallet db. + */ +export function openTalerDb( + idbFactory: IDBFactory, + onVersionChange: () => void, + onUpgradeUnsupported: (oldVersion: number, newVersion: number) => void, +): Promise<IDBDatabase> { + return new Promise<IDBDatabase>((resolve, reject) => { + const req = idbFactory.open(DB_NAME, WALLET_DB_VERSION); + req.onerror = e => { + console.log("taler database error", e); + reject(e); + }; + req.onsuccess = e => { + req.result.onversionchange = (evt: IDBVersionChangeEvent) => { + console.log( + `handling live db version change from ${evt.oldVersion} to ${ + evt.newVersion + }`, + ); + req.result.close(); + onVersionChange(); + }; + resolve(req.result); + }; + req.onupgradeneeded = e => { + const db = req.result; + console.log( + `DB: upgrade needed: oldVersion=${e.oldVersion}, newVersion=${ + e.newVersion + }`, + ); + switch (e.oldVersion) { + case 0: // DB does not exist yet + for (const n in Stores) { + if ((Stores as any)[n] instanceof Store) { + const si: Store<any> = (Stores as any)[n]; + const s = db.createObjectStore(si.name, si.storeParams); + for (const indexName in si as any) { + if ((si as any)[indexName] instanceof Index) { + const ii: Index<any, any> = (si as any)[indexName]; + s.createIndex(ii.indexName, ii.keyPath, ii.options); + } + } + } + } + break; + default: + if (e.oldVersion !== WALLET_DB_VERSION) { + onUpgradeUnsupported(e.oldVersion, WALLET_DB_VERSION); + throw Error("incompatible DB"); + } + break; + } + }; + }); +} + +export function exportDb(db: IDBDatabase): Promise<any> { + const dump = { + name: db.name, + stores: {} as { [s: string]: any }, + version: db.version, + }; + + return new Promise((resolve, reject) => { + const tx = db.transaction(Array.from(db.objectStoreNames)); + tx.addEventListener("complete", () => { + resolve(dump); + }); + // tslint:disable-next-line:prefer-for-of + for (let i = 0; i < db.objectStoreNames.length; i++) { + const name = db.objectStoreNames[i]; + const storeDump = {} as { [s: string]: any }; + dump.stores[name] = storeDump; + tx.objectStore(name) + .openCursor() + .addEventListener("success", (e: Event) => { + const cursor = (e.target as any).result; + if (cursor) { + storeDump[cursor.key] = cursor.value; + cursor.continue(); + } + }); + } + }); +} + +export function importDb(db: IDBDatabase, dump: any): Promise<void> { + console.log("importing db", dump); + return new Promise<void>((resolve, reject) => { + const tx = db.transaction(Array.from(db.objectStoreNames), "readwrite"); + if (dump.stores) { + for (const storeName in dump.stores) { + const objects = []; + const dumpStore = dump.stores[storeName]; + for (const key in dumpStore) { + objects.push(dumpStore[key]); + } + console.log(`importing ${objects.length} records into ${storeName}`); + const store = tx.objectStore(storeName); + for (const obj of objects) { + store.put(obj); + } + } + } + tx.addEventListener("complete", () => { + resolve(); + }); + }); +} + +export function deleteDb(idbFactory: IDBFactory) { + idbFactory.deleteDatabase(DB_NAME); +} |