-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathDatabase.js
99 lines (90 loc) · 2.7 KB
/
Database.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
/*global indexedDB, setTimeout */
class Database {
// name: string
// version: number
// setup: (db,oldVersion,newVersion)
// needsUpdate (optional)
constructor(mixin) {
this._db = null;
Object.assign(this, mixin);
}
needsUpdate() {}
open() {
if (this._db) {
return this._db;
}
const _db = new Promise((resolve, reject) => {
const name = this.name;
const request = indexedDB.open(name, this.version);
let didTimeOut = false;
setTimeout(() => {
didTimeOut = true;
reject(new Error(`Timed out trying to open ${name}`));
}, 2000);
request.onupgradeneeded = (event) => {
const db = request.result;
if (didTimeOut) {
request.transaction.abort();
db.close();
} else {
this.setup(db, event.newVersion, event.oldVersion);
}
};
request.onsuccess = () => {
const db = request.result;
if (didTimeOut) {
db.close();
} else {
db.onversionchange = () => this.needsUpdate();
resolve(db);
}
};
request.onerror = () => reject(request.errorCode);
});
_db.catch(() => {
if (this._db === _db) {
this._db = null;
}
});
this._db = _db;
return _db;
}
/**
* @callback TxnHandler
* @param {IDBTransaction} txn
*/
// Mode = readwrite or readonly
async transaction(storeNames, mode, /** @type TxnHandler */ fn) {
const db = await this.open();
return new Promise((resolve, reject) => {
const transaction = db.transaction(storeNames, mode);
const result = fn(transaction);
transaction.onabort = () => reject(transaction.error);
transaction.oncomplete = () => resolve(result);
});
}
async close() {
const _db = this._db;
if (_db) {
this._db = null;
const db = await _db;
db.close();
}
}
}
const promisify = (request) =>
new Promise((resolve, reject) => {
request.onsuccess = () => resolve(request.result);
request.onerror = () => reject(request.errorCode);
});
const iterate = async function* (cursor) {
while (true) {
const result = await promisify(cursor);
if (!result) {
break;
}
yield result;
result.continue();
}
};
export { Database, promisify, iterate };