blob: bc354fd94be50f9a3f4dd990b5c146e0aeb3e4f6 [file] [log] [blame]
// Abstraction over IDBCursor and getAll()/getAllKeys() that allows us to batch our operations
// while falling back to a normal IDBCursor operation on browsers that don't support getAll() or
// getAllKeys(). This allows for a much faster implementation than just straight-up cursors, because
// we're not processing each document one-at-a-time.
function runBatchedCursor(objectStore, startKey, descending, batchSize, onBatch) {
// Bail out of getAll()/getAllKeys() in the following cases:
// 1) either method is unsupported (we need both)
// 2) batchSize is 1 (might as well use IDBCursor), or batchSize is -1 (i.e. batchSize unlimited,
// not really clear the user wants a batched approach where the entire DB is read into memory,
// perhaps they are filtering on a per-doc basis)
// 3) descending – no real way to do this via getAll()/getAllKeys()
var useGetAll = typeof objectStore.getAll === 'function' &&
typeof objectStore.getAllKeys === 'function' && batchSize > 1 && !descending;
var keysBatch;
var valuesBatch;
var pseudoCursor;
function onGetAll(e) {
valuesBatch = e.target.result;
if (keysBatch) {
onBatch(keysBatch, valuesBatch, pseudoCursor);
}
}
function onGetAllKeys(e) {
keysBatch = e.target.result;
if (valuesBatch) {
onBatch(keysBatch, valuesBatch, pseudoCursor);
}
}
function continuePseudoCursor() {
if (!keysBatch.length) { // no more results
return onBatch();
}
// fetch next batch, exclusive start
range = IDBKeyRange.lowerBound(keysBatch[keysBatch.length - 1], true);
keysBatch = null;
valuesBatch = null;
objectStore.getAll(range, batchSize).onsuccess = onGetAll;
objectStore.getAllKeys(range, batchSize).onsuccess = onGetAllKeys;
}
function onCursor(e) {
var cursor = e.target.result;
if (!cursor) { // done
return onBatch();
}
// regular IDBCursor acts like a batch where batch size is always 1
onBatch([cursor.key], [cursor.value], cursor);
}
var range = (startKey && !descending) ? IDBKeyRange.lowerBound(startKey, true) : null;
if (useGetAll) {
pseudoCursor = {"continue": continuePseudoCursor};
objectStore.getAll(range, batchSize).onsuccess = onGetAll;
objectStore.getAllKeys(range, batchSize).onsuccess = onGetAllKeys;
} else if (descending) {
objectStore.openCursor(range, 'prev').onsuccess = onCursor;
} else {
objectStore.openCursor(range).onsuccess = onCursor;
}
}
export default runBatchedCursor;