-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
111 lines (101 loc) · 2.89 KB
/
index.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
100
101
102
103
104
105
106
107
108
109
110
111
/**
* Open IndexedDB database with `name`.
* Retry logic allows to avoid issues in tests env,
* when db with the same name delete/open repeatedly and can be blocked.
*
* @param {String} dbName
* @param {Number} [version]
* @param {Function} [upgradeCallback]
* @return {Promise}
*/
export function open(dbName, version, upgradeCallback) {
return new Promise((resolve, reject) => {
let isFirst = true
if (typeof version === 'function') {
upgradeCallback = version
version = undefined
}
const openDb = () => {
// don't call open with 2 arguments, when version is not set
const req = version ? idb().open(dbName, version) : idb().open(dbName)
req.onblocked = () => {
if (isFirst) {
isFirst = false
setTimeout(openDb, 100)
} else {
reject(new Error('database is blocked'))
}
}
if (typeof upgradeCallback === 'function') req.onupgradeneeded = upgradeCallback
req.onerror = (e) => reject(e.target.error)
req.onsuccess = (e) => resolve(e.target.result)
}
openDb()
})
}
/**
* Delete `db` properly:
* - close it and wait 100ms to disk flush (Safari, older Chrome, Firefox)
* - if database is locked, due to inconsistent exectution of `versionchange`,
* try again in 100ms
*
* @param {IDBDatabase|String} db
* @return {Promise}
*/
export function del(db) {
const dbName = typeof db !== 'string' ? db.name : db
return new Promise((resolve, reject) => {
let isFirst = true
const delDb = () => {
const req = idb().deleteDatabase(dbName)
req.onblocked = () => {
if (isFirst) {
isFirst = false
setTimeout(delDb, 100)
} else {
reject(new Error('database is blocked'))
}
}
req.onerror = (e) => reject(e.target.error)
req.onsuccess = () => resolve()
}
if (typeof db !== 'string') {
db.close()
setTimeout(delDb, 100)
} else {
delDb()
}
})
}
/**
* Compare `first` and `second`.
* Added for consistency with official API.
*
* @param {Any} first
* @param {Any} second
* @return {Number} -1|0|1
*/
export function cmp(first, second) {
return idb().cmp(first, second)
}
/**
* Get globally available IDBFactory instance.
* - it uses `global`, so it can work in any env.
* - it tries to use `global.forceIndexedDB` first,
* so you can rewrite `global.indexedDB` with polyfill
* https://bugs.webkit.org/show_bug.cgi?id=137034
* - it fallbacks to all possibly available implementations
* https://github.com/axemclion/IndexedDBShim#ios
* - function allows to have dynamic link,
* which can be changed after module's initial exectution
*
* @return {IDBFactory}
*/
function idb() {
return global.forceIndexedDB
|| global.indexedDB
|| global.webkitIndexedDB
|| global.mozIndexedDB
|| global.msIndexedDB
|| global.shimIndexedDB
}