Commit 4c835354 authored by Romain Courteaud's avatar Romain Courteaud

IDB: reduce diff size

parent e11ab351
...@@ -130,8 +130,11 @@ ...@@ -130,8 +130,11 @@
} }
} }
function waitForOpenIndexedDB(db_name, version, index_keys, callback) { function waitForOpenIndexedDB(storage, callback) {
var request; var request,
db_name = storage._database_name,
version = storage._version,
index_keys = storage._index_keys;
function canceller() { function canceller() {
if ((request !== undefined) && (request.result !== undefined)) { if ((request !== undefined) && (request.result !== undefined)) {
...@@ -293,28 +296,27 @@ ...@@ -293,28 +296,27 @@
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(context._database_name, context._version, return waitForOpenIndexedDB(context, function (db) {
context._index_keys, function (db) { return waitForTransaction(db, ["metadata"], "readonly",
return waitForTransaction(db, ["metadata"], "readonly", function (tx) {
function (tx) { key = "_id";
key = "_id"; if (options.subquery) {
if (options.subquery) { query = parseStringToObject(options.subquery);
query = parseStringToObject(options.subquery); key = "doc." + query.key;
key = "doc." + query.key; value = IDBKeyRange.only(query.value);
value = IDBKeyRange.only(query.value); }
} if (options.include_docs === true) {
if (options.include_docs === true) {
return waitForAllSynchronousCursor(
tx.objectStore("metadata").index(key).openCursor(value),
pushIncludedMetadata
);
}
return waitForAllSynchronousCursor( return waitForAllSynchronousCursor(
tx.objectStore("metadata").index(key).openKeyCursor(value), tx.objectStore("metadata").index(key).openCursor(value),
pushMetadata pushIncludedMetadata
); );
}); }
}); return waitForAllSynchronousCursor(
tx.objectStore("metadata").index(key).openKeyCursor(value),
pushMetadata
);
});
});
}) })
.push(function () { .push(function () {
return result_list; return result_list;
...@@ -325,13 +327,12 @@ ...@@ -325,13 +327,12 @@
var context = this; var context = this;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(context._database_name, context._version, return waitForOpenIndexedDB(context, function (db) {
context._index_keys, function (db) { return waitForTransaction(db, ["metadata"], "readonly",
return waitForTransaction(db, ["metadata"], "readonly", function (tx) {
function (tx) { return waitForIDBRequest(tx.objectStore("metadata").get(id));
return waitForIDBRequest(tx.objectStore("metadata").get(id)); });
}); });
});
}) })
.push(function (evt) { .push(function (evt) {
if (evt.target.result) { if (evt.target.result) {
...@@ -354,20 +355,19 @@ ...@@ -354,20 +355,19 @@
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(context._database_name, context._version, return waitForOpenIndexedDB(context, function (db) {
context._index_keys, function (db) { return waitForTransaction(db, ["metadata", "attachment"],
return waitForTransaction(db, ["metadata", "attachment"], "readonly", function (tx) {
"readonly", function (tx) { return RSVP.all([
return RSVP.all([ waitForIDBRequest(tx.objectStore("metadata").get(id)),
waitForIDBRequest(tx.objectStore("metadata").get(id)), waitForAllSynchronousCursor(
waitForAllSynchronousCursor( tx.objectStore("attachment").index("_id")
tx.objectStore("attachment").index("_id") .openKeyCursor(IDBKeyRange.only(id)),
.openKeyCursor(IDBKeyRange.only(id)), addEntry
addEntry )
) ]);
]); });
}); });
});
}) })
.push(function (result_list) { .push(function (result_list) {
var evt = result_list[0]; var evt = result_list[0];
...@@ -384,66 +384,63 @@ ...@@ -384,66 +384,63 @@
}; };
IndexedDBStorage.prototype.put = function (id, metadata) { IndexedDBStorage.prototype.put = function (id, metadata) {
return waitForOpenIndexedDB(this._database_name, this._version, return waitForOpenIndexedDB(this, function (db) {
this._index_keys, function (db) { return waitForTransaction(db, ["metadata"], "readwrite",
return waitForTransaction(db, ["metadata"], "readwrite", function (tx) {
function (tx) { return waitForIDBRequest(tx.objectStore("metadata").put({
return waitForIDBRequest(tx.objectStore("metadata").put({ "_id": id,
"_id": id, "doc": metadata
"doc": metadata }));
})); });
}); });
});
}; };
IndexedDBStorage.prototype.remove = function (id) { IndexedDBStorage.prototype.remove = function (id) {
return waitForOpenIndexedDB(this._database_name, this._version, return waitForOpenIndexedDB(this, function (db) {
this._index_keys, function (db) { return waitForTransaction(db, ["metadata", "attachment", "blob"],
return waitForTransaction(db, ["metadata", "attachment", "blob"], "readwrite", function (tx) {
"readwrite", function (tx) {
var promise_list = [],
var promise_list = [], metadata_store = tx.objectStore("metadata"),
metadata_store = tx.objectStore("metadata"), attachment_store = tx.objectStore("attachment"),
attachment_store = tx.objectStore("attachment"), blob_store = tx.objectStore("blob");
blob_store = tx.objectStore("blob");
function deleteAttachment(cursor) {
promise_list.push(
waitForIDBRequest(attachment_store.delete(cursor.primaryKey))
);
}
function deleteBlob(cursor) {
promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
);
}
function deleteAttachment(cursor) { return RSVP.all([
promise_list.push( waitForIDBRequest(metadata_store.delete(id)),
waitForIDBRequest(attachment_store.delete(cursor.primaryKey)) waitForAllSynchronousCursor(
); attachment_store.index("_id")
} .openKeyCursor(IDBKeyRange.only(id)),
function deleteBlob(cursor) { deleteAttachment
promise_list.push( ),
waitForIDBRequest(blob_store.delete(cursor.primaryKey)) waitForAllSynchronousCursor(
); blob_store.index("_id")
} .openKeyCursor(IDBKeyRange.only(id)),
deleteBlob
return RSVP.all([ ),
waitForIDBRequest(metadata_store.delete(id)), ])
waitForAllSynchronousCursor( .then(function () {
attachment_store.index("_id") return RSVP.all(promise_list);
.openKeyCursor(IDBKeyRange.only(id)), });
deleteAttachment });
), });
waitForAllSynchronousCursor(
blob_store.index("_id")
.openKeyCursor(IDBKeyRange.only(id)),
deleteBlob
),
])
.then(function () {
return RSVP.all(promise_list);
});
});
});
}; };
IndexedDBStorage.prototype.getAttachment = function (id, name, options) { IndexedDBStorage.prototype.getAttachment = function (id, name, options) {
if (options === undefined) { if (options === undefined) {
options = {}; options = {};
} }
var db_name = this._database_name, var start,
start,
end, end,
array_buffer_list = [], array_buffer_list = [],
context = this; context = this;
...@@ -467,66 +464,65 @@ ...@@ -467,66 +464,65 @@
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(db_name, context._version, return waitForOpenIndexedDB(context, function (db) {
context._index_keys, function (db) { return waitForTransaction(db, ["blob"], "readonly",
return waitForTransaction(db, ["blob"], "readonly", function (tx) {
function (tx) { var key_path = buildKeyPath([id, name]),
var key_path = buildKeyPath([id, name]), blob_store = tx.objectStore("blob"),
blob_store = tx.objectStore("blob"), start_index,
start_index, end_index,
end_index, promise_list = [];
promise_list = [];
start_index = Math.floor(start / UNITE);
start_index = Math.floor(start / UNITE); if (end !== undefined) {
if (end !== undefined) { end_index = Math.floor(end / UNITE);
end_index = Math.floor(end / UNITE); if (end % UNITE === 0) {
if (end % UNITE === 0) { end_index -= 1;
end_index -= 1;
}
} }
}
function getBlobKey(cursor) { function getBlobKey(cursor) {
var index = parseInt( var index = parseInt(
cursor.primaryKey.slice(key_path.length + 1), cursor.primaryKey.slice(key_path.length + 1),
10 10
), ),
i; i;
if ((start !== 0) && (index < start_index)) { if ((start !== 0) && (index < start_index)) {
// No need to fetch blobs at the start // No need to fetch blobs at the start
return; return;
} }
if ((end !== undefined) && (index > end_index)) { if ((end !== undefined) && (index > end_index)) {
// No need to fetch blobs at the end // No need to fetch blobs at the end
return; return;
}
i = index - start_index;
// Extend array size
while (i > promise_list.length) {
promise_list.push(null);
i -= 1;
}
// Sort the blob by their index
promise_list.splice(
index - start_index,
0,
waitForIDBRequest(blob_store.get(cursor.primaryKey))
);
} }
// Get all blob keys to check if they must be fetched i = index - start_index;
return waitForAllSynchronousCursor( // Extend array size
blob_store.index("_id_attachment") while (i > promise_list.length) {
.openKeyCursor(IDBKeyRange.only([id, name])), promise_list.push(null);
getBlobKey i -= 1;
) }
.then(function () { // Sort the blob by their index
return RSVP.all(promise_list); promise_list.splice(
}); index - start_index,
}); 0,
}); waitForIDBRequest(blob_store.get(cursor.primaryKey))
);
}
// Get all blob keys to check if they must be fetched
return waitForAllSynchronousCursor(
blob_store.index("_id_attachment")
.openKeyCursor(IDBKeyRange.only([id, name])),
getBlobKey
)
.then(function () {
return RSVP.all(promise_list);
});
});
});
}) })
.push(function (result_list) { .push(function (result_list) {
// No need to keep the IDB open // No need to keep the IDB open
...@@ -553,47 +549,46 @@ ...@@ -553,47 +549,46 @@
// Request the full blob // Request the full blob
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
return waitForOpenIndexedDB(db_name, context._version, return waitForOpenIndexedDB(context, function (db) {
context._index_keys, function (db) { return waitForTransaction(db, ["attachment", "blob"], "readonly",
return waitForTransaction(db, ["attachment", "blob"], "readonly", function (tx) {
function (tx) { var key_path = buildKeyPath([id, name]),
var key_path = buildKeyPath([id, name]), attachment_store = tx.objectStore("attachment"),
attachment_store = tx.objectStore("attachment"), blob_store = tx.objectStore("blob");
blob_store = tx.objectStore("blob");
function getBlob(cursor) { function getBlob(cursor) {
var index = parseInt( var index = parseInt(
cursor.primaryKey.slice(key_path.length + 1), cursor.primaryKey.slice(key_path.length + 1),
10 10
), ),
i = index; i = index;
// Extend array size // Extend array size
while (i > array_buffer_list.length) { while (i > array_buffer_list.length) {
array_buffer_list.push(null); array_buffer_list.push(null);
i -= 1; i -= 1;
}
// Sort the blob by their index
array_buffer_list.splice(
index,
0,
cursor.value.blob
);
} }
// Sort the blob by their index
return RSVP.all([ array_buffer_list.splice(
// Get the attachment info (mime type) index,
waitForIDBRequest(attachment_store.get( 0,
key_path cursor.value.blob
)), );
// Get all needed blobs }
waitForAllSynchronousCursor(
blob_store.index("_id_attachment") return RSVP.all([
.openCursor(IDBKeyRange.only([id, name])), // Get the attachment info (mime type)
getBlob waitForIDBRequest(attachment_store.get(
) key_path
]); )),
}); // Get all needed blobs
}); waitForAllSynchronousCursor(
blob_store.index("_id_attachment")
.openCursor(IDBKeyRange.only([id, name])),
getBlob
)
]);
});
});
}) })
.push(function (result_list) { .push(function (result_list) {
...@@ -626,7 +621,7 @@ ...@@ -626,7 +621,7 @@
}; };
IndexedDBStorage.prototype.putAttachment = function (id, name, blob) { IndexedDBStorage.prototype.putAttachment = function (id, name, blob) {
var db_name = this._database_name, context = this; var context = this;
return new RSVP.Queue() return new RSVP.Queue()
.push(function () { .push(function () {
// Split the blob first // Split the blob first
...@@ -644,104 +639,102 @@ ...@@ -644,104 +639,102 @@
handled_size += UNITE; handled_size += UNITE;
} }
return waitForOpenIndexedDB(db_name, context._version, return waitForOpenIndexedDB(context, function (db) {
context._index_keys, function (db) { return waitForTransaction(db, ["attachment", "blob"], "readwrite",
return waitForTransaction(db, ["attachment", "blob"], "readwrite", function (tx) {
function (tx) { var blob_store,
var blob_store, promise_list,
promise_list, delete_promise_list = [],
delete_promise_list = [], key_path = buildKeyPath([id, name]),
key_path = buildKeyPath([id, name]), i;
i; // First write the attachment info on top of previous
// First write the attachment info on top of previous promise_list = [
promise_list = [ waitForIDBRequest(tx.objectStore("attachment").put({
waitForIDBRequest(tx.objectStore("attachment").put({ "_key_path": key_path,
"_key_path": key_path, "_id": id,
"_id": id, "_attachment": name,
"_attachment": name, "info": {
"info": { "content_type": blob.type,
"content_type": blob.type, "length": blob.size
"length": blob.size }
} }))
];
// Then, write all blob parts on top of previous
blob_store = tx.objectStore("blob");
for (i = 0; i < blob_part.length; i += 1) {
promise_list.push(
waitForIDBRequest(blob_store.put({
"_key_path": buildKeyPath([id, name, i]),
"_id" : id,
"_attachment" : name,
"_part" : i,
"blob": blob_part[i]
})) }))
]; );
// Then, write all blob parts on top of previous }
blob_store = tx.objectStore("blob");
for (i = 0; i < blob_part.length; i += 1) {
promise_list.push(
waitForIDBRequest(blob_store.put({
"_key_path": buildKeyPath([id, name, i]),
"_id" : id,
"_attachment" : name,
"_part" : i,
"blob": blob_part[i]
}))
);
}
function deleteEntry(cursor) { function deleteEntry(cursor) {
var index = parseInt( var index = parseInt(
cursor.primaryKey.slice(key_path.length + 1), cursor.primaryKey.slice(key_path.length + 1),
10 10
);
if (index >= blob_part.length) {
delete_promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
); );
if (index >= blob_part.length) {
delete_promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
);
}
} }
}
// Finally, remove all remaining blobs // Finally, remove all remaining blobs
promise_list.push( promise_list.push(
waitForAllSynchronousCursor( waitForAllSynchronousCursor(
blob_store.index("_id_attachment") blob_store.index("_id_attachment")
.openKeyCursor(IDBKeyRange.only([id, name])), .openKeyCursor(IDBKeyRange.only([id, name])),
deleteEntry deleteEntry
) )
); );
return RSVP.all(promise_list) return RSVP.all(promise_list)
.then(function () { .then(function () {
if (delete_promise_list.length) { if (delete_promise_list.length) {
return RSVP.all(delete_promise_list); return RSVP.all(delete_promise_list);
} }
}); });
}); });
}); });
}); });
}; };
IndexedDBStorage.prototype.removeAttachment = function (id, name) { IndexedDBStorage.prototype.removeAttachment = function (id, name) {
return waitForOpenIndexedDB(this._database_name, this._version, return waitForOpenIndexedDB(this, function (db) {
this._index_keys, function (db) { return waitForTransaction(db, ["attachment", "blob"], "readwrite",
return waitForTransaction(db, ["attachment", "blob"], "readwrite", function (tx) {
function (tx) { var promise_list = [],
var promise_list = [], attachment_store = tx.objectStore("attachment"),
attachment_store = tx.objectStore("attachment"), blob_store = tx.objectStore("blob");
blob_store = tx.objectStore("blob");
function deleteEntry(cursor) {
promise_list.push(
waitForIDBRequest(blob_store.delete(cursor.primaryKey))
);
}
function deleteEntry(cursor) { return RSVP.all([
promise_list.push( waitForIDBRequest(
waitForIDBRequest(blob_store.delete(cursor.primaryKey)) attachment_store.delete(buildKeyPath([id, name]))
); ),
} waitForAllSynchronousCursor(
blob_store.index("_id_attachment")
return RSVP.all([ .openKeyCursor(IDBKeyRange.only([id, name])),
waitForIDBRequest( deleteEntry
attachment_store.delete(buildKeyPath([id, name])) )
), ])
waitForAllSynchronousCursor( .then(function () {
blob_store.index("_id_attachment") return RSVP.all(promise_list);
.openKeyCursor(IDBKeyRange.only([id, name])), });
deleteEntry
)
])
.then(function () {
return RSVP.all(promise_list);
});
}); });
}); });
}; };
jIO.addStorage("indexeddb", IndexedDBStorage); jIO.addStorage("indexeddb", IndexedDBStorage);
......
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