Created
September 13, 2010 20:35
-
-
Save apage43/577988 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Changes filter: "conflicts": "function(doc, req) { if(doc._conflicts) { return true; } else { return false; }}" | |
var dbase = 'focus'; | |
var ddoc = 'app'; | |
var sys = require('sys'), | |
couchdb = require('node-couchdb/lib/couchdb'), | |
client = couchdb.createClient(5984, 'crate.im'), | |
db = client.db(dbase), | |
changes = db.changesStream({filter: ddoc + '/conflicts'}); | |
var default_merge = function(conflicts, prevdoc) | |
{ | |
if(!prevdoc) { | |
return false; | |
} | |
delete prevdoc._rev; | |
var newdoc =JSON.parse(JSON.stringify(prevdoc)); | |
var updated = {}; | |
for(var i in conflicts) | |
{ | |
sys.puts(' Conflict ' + i + ' ' + JSON.stringify(conflicts[i])); | |
for(var k in conflicts[i]) | |
{ | |
delete conflicts[i]._rev; | |
if(!newdoc[k]) | |
{ | |
//Key doesn't exist in previous rev. | |
newdoc[k] = conflicts[i][k]; | |
} else { | |
if(!prevdoc[k]) { | |
//Conflicting docs both added the same new field. | |
//not handling this. | |
sys.puts("Both added field " + k); | |
return false; | |
} else { | |
//Key is in new doc and previous doc. | |
if(JSON.stringify(conflicts[i][k]) != JSON.stringify(prevdoc[k])) { | |
//We have a new version of this key. | |
if(!updated[k]) { | |
sys.puts("Field " + k + ": " + JSON.stringify(prevdoc[k]) + " -> " + JSON.stringify(conflicts[i][k])); | |
//We are the sole updater so far. | |
newdoc[k] = conflicts[i][k]; | |
updated[k] = true; | |
} else { | |
//Conflicting docs both updated the same field, not handling this. | |
sys.puts("Both updated field " + k + "\n"); | |
return false; | |
} | |
} | |
} | |
} | |
} | |
} | |
return newdoc; | |
} | |
db.getDoc('_design/' + ddoc, function (er, ddoc) { | |
if(er) throw new Error("Error fetching design doc"); | |
var merge = default_merge; | |
if(ddoc.merge_func) | |
{ | |
sys.puts("Custom merge function: " + ddoc.merge_func); | |
merge = eval(ddoc.merge_func); | |
} | |
changes.on('data', function (change) { | |
sys.print(JSON.stringify(change)+'\n'); | |
db.request({method: 'get', path: '/' + change.id, query: {conflicts: true, revs: true}}, function(er, doc) | |
{ | |
sys.print('Processing conflict...\n'); | |
if(doc._conflicts) { | |
db.request({method: 'get', path: '/'+change.id, query: { | |
rev: (doc._revisions.start - 1) + '-' + doc._revisions.ids[1] | |
}}, function(er, previous) { | |
var conflicts = []; | |
sys.print(' Previous rev: ' + JSON.stringify(previous)+'\n'); | |
for(var rev in doc._conflicts) { | |
db.request({method: 'get', path:'/' + change.id, query: {rev: doc._conflicts[rev]}}, function(er, cdoc) { | |
if(er) throw new Error(JSON.stringify(er)); | |
conflicts.push(cdoc); | |
if(conflicts.length == doc._conflicts.length) { | |
var current = JSON.parse(JSON.stringify(doc)); | |
delete current._revisions; | |
delete current._conflicts; | |
conflicts.push(current); | |
var result = merge(conflicts, previous); | |
if(result) | |
{ | |
sys.puts(' Merge result: ' + JSON.stringify(result)); | |
result._rev = doc._rev; | |
db.bulkDocs({docs: [result].concat(doc._conflicts.map(function(x) { | |
return {_id: doc._id, _rev: x, _deleted: true}; | |
}))}, function(er) { | |
if(er) sys.puts("Commit of merge failed: " + JSON.stringify(er)); | |
sys.puts("Merge successfully saved."); | |
}); | |
} else { | |
sys.puts("Could not resolve conflict automatically."); | |
} | |
}; | |
}); | |
} | |
}); | |
} | |
}); | |
}); | |
}); | |
sys.print('Mergeist - couchdb conflicts automerger\n'); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment