Commit dd400574 authored by Tristan Cavelier's avatar Tristan Cavelier

Improve indexeddb error management

parent 68cd478a
...@@ -81,27 +81,39 @@ ...@@ -81,27 +81,39 @@
// XXX doc string // XXX doc string
IndexedDBStorage.prototype.createDBIfNecessary = function () { IndexedDBStorage.prototype.createDBIfNecessary = function () {
var status, request = indexedDB.open(this._database_name); var status, open_req = indexedDB.open(this._database_name);
// No request.abort() is provided so we cannot cancel database creation // No request.abort() is provided so we cannot cancel database creation
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
request.onupgradeneeded = function () { open_req.onupgradeneeded = function () {
// *Called at t + 1*
var store, db = open_req.result;
// If we reach this point, the database is created. // If we reach this point, the database is created.
// There is no way to cancel the operation from here. // There is no way to cancel the operation from here.
// So let's continue. // So let's continue.
var db = request.result, try {
store = db.createObjectStore("metadata", { store = db.createObjectStore("metadata", {
"keyPath": "_id" "keyPath": "_id"
}); });
store.createIndex("_id", "_id"); // `createObjectStore` can throw InvalidStateError - open_req.onerror
status = "created"; // and db.onerror won't be called.
store.createIndex("_id", "_id");
// `store.createIndex` can throw an error
status = "created";
// store.transaction.oncomplete = function () {
// // *Called at t + 2*
// };
} catch (e) {
reject(e);
db.close();
}
}; };
request.onerror = function () { open_req.onerror = function () {
var db = request.result; if (open_req.result) { open_req.result.close(); }
if (db) { db.close(); } reject(open_req.error);
reject(request.error);
}; };
request.onsuccess = function () { open_req.onsuccess = function () {
request.result.close(); // *Called at t + 3*
open_req.result.close();
resolve(status || "no_content"); resolve(status || "no_content");
}; };
}); });
...@@ -109,42 +121,59 @@ ...@@ -109,42 +121,59 @@
// XXX doc string // XXX doc string
IndexedDBStorage.prototype.getMetadata = function (id) { IndexedDBStorage.prototype.getMetadata = function (id) {
var onCancel, request = indexedDB.open(this._database_name); var onCancel, open_req = indexedDB.open(this._database_name);
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
request.onerror = function () { open_req.onerror = function () {
var db = request.result; if (open_req.result) { open_req.result.close(); }
reject(request.error); reject(open_req.error);
if (db) { db.close(); }
}; };
request.onsuccess = function () { open_req.onsuccess = function () {
// *Called at t + 1*
var tx, store, get_req, err, res, db = open_req.result;
try { try {
var db, tx, store, getrequest; db.onerror = function () {
db = request.result; db.close();
};
tx = db.transaction("metadata", "readonly"); tx = db.transaction("metadata", "readonly");
store = tx.objectStore("metadata"); // `db.transaction` can throw an error
tx.onerror = function () {
reject(err || tx.error);
db.close();
};
tx.oncomplete = function () {
// *Called at t + 3*
if (err) {
reject(err);
} else {
resolve(res);
}
db.close();
};
// we can cancel the transaction from here // we can cancel the transaction from here
onCancel = function () { onCancel = function () {
tx.abort(); tx.abort();
db.close(); db.close();
}; };
getrequest = store.get(id); store = tx.objectStore("metadata");
getrequest.onabort = function () { get_req = store.get(id);
// if cancelled, the getrequest should fail get_req.onabort = function () {
reject(getrequest.error); // if cancelled, the get_req should fail
db.close(); // and I hope the tx.onerror is called
err = get_req.error;
}; };
getrequest.onerror = getrequest.onabort; get_req.onerror = get_req.onabort;
getrequest.onsuccess = function () { get_req.onsuccess = function () {
// if cancelled, this function should not be called // *Called at t + 2*
if (!getrequest.result) { // if cancelled, this listener should not be called
reject("not_found"); if (!get_req.result) {
err = "not_found";
return; return;
} }
resolve(getrequest.result); res = get_req.result;
db.close();
}; };
} catch (e) { } catch (e) {
reject(e); reject(e);
db.close();
} }
}; };
}, function () { }, function () {
...@@ -156,31 +185,39 @@ ...@@ -156,31 +185,39 @@
// XXX doc string // XXX doc string
IndexedDBStorage.prototype.putMetadata = function (metadata) { IndexedDBStorage.prototype.putMetadata = function (metadata) {
var onCancel, request = indexedDB.open(this._database_name); var onCancel, open_req = indexedDB.open(this._database_name);
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
request.onerror = function () { open_req.onerror = function () {
var db = request.result; if (open_req.result) { open_req.result.close(); }
reject(request.error); reject(open_req.error);
if (db) { db.close(); }
}; };
request.onsuccess = function () { open_req.onsuccess = function () {
// *Called at t + 1*
var tx, store, db = open_req.result;
try { try {
var db, tx, store;
db = request.result;
tx = db.transaction("metadata", "readwrite"); tx = db.transaction("metadata", "readwrite");
store = tx.objectStore("metadata"); tx.onerror = function () {
// we can cancel the transaction from here reject(tx.error);
onCancel = function () {
tx.abort();
db.close(); db.close();
}; };
store.put(metadata);
tx.oncomplete = function () { tx.oncomplete = function () {
// *Called at t + 3*
resolve(); resolve();
db.close(); db.close();
}; };
// we can cancel the transaction from here
onCancel = function () {
tx.abort();
db.close();
};
store = tx.objectStore("metadata");
store.put(metadata);
// store.onsuccess = function () {
// // *Called at t + 2*
// };
} catch (e) { } catch (e) {
reject(e); reject(e);
db.close();
} }
}; };
}, function () { }, function () {
...@@ -229,41 +266,44 @@ ...@@ -229,41 +266,44 @@
}; };
IndexedDBStorage.prototype.getList = function () { IndexedDBStorage.prototype.getList = function () {
var rows = [], onCancel, request = indexedDB.open(this._database_name); var rows = [], onCancel, open_req = indexedDB.open(this._database_name);
return new Promise(function (resolve, reject) { return new Promise(function (resolve, reject) {
request.onsuccess = function () { open_req.onerror = function () {
var db, tx, store, index, indexrequest; if (open_req.result) { open_req.result.close(); }
db = request.result; reject(open_req.error);
tx = db.transaction("metadata", "readonly");
onCancel = function () {
tx.abort();
db.close();
};
store = tx.objectStore("metadata");
index = store.index("_id");
indexrequest = index.openCursor();
indexrequest.onsuccess = function () {
var cursor = indexrequest.result;
if (cursor) {
// Called for each matching record.
rows.push({
"id": cursor.value._id,
"doc": cursor.value,
"value": {}
});
cursor.continue();
} else {
// No more matching records.
resolve({"data": {"rows": rows, "total_rows": rows.length}});
db.close();
}
};
}; };
request.onerror = function () { open_req.onsuccess = function () {
reject(request.error); var tx, store, index, index_req, db = open_req.result;
var db = request.result; try {
if (db) { db.close(); } tx = db.transaction("metadata", "readonly");
onCancel = function () {
tx.abort();
db.close();
};
store = tx.objectStore("metadata");
index = store.index("_id");
index_req = index.openCursor();
index_req.onsuccess = function () {
var cursor = index_req.result;
if (cursor) {
// Called for each matching record.
rows.push({
"id": cursor.value._id,
"doc": cursor.value,
"value": {}
});
cursor.continue();
} else {
// No more matching records.
resolve({"data": {"rows": rows, "total_rows": rows.length}});
db.close();
}
};
} catch (e) {
reject(e);
db.close();
}
}; };
}, function () { }, function () {
if (typeof onCancel === "function") { if (typeof onCancel === "function") {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment