blob: f2f3c063242560f52c7b0f29a1f3f62848c48fba [file] [log] [blame]
import clone from '../deps/clone';
import Promise from '../deps/promise';
function isGenOne(rev) {
return /^1-/.test(rev);
}
function createBulkGetOpts(diffs) {
var requests = [];
Object.keys(diffs).forEach(function (id) {
var missingRevs = diffs[id].missing;
missingRevs.forEach(function (missingRev) {
requests.push({
id: id,
rev: missingRev
});
});
});
return {
docs: requests,
revs: true,
attachments: true,
binary: true
};
}
//
// Fetch all the documents from the src as described in the "diffs",
// which is a mapping of docs IDs to revisions. If the state ever
// changes to "cancelled", then the returned promise will be rejected.
// Else it will be resolved with a list of fetched documents.
//
function getDocs(src, diffs, state) {
diffs = clone(diffs); // we do not need to modify this
var resultDocs = [];
function getAllDocs() {
var bulkGetOpts = createBulkGetOpts(diffs);
if (!bulkGetOpts.docs.length) { // optimization: skip empty requests
return;
}
return src.bulkGet(bulkGetOpts).then(function (bulkGetResponse) {
/* istanbul ignore if */
if (state.cancelled) {
throw new Error('cancelled');
}
bulkGetResponse.results.forEach(function (bulkGetInfo) {
bulkGetInfo.docs.forEach(function (doc) {
if (doc.ok) {
resultDocs.push(doc.ok);
}
});
});
});
}
function hasAttachments(doc) {
return doc._attachments && Object.keys(doc._attachments).length > 0;
}
function fetchRevisionOneDocs(ids) {
// Optimization: fetch gen-1 docs and attachments in
// a single request using _all_docs
return src.allDocs({
keys: ids,
include_docs: true
}).then(function (res) {
if (state.cancelled) {
throw new Error('cancelled');
}
res.rows.forEach(function (row) {
if (row.deleted || !row.doc || !isGenOne(row.value.rev) ||
hasAttachments(row.doc)) {
// if any of these conditions apply, we need to fetch using get()
return;
}
// the doc we got back from allDocs() is sufficient
resultDocs.push(row.doc);
delete diffs[row.id];
});
});
}
function getRevisionOneDocs() {
// filter out the generation 1 docs and get them
// leaving the non-generation one docs to be got otherwise
var ids = Object.keys(diffs).filter(function (id) {
var missing = diffs[id].missing;
return missing.length === 1 && isGenOne(missing[0]);
});
if (ids.length > 0) {
return fetchRevisionOneDocs(ids);
}
}
function returnDocs() {
return resultDocs;
}
return Promise.resolve()
.then(getRevisionOneDocs)
.then(getAllDocs)
.then(returnDocs);
}
export default getDocs;