| 'use strict'; |
| |
| var merge = require('../../merge'); |
| var errors = require('../errors'); |
| var isDeleted = require('./isDeleted'); |
| var parseDoc = require('./parseDoc').parseDoc; |
| |
| function revExists(metadata, rev) { |
| var found = false; |
| merge.traverseRevTree(metadata.rev_tree, function (leaf, pos, id) { |
| if ((pos + '-' + id) === rev) { |
| found = true; |
| } |
| }); |
| return found; |
| } |
| |
| function updateDoc(prev, docInfo, results, i, cb, writeDoc, newEdits) { |
| |
| if (revExists(prev, docInfo.metadata.rev)) { |
| results[i] = docInfo; |
| return cb(); |
| } |
| |
| // TODO: some of these can be pre-calculated, but it's safer to just |
| // call merge.winningRev() and isDeleted() all over again |
| var previousWinningRev = merge.winningRev(prev); |
| var previouslyDeleted = isDeleted(prev, previousWinningRev); |
| var deleted = isDeleted(docInfo.metadata); |
| var isRoot = /^1-/.test(docInfo.metadata.rev); |
| |
| if (previouslyDeleted && !deleted && newEdits && isRoot) { |
| var newDoc = docInfo.data; |
| newDoc._rev = previousWinningRev; |
| newDoc._id = docInfo.metadata.id; |
| docInfo = parseDoc(newDoc, newEdits); |
| } |
| |
| var merged = merge.merge(prev.rev_tree, docInfo.metadata.rev_tree[0], 1000); |
| |
| var inConflict = newEdits && (((previouslyDeleted && deleted) || |
| (!previouslyDeleted && merged.conflicts !== 'new_leaf') || |
| (previouslyDeleted && !deleted && merged.conflicts === 'new_branch'))); |
| |
| if (inConflict) { |
| var err = errors.error(errors.REV_CONFLICT); |
| results[i] = err; |
| return cb(); |
| } |
| |
| var newRev = docInfo.metadata.rev; |
| docInfo.metadata.rev_tree = merged.tree; |
| /* istanbul ignore else */ |
| if (prev.rev_map) { |
| docInfo.metadata.rev_map = prev.rev_map; // used only by leveldb |
| } |
| |
| // recalculate |
| var winningRev = merge.winningRev(docInfo.metadata); |
| var winningRevIsDeleted = isDeleted(docInfo.metadata, winningRev); |
| |
| // calculate the total number of documents that were added/removed, |
| // from the perspective of total_rows/doc_count |
| var delta = (previouslyDeleted === winningRevIsDeleted) ? 0 : |
| previouslyDeleted < winningRevIsDeleted ? -1 : 1; |
| |
| var newRevIsDeleted = isDeleted(docInfo.metadata, newRev); |
| |
| writeDoc(docInfo, winningRev, winningRevIsDeleted, newRevIsDeleted, |
| true, delta, i, cb); |
| } |
| |
| module.exports = updateDoc; |