| import { createError, REV_CONFLICT } from '../errors'; |
| import isDeleted from './isDeleted'; |
| import { parseDoc as parseDoc } from './parseDoc'; |
| import calculateWinningRev from '../../deps/merge/winningRev'; |
| import merge from '../../deps/merge/index'; |
| import revExists from '../../deps/merge/revExists'; |
| |
| function updateDoc(revLimit, prev, docInfo, results, |
| i, cb, writeDoc, newEdits) { |
| |
| if (revExists(prev.rev_tree, docInfo.metadata.rev)) { |
| results[i] = docInfo; |
| return cb(); |
| } |
| |
| // sometimes this is pre-calculated. historically not always |
| var previousWinningRev = prev.winningRev || calculateWinningRev(prev); |
| var previouslyDeleted = 'deleted' in prev ? prev.deleted : |
| isDeleted(prev, previousWinningRev); |
| var deleted = 'deleted' in docInfo.metadata ? docInfo.metadata.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(prev.rev_tree, docInfo.metadata.rev_tree[0], revLimit); |
| |
| var inConflict = newEdits && (((previouslyDeleted && deleted) || |
| (!previouslyDeleted && merged.conflicts !== 'new_leaf') || |
| (previouslyDeleted && !deleted && merged.conflicts === 'new_branch'))); |
| |
| if (inConflict) { |
| var err = createError(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 = calculateWinningRev(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; |
| if (newRev === winningRev) { |
| // if the new rev is the same as the winning rev, we can reuse that value |
| newRevIsDeleted = winningRevIsDeleted; |
| } else { |
| // if they're not the same, then we need to recalculate |
| newRevIsDeleted = isDeleted(docInfo.metadata, newRev); |
| } |
| |
| writeDoc(docInfo, winningRev, winningRevIsDeleted, newRevIsDeleted, |
| true, delta, i, cb); |
| } |
| |
| export default updateDoc; |