Skip to content

Instantly share code, notes, and snippets.

@willconant
Created April 7, 2010 20:49
Show Gist options
  • Save willconant/359435 to your computer and use it in GitHub Desktop.
Save willconant/359435 to your computer and use it in GitHub Desktop.
// saves local changes to articles. mergeParentGuid should be null unless we are resolving a merge conflict
function editArticle(articleName, content, mergeParentGuid, callback) {
flow.exec(
function() {
// find my current head for this article
db.sync.findLastLocal("articleHeads", {name: articleName}, this)
},function(err, articleHead) {
if (err) throw err
var article = {
name: articleName,
parent1Guid: articleHead ? articleHead.currentGuid : null,
parent2Guid: mergeParentGuid,
content: content
}
// save the article in a sync table getting a guid back
db.sync.save("articles", article, this)
},function(err, newGuid) {
if (err) throw err
// save an entry in the articleHeads table pointing at the latest
// version of this article
db.sync.save("articleHeads", {name: articleName, currentGuid: newGuid}, callback)
}
)
}
// this is a quick-and-dirty bit of code for pulling remote articles and marking conflicts
db.sync.pull(remoteNode, "articles", function(articlesSyncResponse) {
articlesSyncResponse.addListener("close", function(err) {
if (err) throw err
db.sync.pull(remoteNode, "articleHeads", function(headsSyncResponse) {
// I think this is most convenient if the response is an EventEmitter
// The "receive" event is emitted for each new row from the remote node.
// By the time "receive" is fired, the node is already saved in your
// local db. (The idea being that NoSQLite keeps track of which rows
// it has received from each node, so you don't have to. That's the
// automatic part of the synchronization layer.)
var latestRemoteHeadGuids = {}
headsSyncResponse.addListener("receive", function(remoteHead) {
latestRemoteHeadGuids[remoteHead.articleName] = remoteHead.currentGuid
})
headsSyncResponse.addListener("close", function(err) {
if (err) throw err
// now I have all of the heads of remotely changed documents...
// we can actually look for conflicts now.
for (var articleName in latestRemoteHeadGuids) {
db.sync.findLastLocal("articleHeads", {name: articleName}, function(localHead) {
// sometimes I hate asynchronous programming
// saving keystrokes...
var remoteGuid = latestRemoteHeadGuids[articleName]
if (localHead === null) {
// simple case, we don't even have that article
db.sync.save("articleHeads", {name: articleName, currentGuid: remoteGuid})
}
else {
articleIsDescendantOf(remoteGuid, localHead.currentGuid, function(isDescendant) {
if (isDescendant) {
// this is also a simple case akin to Git's "fast-forward"
db.sync.save("articleHeads", {name: articleName, currentGuid: remoteGuid})
}
else {
// This means we have a conflict.
// keep remotes from pulling until conflict is resolved
db.sync.disableSync("articles")
db.sync.disableSync("articleHeads")
// save conflict state in local tables (i think you should support
// upserts in local non-sync tables).
db.upsert("articleConflicts", {articleName: articleName}, {articleName: articleName, conflict: true})
}
})
}
}) // end of findLastLocal("articleHeads"...
} // end for (var articleName... this is why I wrote flow-js
}) // end "close" handler on headsSyncResponse
}) // end db.sync.pull articleHeads
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment