in public/dexie.js [2083:2212]
this.open = function () {
if (isBeingOpened || idbdb)
return dbReadyPromise.then(function () {
return dbOpenError ? rejection(dbOpenError) : db;
});
debug && (openCanceller._stackHolder = getErrorWithStack()); // Let stacks point to when open() was called rather than where new Dexie() was called.
isBeingOpened = true;
dbOpenError = null;
openComplete = false;
// Function pointers to call when the core opening process completes.
var resolveDbReady = dbReadyResolve,
// upgradeTransaction to abort on failure.
upgradeTransaction = null;
return Promise.race([
openCanceller,
new Promise(function (resolve, reject) {
// Multiply db.verno with 10 will be needed to workaround upgrading bug in IE:
// IE fails when deleting objectStore after reading from it.
// A future version of Dexie.js will stopover an intermediate version to workaround this.
// At that point, we want to be backward compatible. Could have been multiplied with 2, but by using 10, it is easier to map the number to the real version number.
// If no API, throw!
if (!indexedDB)
throw new exceptions.MissingAPI(
"indexedDB API not found. If using IE10+, make sure to run your code on a server URL " +
"(not locally). If using old Safari versions, make sure to include indexedDB polyfill."
);
var req = autoSchema
? indexedDB.open(dbName)
: indexedDB.open(dbName, Math.round(db.verno * 10));
if (!req)
throw new exceptions.MissingAPI("IndexedDB API not available"); // May happen in Safari private mode, see https://github.com/dfahlander/Dexie.js/issues/134
req.onerror = eventRejectHandler(reject);
req.onblocked = wrap(fireOnBlocked);
req.onupgradeneeded = wrap(function (e) {
upgradeTransaction = req.transaction;
if (autoSchema && !db._allowEmptyDB) {
// Caller did not specify a version or schema. Doing that is only acceptable for opening alread existing databases.
// If onupgradeneeded is called it means database did not exist. Reject the open() promise and make sure that we
// do not create a new database by accident here.
req.onerror = preventDefault; // Prohibit onabort error from firing before we're done!
upgradeTransaction.abort(); // Abort transaction (would hope that this would make DB disappear but it doesnt.)
// Close database and delete it.
req.result.close();
var delreq = indexedDB.deleteDatabase(dbName); // The upgrade transaction is atomic, and javascript is single threaded - meaning that there is no risk that we delete someone elses database here!
delreq.onsuccess = delreq.onerror = wrap(function () {
reject(
new exceptions.NoSuchDatabase(
"Database " + dbName + " doesnt exist"
)
);
});
} else {
upgradeTransaction.onerror = eventRejectHandler(reject);
var oldVer = e.oldVersion > Math.pow(2, 62) ? 0 : e.oldVersion; // Safari 8 fix.
runUpgraders(oldVer / 10, upgradeTransaction, reject, req);
}
}, reject);
req.onsuccess = wrap(function () {
// Core opening procedure complete. Now let's just record some stuff.
upgradeTransaction = null;
idbdb = req.result;
connections.push(db); // Used for emulating versionchange event on IE/Edge/Safari.
if (autoSchema) readGlobalSchema();
else if (idbdb.objectStoreNames.length > 0) {
try {
adjustToExistingIndexNames(
globalSchema,
idbdb.transaction(
safariMultiStoreFix(idbdb.objectStoreNames),
READONLY
)
);
} catch (e) {
// Safari may bail out if > 1 store names. However, this shouldnt be a showstopper. Issue #120.
}
}
idbdb.onversionchange = wrap(function (ev) {
db._vcFired = true; // detect implementations that not support versionchange (IE/Edge/Safari)
db.on("versionchange").fire(ev);
});
if (!hasNativeGetDatabaseNames && dbName !== "__dbnames") {
dbNamesDB.dbnames.put({ name: dbName }).catch(nop);
}
resolve();
}, reject);
}),
])
.then(function () {
// Before finally resolving the dbReadyPromise and this promise,
// call and await all on('ready') subscribers:
// Dexie.vip() makes subscribers able to use the database while being opened.
// This is a must since these subscribers take part of the opening procedure.
onReadyBeingFired = [];
return Promise.resolve(Dexie.vip(db.on.ready.fire)).then(
function fireRemainders() {
if (onReadyBeingFired.length > 0) {
// In case additional subscribers to db.on('ready') were added during the time db.on.ready.fire was executed.
var remainders = onReadyBeingFired.reduce(promisableChain, nop);
onReadyBeingFired = [];
return Promise.resolve(Dexie.vip(remainders)).then(
fireRemainders
);
}
}
);
})
.finally(function () {
onReadyBeingFired = null;
})
.then(function () {
// Resolve the db.open() with the db instance.
isBeingOpened = false;
return db;
})
.catch(function (err) {
try {
// Did we fail within onupgradeneeded? Make sure to abort the upgrade transaction so it doesnt commit.
upgradeTransaction && upgradeTransaction.abort();
} catch (e) {}
isBeingOpened = false; // Set before calling db.close() so that it doesnt reject openCanceller again (leads to unhandled rejection event).
db.close(); // Closes and resets idbdb, removes connections, resets dbReadyPromise and openCanceller so that a later db.open() is fresh.
// A call to db.close() may have made on-ready subscribers fail. Use dbOpenError if set, since err could be a follow-up error on that.
dbOpenError = err; // Record the error. It will be used to reject further promises of db operations.
return rejection(dbOpenError);
})
.finally(function () {
openComplete = true;
resolveDbReady(); // dbReadyPromise is resolved no matter if open() rejects or resolved. It's just to wake up waiters.
});
};