@converse/skeletor 0.0.7 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1115 +0,0 @@
1
- import isIndexedDBValid from '../utils/isIndexedDBValid';
2
- import createBlob from '../utils/createBlob';
3
- import idb from '../utils/idb';
4
- import Promise from '../utils/promise';
5
- import executeCallback from '../utils/executeCallback';
6
- import executeTwoCallbacks from '../utils/executeTwoCallbacks';
7
- import normalizeKey from '../utils/normalizeKey';
8
- import getCallback from '../utils/getCallback';
9
-
10
- // Some code originally from async_storage.js in
11
- // [Gaia](https://github.com/mozilla-b2g/gaia).
12
-
13
- const DETECT_BLOB_SUPPORT_STORE = 'local-forage-detect-blob-support';
14
- let supportsBlobs;
15
- const dbContexts = {};
16
- const toString = Object.prototype.toString;
17
-
18
- // Transaction Modes
19
- const READ_ONLY = 'readonly';
20
- const READ_WRITE = 'readwrite';
21
-
22
- // Transform a binary string to an array buffer, because otherwise
23
- // weird stuff happens when you try to work with the binary string directly.
24
- // It is known.
25
- // From http://stackoverflow.com/questions/14967647/ (continues on next line)
26
- // encode-decode-image-with-base64-breaks-image (2013-04-21)
27
- function _binStringToArrayBuffer(bin) {
28
- var length = bin.length;
29
- var buf = new ArrayBuffer(length);
30
- var arr = new Uint8Array(buf);
31
- for (var i = 0; i < length; i++) {
32
- arr[i] = bin.charCodeAt(i);
33
- }
34
- return buf;
35
- }
36
-
37
- //
38
- // Blobs are not supported in all versions of IndexedDB, notably
39
- // Chrome <37 and Android <5. In those versions, storing a blob will throw.
40
- //
41
- // Various other blob bugs exist in Chrome v37-42 (inclusive).
42
- // Detecting them is expensive and confusing to users, and Chrome 37-42
43
- // is at very low usage worldwide, so we do a hacky userAgent check instead.
44
- //
45
- // content-type bug: https://code.google.com/p/chromium/issues/detail?id=408120
46
- // 404 bug: https://code.google.com/p/chromium/issues/detail?id=447916
47
- // FileReader bug: https://code.google.com/p/chromium/issues/detail?id=447836
48
- //
49
- // Code borrowed from PouchDB. See:
50
- // https://github.com/pouchdb/pouchdb/blob/master/packages/node_modules/pouchdb-adapter-idb/src/blobSupport.js
51
- //
52
- function _checkBlobSupportWithoutCaching(idb) {
53
- return new Promise(function(resolve) {
54
- var txn = idb.transaction(DETECT_BLOB_SUPPORT_STORE, READ_WRITE);
55
- var blob = createBlob(['']);
56
- txn.objectStore(DETECT_BLOB_SUPPORT_STORE).put(blob, 'key');
57
-
58
- txn.onabort = function(e) {
59
- // If the transaction aborts now its due to not being able to
60
- // write to the database, likely due to the disk being full
61
- e.preventDefault();
62
- e.stopPropagation();
63
- resolve(false);
64
- };
65
-
66
- txn.oncomplete = function() {
67
- var matchedChrome = navigator.userAgent.match(/Chrome\/(\d+)/);
68
- var matchedEdge = navigator.userAgent.match(/Edge\//);
69
- // MS Edge pretends to be Chrome 42:
70
- // https://msdn.microsoft.com/en-us/library/hh869301%28v=vs.85%29.aspx
71
- resolve(
72
- matchedEdge ||
73
- !matchedChrome ||
74
- parseInt(matchedChrome[1], 10) >= 43
75
- );
76
- };
77
- }).catch(function() {
78
- return false; // error, so assume unsupported
79
- });
80
- }
81
-
82
- function _checkBlobSupport(idb) {
83
- if (typeof supportsBlobs === 'boolean') {
84
- return Promise.resolve(supportsBlobs);
85
- }
86
- return _checkBlobSupportWithoutCaching(idb).then(function(value) {
87
- supportsBlobs = value;
88
- return supportsBlobs;
89
- });
90
- }
91
-
92
- function _deferReadiness(dbInfo) {
93
- var dbContext = dbContexts[dbInfo.name];
94
-
95
- // Create a deferred object representing the current database operation.
96
- var deferredOperation = {};
97
-
98
- deferredOperation.promise = new Promise(function(resolve, reject) {
99
- deferredOperation.resolve = resolve;
100
- deferredOperation.reject = reject;
101
- });
102
-
103
- // Enqueue the deferred operation.
104
- dbContext.deferredOperations.push(deferredOperation);
105
-
106
- // Chain its promise to the database readiness.
107
- if (!dbContext.dbReady) {
108
- dbContext.dbReady = deferredOperation.promise;
109
- } else {
110
- dbContext.dbReady = dbContext.dbReady.then(function() {
111
- return deferredOperation.promise;
112
- });
113
- }
114
- }
115
-
116
- function _advanceReadiness(dbInfo) {
117
- var dbContext = dbContexts[dbInfo.name];
118
-
119
- // Dequeue a deferred operation.
120
- var deferredOperation = dbContext.deferredOperations.pop();
121
-
122
- // Resolve its promise (which is part of the database readiness
123
- // chain of promises).
124
- if (deferredOperation) {
125
- deferredOperation.resolve();
126
- return deferredOperation.promise;
127
- }
128
- }
129
-
130
- function _rejectReadiness(dbInfo, err) {
131
- var dbContext = dbContexts[dbInfo.name];
132
-
133
- // Dequeue a deferred operation.
134
- var deferredOperation = dbContext.deferredOperations.pop();
135
-
136
- // Reject its promise (which is part of the database readiness
137
- // chain of promises).
138
- if (deferredOperation) {
139
- deferredOperation.reject(err);
140
- return deferredOperation.promise;
141
- }
142
- }
143
-
144
- function _getConnection(dbInfo, upgradeNeeded) {
145
- return new Promise(function(resolve, reject) {
146
- dbContexts[dbInfo.name] = dbContexts[dbInfo.name] || createDbContext();
147
-
148
- if (dbInfo.db) {
149
- if (upgradeNeeded) {
150
- _deferReadiness(dbInfo);
151
- dbInfo.db.close();
152
- } else {
153
- return resolve(dbInfo.db);
154
- }
155
- }
156
-
157
- var dbArgs = [dbInfo.name];
158
-
159
- if (upgradeNeeded) {
160
- dbArgs.push(dbInfo.version);
161
- }
162
-
163
- var openreq = idb.open.apply(idb, dbArgs);
164
-
165
- if (upgradeNeeded) {
166
- openreq.onupgradeneeded = function(e) {
167
- var db = openreq.result;
168
- try {
169
- db.createObjectStore(dbInfo.storeName);
170
- if (e.oldVersion <= 1) {
171
- // Added when support for blob shims was added
172
- db.createObjectStore(DETECT_BLOB_SUPPORT_STORE);
173
- }
174
- } catch (ex) {
175
- if (ex.name === 'ConstraintError') {
176
- console.warn(
177
- 'The database "' +
178
- dbInfo.name +
179
- '"' +
180
- ' has been upgraded from version ' +
181
- e.oldVersion +
182
- ' to version ' +
183
- e.newVersion +
184
- ', but the storage "' +
185
- dbInfo.storeName +
186
- '" already exists.'
187
- );
188
- } else {
189
- throw ex;
190
- }
191
- }
192
- };
193
- }
194
-
195
- openreq.onerror = function(e) {
196
- e.preventDefault();
197
- reject(openreq.error);
198
- };
199
-
200
- openreq.onsuccess = function() {
201
- var db = openreq.result;
202
- db.onversionchange = function(e) {
203
- // Triggered when the database is modified (e.g. adding an objectStore) or
204
- // deleted (even when initiated by other sessions in different tabs).
205
- // Closing the connection here prevents those operations from being blocked.
206
- // If the database is accessed again later by this instance, the connection
207
- // will be reopened or the database recreated as needed.
208
- e.target.close();
209
- };
210
- resolve(db);
211
- _advanceReadiness(dbInfo);
212
- };
213
- });
214
- }
215
-
216
- function _getOriginalConnection(dbInfo) {
217
- return _getConnection(dbInfo, false);
218
- }
219
-
220
- function _getUpgradedConnection(dbInfo) {
221
- return _getConnection(dbInfo, true);
222
- }
223
-
224
- function _isUpgradeNeeded(dbInfo, defaultVersion) {
225
- if (!dbInfo.db) {
226
- return true;
227
- }
228
-
229
- var isNewStore = !dbInfo.db.objectStoreNames.contains(dbInfo.storeName);
230
- var isDowngrade = dbInfo.version < dbInfo.db.version;
231
- var isUpgrade = dbInfo.version > dbInfo.db.version;
232
-
233
- if (isDowngrade) {
234
- // If the version is not the default one
235
- // then warn for impossible downgrade.
236
- if (dbInfo.version !== defaultVersion) {
237
- console.warn(
238
- 'The database "' +
239
- dbInfo.name +
240
- '"' +
241
- " can't be downgraded from version " +
242
- dbInfo.db.version +
243
- ' to version ' +
244
- dbInfo.version +
245
- '.'
246
- );
247
- }
248
- // Align the versions to prevent errors.
249
- dbInfo.version = dbInfo.db.version;
250
- }
251
-
252
- if (isUpgrade || isNewStore) {
253
- // If the store is new then increment the version (if needed).
254
- // This will trigger an "upgradeneeded" event which is required
255
- // for creating a store.
256
- if (isNewStore) {
257
- var incVersion = dbInfo.db.version + 1;
258
- if (incVersion > dbInfo.version) {
259
- dbInfo.version = incVersion;
260
- }
261
- }
262
-
263
- return true;
264
- }
265
-
266
- return false;
267
- }
268
-
269
- // encode a blob for indexeddb engines that don't support blobs
270
- function _encodeBlob(blob) {
271
- return new Promise(function(resolve, reject) {
272
- var reader = new FileReader();
273
- reader.onerror = reject;
274
- reader.onloadend = function(e) {
275
- var base64 = btoa(e.target.result || '');
276
- resolve({
277
- __local_forage_encoded_blob: true,
278
- data: base64,
279
- type: blob.type
280
- });
281
- };
282
- reader.readAsBinaryString(blob);
283
- });
284
- }
285
-
286
- // decode an encoded blob
287
- function _decodeBlob(encodedBlob) {
288
- var arrayBuff = _binStringToArrayBuffer(atob(encodedBlob.data));
289
- return createBlob([arrayBuff], { type: encodedBlob.type });
290
- }
291
-
292
- // is this one of our fancy encoded blobs?
293
- function _isEncodedBlob(value) {
294
- return value && value.__local_forage_encoded_blob;
295
- }
296
-
297
- // Specialize the default `ready()` function by making it dependent
298
- // on the current database operations. Thus, the driver will be actually
299
- // ready when it's been initialized (default) *and* there are no pending
300
- // operations on the database (initiated by some other instances).
301
- function _fullyReady(callback) {
302
- var self = this;
303
-
304
- var promise = self._initReady().then(function() {
305
- var dbContext = dbContexts[self._dbInfo.name];
306
-
307
- if (dbContext && dbContext.dbReady) {
308
- return dbContext.dbReady;
309
- }
310
- });
311
-
312
- executeTwoCallbacks(promise, callback, callback);
313
- return promise;
314
- }
315
-
316
- // Try to establish a new db connection to replace the
317
- // current one which is broken (i.e. experiencing
318
- // InvalidStateError while creating a transaction).
319
- function _tryReconnect(dbInfo) {
320
- _deferReadiness(dbInfo);
321
-
322
- var dbContext = dbContexts[dbInfo.name];
323
- var forages = dbContext.forages;
324
-
325
- for (var i = 0; i < forages.length; i++) {
326
- const forage = forages[i];
327
- if (forage._dbInfo.db) {
328
- forage._dbInfo.db.close();
329
- forage._dbInfo.db = null;
330
- }
331
- }
332
- dbInfo.db = null;
333
-
334
- return _getOriginalConnection(dbInfo)
335
- .then(db => {
336
- dbInfo.db = db;
337
- if (_isUpgradeNeeded(dbInfo)) {
338
- // Reopen the database for upgrading.
339
- return _getUpgradedConnection(dbInfo);
340
- }
341
- return db;
342
- })
343
- .then(db => {
344
- // store the latest db reference
345
- // in case the db was upgraded
346
- dbInfo.db = dbContext.db = db;
347
- for (var i = 0; i < forages.length; i++) {
348
- forages[i]._dbInfo.db = db;
349
- }
350
- })
351
- .catch(err => {
352
- _rejectReadiness(dbInfo, err);
353
- throw err;
354
- });
355
- }
356
-
357
- // FF doesn't like Promises (micro-tasks) and IDDB store operations,
358
- // so we have to do it with callbacks
359
- function createTransaction(dbInfo, mode, callback, retries) {
360
- if (retries === undefined) {
361
- retries = 1;
362
- }
363
-
364
- try {
365
- var tx = dbInfo.db.transaction(dbInfo.storeName, mode);
366
- callback(null, tx);
367
- } catch (err) {
368
- if (
369
- retries > 0 &&
370
- (!dbInfo.db ||
371
- err.name === 'InvalidStateError' ||
372
- err.name === 'NotFoundError')
373
- ) {
374
- return Promise.resolve()
375
- .then(() => {
376
- if (
377
- !dbInfo.db ||
378
- (err.name === 'NotFoundError' &&
379
- !dbInfo.db.objectStoreNames.contains(
380
- dbInfo.storeName
381
- ) &&
382
- dbInfo.version <= dbInfo.db.version)
383
- ) {
384
- // increase the db version, to create the new ObjectStore
385
- if (dbInfo.db) {
386
- dbInfo.version = dbInfo.db.version + 1;
387
- }
388
- // Reopen the database for upgrading.
389
- return _getUpgradedConnection(dbInfo);
390
- }
391
- })
392
- .then(() => {
393
- return _tryReconnect(dbInfo).then(function() {
394
- createTransaction(dbInfo, mode, callback, retries - 1);
395
- });
396
- })
397
- .catch(callback);
398
- }
399
-
400
- callback(err);
401
- }
402
- }
403
-
404
- function createDbContext() {
405
- return {
406
- // Running localForages sharing a database.
407
- forages: [],
408
- // Shared database.
409
- db: null,
410
- // Database readiness (promise).
411
- dbReady: null,
412
- // Deferred operations on the database.
413
- deferredOperations: []
414
- };
415
- }
416
-
417
- // Open the IndexedDB database (automatically creates one if one didn't
418
- // previously exist), using any options set in the config.
419
- function _initStorage(options) {
420
- var self = this;
421
- var dbInfo = {
422
- db: null
423
- };
424
-
425
- if (options) {
426
- for (var i in options) {
427
- dbInfo[i] = options[i];
428
- }
429
- }
430
-
431
- // Get the current context of the database;
432
- var dbContext = dbContexts[dbInfo.name];
433
-
434
- // ...or create a new context.
435
- if (!dbContext) {
436
- dbContext = createDbContext();
437
- // Register the new context in the global container.
438
- dbContexts[dbInfo.name] = dbContext;
439
- }
440
-
441
- // Register itself as a running localForage in the current context.
442
- dbContext.forages.push(self);
443
-
444
- // Replace the default `ready()` function with the specialized one.
445
- if (!self._initReady) {
446
- self._initReady = self.ready;
447
- self.ready = _fullyReady;
448
- }
449
-
450
- // Create an array of initialization states of the related localForages.
451
- var initPromises = [];
452
-
453
- function ignoreErrors() {
454
- // Don't handle errors here,
455
- // just makes sure related localForages aren't pending.
456
- return Promise.resolve();
457
- }
458
-
459
- for (var j = 0; j < dbContext.forages.length; j++) {
460
- var forage = dbContext.forages[j];
461
- if (forage !== self) {
462
- // Don't wait for itself...
463
- initPromises.push(forage._initReady().catch(ignoreErrors));
464
- }
465
- }
466
-
467
- // Take a snapshot of the related localForages.
468
- var forages = dbContext.forages.slice(0);
469
-
470
- // Initialize the connection process only when
471
- // all the related localForages aren't pending.
472
- return Promise.all(initPromises)
473
- .then(function() {
474
- dbInfo.db = dbContext.db;
475
- // Get the connection or open a new one without upgrade.
476
- return _getOriginalConnection(dbInfo);
477
- })
478
- .then(function(db) {
479
- dbInfo.db = db;
480
- if (_isUpgradeNeeded(dbInfo, self._defaultConfig.version)) {
481
- // Reopen the database for upgrading.
482
- return _getUpgradedConnection(dbInfo);
483
- }
484
- return db;
485
- })
486
- .then(function(db) {
487
- dbInfo.db = dbContext.db = db;
488
- self._dbInfo = dbInfo;
489
- // Share the final connection amongst related localForages.
490
- for (var k = 0; k < forages.length; k++) {
491
- var forage = forages[k];
492
- if (forage !== self) {
493
- // Self is already up-to-date.
494
- forage._dbInfo.db = dbInfo.db;
495
- forage._dbInfo.version = dbInfo.version;
496
- }
497
- }
498
- });
499
- }
500
-
501
- function getItem(key, callback) {
502
- var self = this;
503
-
504
- key = normalizeKey(key);
505
-
506
- var promise = new Promise(function(resolve, reject) {
507
- self
508
- .ready()
509
- .then(function() {
510
- createTransaction(self._dbInfo, READ_ONLY, function(
511
- err,
512
- transaction
513
- ) {
514
- if (err) {
515
- return reject(err);
516
- }
517
-
518
- try {
519
- var store = transaction.objectStore(
520
- self._dbInfo.storeName
521
- );
522
- var req = store.get(key);
523
-
524
- req.onsuccess = function() {
525
- var value = req.result;
526
- if (value === undefined) {
527
- value = null;
528
- }
529
- if (_isEncodedBlob(value)) {
530
- value = _decodeBlob(value);
531
- }
532
- resolve(value);
533
- };
534
-
535
- req.onerror = function() {
536
- reject(req.error);
537
- };
538
- } catch (e) {
539
- reject(e);
540
- }
541
- });
542
- })
543
- .catch(reject);
544
- });
545
-
546
- executeCallback(promise, callback);
547
- return promise;
548
- }
549
-
550
- // Iterate over all items stored in database.
551
- function iterate(iterator, callback) {
552
- var self = this;
553
-
554
- var promise = new Promise(function(resolve, reject) {
555
- self
556
- .ready()
557
- .then(function() {
558
- createTransaction(self._dbInfo, READ_ONLY, function(
559
- err,
560
- transaction
561
- ) {
562
- if (err) {
563
- return reject(err);
564
- }
565
-
566
- try {
567
- var store = transaction.objectStore(
568
- self._dbInfo.storeName
569
- );
570
- var req = store.openCursor();
571
- var iterationNumber = 1;
572
-
573
- req.onsuccess = function() {
574
- var cursor = req.result;
575
-
576
- if (cursor) {
577
- var value = cursor.value;
578
- if (_isEncodedBlob(value)) {
579
- value = _decodeBlob(value);
580
- }
581
- var result = iterator(
582
- value,
583
- cursor.key,
584
- iterationNumber++
585
- );
586
-
587
- // when the iterator callback returns any
588
- // (non-`undefined`) value, then we stop
589
- // the iteration immediately
590
- if (result !== void 0) {
591
- resolve(result);
592
- } else {
593
- cursor.continue();
594
- }
595
- } else {
596
- resolve();
597
- }
598
- };
599
-
600
- req.onerror = function() {
601
- reject(req.error);
602
- };
603
- } catch (e) {
604
- reject(e);
605
- }
606
- });
607
- })
608
- .catch(reject);
609
- });
610
-
611
- executeCallback(promise, callback);
612
-
613
- return promise;
614
- }
615
-
616
- function setItem(key, value, callback) {
617
- var self = this;
618
-
619
- key = normalizeKey(key);
620
-
621
- var promise = new Promise(function(resolve, reject) {
622
- var dbInfo;
623
- self
624
- .ready()
625
- .then(function() {
626
- dbInfo = self._dbInfo;
627
- if (toString.call(value) === '[object Blob]') {
628
- return _checkBlobSupport(dbInfo.db).then(function(
629
- blobSupport
630
- ) {
631
- if (blobSupport) {
632
- return value;
633
- }
634
- return _encodeBlob(value);
635
- });
636
- }
637
- return value;
638
- })
639
- .then(function(value) {
640
- createTransaction(self._dbInfo, READ_WRITE, function(
641
- err,
642
- transaction
643
- ) {
644
- if (err) {
645
- return reject(err);
646
- }
647
-
648
- try {
649
- var store = transaction.objectStore(
650
- self._dbInfo.storeName
651
- );
652
-
653
- // The reason we don't _save_ null is because IE 10 does
654
- // not support saving the `null` type in IndexedDB. How
655
- // ironic, given the bug below!
656
- // See: https://github.com/mozilla/localForage/issues/161
657
- if (value === null) {
658
- value = undefined;
659
- }
660
-
661
- var req = store.put(value, key);
662
-
663
- transaction.oncomplete = function() {
664
- // Cast to undefined so the value passed to
665
- // callback/promise is the same as what one would get out
666
- // of `getItem()` later. This leads to some weirdness
667
- // (setItem('foo', undefined) will return `null`), but
668
- // it's not my fault localStorage is our baseline and that
669
- // it's weird.
670
- if (value === undefined) {
671
- value = null;
672
- }
673
-
674
- resolve(value);
675
- };
676
- transaction.onabort = transaction.onerror = function() {
677
- var err = req.error
678
- ? req.error
679
- : req.transaction.error;
680
- reject(err);
681
- };
682
- } catch (e) {
683
- reject(e);
684
- }
685
- });
686
- })
687
- .catch(reject);
688
- });
689
-
690
- executeCallback(promise, callback);
691
- return promise;
692
- }
693
-
694
- function removeItem(key, callback) {
695
- var self = this;
696
-
697
- key = normalizeKey(key);
698
-
699
- var promise = new Promise(function(resolve, reject) {
700
- self
701
- .ready()
702
- .then(function() {
703
- createTransaction(self._dbInfo, READ_WRITE, function(
704
- err,
705
- transaction
706
- ) {
707
- if (err) {
708
- return reject(err);
709
- }
710
-
711
- try {
712
- var store = transaction.objectStore(
713
- self._dbInfo.storeName
714
- );
715
- // We use a Grunt task to make this safe for IE and some
716
- // versions of Android (including those used by Cordova).
717
- // Normally IE won't like `.delete()` and will insist on
718
- // using `['delete']()`, but we have a build step that
719
- // fixes this for us now.
720
- var req = store.delete(key);
721
- transaction.oncomplete = function() {
722
- resolve();
723
- };
724
-
725
- transaction.onerror = function() {
726
- reject(req.error);
727
- };
728
-
729
- // The request will be also be aborted if we've exceeded our storage
730
- // space.
731
- transaction.onabort = function() {
732
- var err = req.error
733
- ? req.error
734
- : req.transaction.error;
735
- reject(err);
736
- };
737
- } catch (e) {
738
- reject(e);
739
- }
740
- });
741
- })
742
- .catch(reject);
743
- });
744
-
745
- executeCallback(promise, callback);
746
- return promise;
747
- }
748
-
749
- function clear(callback) {
750
- var self = this;
751
-
752
- var promise = new Promise(function(resolve, reject) {
753
- self
754
- .ready()
755
- .then(function() {
756
- createTransaction(self._dbInfo, READ_WRITE, function(
757
- err,
758
- transaction
759
- ) {
760
- if (err) {
761
- return reject(err);
762
- }
763
-
764
- try {
765
- var store = transaction.objectStore(
766
- self._dbInfo.storeName
767
- );
768
- var req = store.clear();
769
-
770
- transaction.oncomplete = function() {
771
- resolve();
772
- };
773
-
774
- transaction.onabort = transaction.onerror = function() {
775
- var err = req.error
776
- ? req.error
777
- : req.transaction.error;
778
- reject(err);
779
- };
780
- } catch (e) {
781
- reject(e);
782
- }
783
- });
784
- })
785
- .catch(reject);
786
- });
787
-
788
- executeCallback(promise, callback);
789
- return promise;
790
- }
791
-
792
- function length(callback) {
793
- var self = this;
794
-
795
- var promise = new Promise(function(resolve, reject) {
796
- self
797
- .ready()
798
- .then(function() {
799
- createTransaction(self._dbInfo, READ_ONLY, function(
800
- err,
801
- transaction
802
- ) {
803
- if (err) {
804
- return reject(err);
805
- }
806
-
807
- try {
808
- var store = transaction.objectStore(
809
- self._dbInfo.storeName
810
- );
811
- var req = store.count();
812
-
813
- req.onsuccess = function() {
814
- resolve(req.result);
815
- };
816
-
817
- req.onerror = function() {
818
- reject(req.error);
819
- };
820
- } catch (e) {
821
- reject(e);
822
- }
823
- });
824
- })
825
- .catch(reject);
826
- });
827
-
828
- executeCallback(promise, callback);
829
- return promise;
830
- }
831
-
832
- function key(n, callback) {
833
- var self = this;
834
-
835
- var promise = new Promise(function(resolve, reject) {
836
- if (n < 0) {
837
- resolve(null);
838
-
839
- return;
840
- }
841
-
842
- self
843
- .ready()
844
- .then(function() {
845
- createTransaction(self._dbInfo, READ_ONLY, function(
846
- err,
847
- transaction
848
- ) {
849
- if (err) {
850
- return reject(err);
851
- }
852
-
853
- try {
854
- var store = transaction.objectStore(
855
- self._dbInfo.storeName
856
- );
857
- var advanced = false;
858
- var req = store.openKeyCursor();
859
-
860
- req.onsuccess = function() {
861
- var cursor = req.result;
862
- if (!cursor) {
863
- // this means there weren't enough keys
864
- resolve(null);
865
-
866
- return;
867
- }
868
-
869
- if (n === 0) {
870
- // We have the first key, return it if that's what they
871
- // wanted.
872
- resolve(cursor.key);
873
- } else {
874
- if (!advanced) {
875
- // Otherwise, ask the cursor to skip ahead n
876
- // records.
877
- advanced = true;
878
- cursor.advance(n);
879
- } else {
880
- // When we get here, we've got the nth key.
881
- resolve(cursor.key);
882
- }
883
- }
884
- };
885
-
886
- req.onerror = function() {
887
- reject(req.error);
888
- };
889
- } catch (e) {
890
- reject(e);
891
- }
892
- });
893
- })
894
- .catch(reject);
895
- });
896
-
897
- executeCallback(promise, callback);
898
- return promise;
899
- }
900
-
901
- function keys(callback) {
902
- var self = this;
903
-
904
- var promise = new Promise(function(resolve, reject) {
905
- self
906
- .ready()
907
- .then(function() {
908
- createTransaction(self._dbInfo, READ_ONLY, function(
909
- err,
910
- transaction
911
- ) {
912
- if (err) {
913
- return reject(err);
914
- }
915
-
916
- try {
917
- var store = transaction.objectStore(
918
- self._dbInfo.storeName
919
- );
920
- var req = store.openKeyCursor();
921
- var keys = [];
922
-
923
- req.onsuccess = function() {
924
- var cursor = req.result;
925
-
926
- if (!cursor) {
927
- resolve(keys);
928
- return;
929
- }
930
-
931
- keys.push(cursor.key);
932
- cursor.continue();
933
- };
934
-
935
- req.onerror = function() {
936
- reject(req.error);
937
- };
938
- } catch (e) {
939
- reject(e);
940
- }
941
- });
942
- })
943
- .catch(reject);
944
- });
945
-
946
- executeCallback(promise, callback);
947
- return promise;
948
- }
949
-
950
- function dropInstance(options, callback) {
951
- callback = getCallback.apply(this, arguments);
952
-
953
- var currentConfig = this.config();
954
- options = (typeof options !== 'function' && options) || {};
955
- if (!options.name) {
956
- options.name = options.name || currentConfig.name;
957
- options.storeName = options.storeName || currentConfig.storeName;
958
- }
959
-
960
- var self = this;
961
- var promise;
962
- if (!options.name) {
963
- promise = Promise.reject('Invalid arguments');
964
- } else {
965
- const isCurrentDb =
966
- options.name === currentConfig.name && self._dbInfo.db;
967
-
968
- const dbPromise = isCurrentDb
969
- ? Promise.resolve(self._dbInfo.db)
970
- : _getOriginalConnection(options).then(db => {
971
- const dbContext = dbContexts[options.name];
972
- const forages = dbContext.forages;
973
- dbContext.db = db;
974
- for (var i = 0; i < forages.length; i++) {
975
- forages[i]._dbInfo.db = db;
976
- }
977
- return db;
978
- });
979
-
980
- if (!options.storeName) {
981
- promise = dbPromise.then(db => {
982
- _deferReadiness(options);
983
-
984
- const dbContext = dbContexts[options.name];
985
- const forages = dbContext.forages;
986
-
987
- db.close();
988
- for (var i = 0; i < forages.length; i++) {
989
- const forage = forages[i];
990
- forage._dbInfo.db = null;
991
- }
992
-
993
- const dropDBPromise = new Promise((resolve, reject) => {
994
- var req = idb.deleteDatabase(options.name);
995
-
996
- req.onerror = () => {
997
- const db = req.result;
998
- if (db) {
999
- db.close();
1000
- }
1001
- reject(req.error);
1002
- };
1003
-
1004
- req.onblocked = () => {
1005
- // Closing all open connections in onversionchange handler should prevent this situation, but if
1006
- // we do get here, it just means the request remains pending - eventually it will succeed or error
1007
- console.warn(
1008
- 'dropInstance blocked for database "' +
1009
- options.name +
1010
- '" until all open connections are closed'
1011
- );
1012
- };
1013
-
1014
- req.onsuccess = () => {
1015
- const db = req.result;
1016
- if (db) {
1017
- db.close();
1018
- }
1019
- resolve(db);
1020
- };
1021
- });
1022
-
1023
- return dropDBPromise
1024
- .then(db => {
1025
- dbContext.db = db;
1026
- for (var i = 0; i < forages.length; i++) {
1027
- const forage = forages[i];
1028
- _advanceReadiness(forage._dbInfo);
1029
- }
1030
- })
1031
- .catch(err => {
1032
- (
1033
- _rejectReadiness(options, err) || Promise.resolve()
1034
- ).catch(() => {});
1035
- throw err;
1036
- });
1037
- });
1038
- } else {
1039
- promise = dbPromise.then(db => {
1040
- if (!db.objectStoreNames.contains(options.storeName)) {
1041
- return;
1042
- }
1043
-
1044
- const newVersion = db.version + 1;
1045
-
1046
- _deferReadiness(options);
1047
-
1048
- const dbContext = dbContexts[options.name];
1049
- const forages = dbContext.forages;
1050
-
1051
- db.close();
1052
- for (let i = 0; i < forages.length; i++) {
1053
- const forage = forages[i];
1054
- forage._dbInfo.db = null;
1055
- forage._dbInfo.version = newVersion;
1056
- }
1057
-
1058
- const dropObjectPromise = new Promise((resolve, reject) => {
1059
- const req = idb.open(options.name, newVersion);
1060
-
1061
- req.onerror = err => {
1062
- const db = req.result;
1063
- db.close();
1064
- reject(err);
1065
- };
1066
-
1067
- req.onupgradeneeded = () => {
1068
- var db = req.result;
1069
- db.deleteObjectStore(options.storeName);
1070
- };
1071
-
1072
- req.onsuccess = () => {
1073
- const db = req.result;
1074
- db.close();
1075
- resolve(db);
1076
- };
1077
- });
1078
-
1079
- return dropObjectPromise
1080
- .then(db => {
1081
- dbContext.db = db;
1082
- for (let j = 0; j < forages.length; j++) {
1083
- const forage = forages[j];
1084
- forage._dbInfo.db = db;
1085
- _advanceReadiness(forage._dbInfo);
1086
- }
1087
- })
1088
- .catch(err => {
1089
- (
1090
- _rejectReadiness(options, err) || Promise.resolve()
1091
- ).catch(() => {});
1092
- throw err;
1093
- });
1094
- });
1095
- }
1096
- }
1097
-
1098
- executeCallback(promise, callback);
1099
- return promise;
1100
- }
1101
-
1102
- export default {
1103
- _driver: 'indexedDBStorage',
1104
- _initStorage: _initStorage,
1105
- _support: isIndexedDBValid(),
1106
- iterate: iterate,
1107
- getItem: getItem,
1108
- setItem: setItem,
1109
- removeItem: removeItem,
1110
- clear: clear,
1111
- length: length,
1112
- key: key,
1113
- keys: keys,
1114
- dropInstance: dropInstance
1115
- }