forked from glynnbird/deconflict
-
Notifications
You must be signed in to change notification settings - Fork 0
/
deconflict.js
141 lines (114 loc) · 4.38 KB
/
deconflict.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// thsis function takes the list of revisions and removes any deleted or not 'ok' ones.
// returns a flat array of document objects
var filterList = function(list,excluderev) {
var retval = []
for (var i in list) {
if (list[i].ok && !list[i].ok._deleted) {
if (!excluderev || (excluderev && list[i].ok._rev != excluderev)) {
retval.push(list[i].ok);
}
}
}
return retval;
}
// convert the incoming array of document to an array of deletions - {_id:"x",_rev:"y",_deleted:true}
var convertToDeletions = function(list) {
var retval = [];
for (var i in list) {
var obj = { _id:list[i]._id, _rev:list[i]._rev, _deleted: true };
retval.push(obj);
}
return retval;
}
// copy the contents of object b into object a
var objmerge = function(a,b) {
for (var i in b) {
if (i != "_id" && i != "_rev") {
a[i] = b[i];
}
}
return a;
}
// In a database 'db' (a nano object), that has document with id 'docid', resolve the
// conflicts by choosing the revision with the highest field 'fieldname'.
var latestWins = function(db, docid, fieldname, callback) {
// fetch the document with open_revs=all
db.get(docid, {open_revs:'all'}, function(err, data) {
// return if document isn't there
if (err) {
return callback("Document could not be fetched");
}
// remove 'deleted' leaf nodes from the list
var doclist = filterList(data);
// if the there is only <=1 revision left, the document is either deleted
// or not conflcited; either way, we're done
if (doclist.length <= 1) {
return callback("Document is not conflicted.");
}
// sort the array of documents by the supplied fieldname
// our winner will be the last object in the sorted array
doclist.sort(function(a, b ){ return a[fieldname]-b[fieldname]});
var last=doclist.pop(); // remove the winning revision from the array
// turn the remaining leaf nodes into deletions
doclist = convertToDeletions(doclist);
// now we can delete the unwanted revisions
db.bulk({docs: doclist}, callback);
});
};
// In a database 'db' (a nano object), that has document with id 'docid', resolve the
// conflicts by merging all of the conflicting revisions together(!)
var merge = function(db, docid, callback) {
var winner = null;
// fetch the document to establish the current winning revision
db.get(docid, function(err,data) {
// return if document isn't there
if (err) {
return callback("Document could not be fetched");
}
winner = data;
// fetch the document with open_revs=all
db.get(docid, {open_revs:'all'}, function(err, data) {
// remove 'deleted' leaf nodes from the list and the winning revision
var doclist = filterList(data, winner._rev);
// if the there is only <=1 revision left, the document not conflcited
if (doclist.length <= 1) {
return callback("Document is not conflicted.");
}
// merge the losing revisions' contents into the winner's
for(var i in doclist) {
var loser = doclist[i];
winner = objmerge(winner, loser);
}
// turn the losing leaf nodes into deletions
doclist = convertToDeletions(doclist);
// add our merged winners
doclist.push(winner);
// now we can deleted the unwanted revisions and create a new winner
db.bulk({docs: doclist}, callback);
});
});
};
// In a database 'db' (a nano object), that has document with id 'docid', resolve the
// conflicts by only keeping the nominated revision (rev)
var nominated = function(db, docid, rev, callback) {
// fetch the document with open_revs=all
db.get(docid, {open_revs:'all'}, function(err, data) {
// remove 'deleted' leaf nodes from the list and the revision
// we want to reamain as the winner
var doclist = filterList(data, rev);
// if the there is only <=1 revision left, the document is
// not conflcited and we don't need to do anything
if (doclist.length <= 1) {
return callback("Document is not conflicted.");
}
// turn the losing leaf nodes into deletions
doclist = convertToDeletions(doclist);
// now we can delete the unwanted revisions, which should leave our winner
db.bulk({docs: doclist}, callback);
});
};
module.exports = {
latestWins: latestWins,
merge: merge,
nominated: nominated
}