histo-revisions v0.0.2
A database that tracks changing revisions of data.
Each revision is accessible through a unique ref which is based on a cryptographic hash of the data's content and history. A ref is similar to a git commit hash.
Each written data object is combined with a link to its ancestors - the combination is called a revision. A revision can be compared to a git commit object.
Revisions look like this:
{
ancestors: ['someref'],
data: 'some data'
}The cryptographic hash of the revision is its ref.
##Documentation
revisions.createDB(opts) -> dbdb.put(data, [ancestorRefs], cb)db.get([ref], cb)db.head(cb) -> refdb.setHead(ref, [previousHead], cb)db.remoteHead(remoteName, cb)db.setRemoteHead(remoteName, ref, cb)db.refDifference(fromRef, toRef, cb)db.ancestors(ref, cb)db.commonAncestor(ref1, ref2, cb)db.createStream(refs) -> streamdb.writeStream(stream, cb)revisions.createSynchronizer(sourceDB, targetDB) -> synchronizersynchronizer.run(cb)- Merging synchronized data
###require('histo-revisions') -> revisions
{
name: 'your-db-name', // will generate uuid if omitted
revisionStore: revStore,
branchStore: branchStore
}With revStore being an object with a content-addressable store interface:
put(data, cb): should write some data and responds with a unique identifier of the data in the callbackget(identifier, cb): should respond with the data in the callbackdel(identifier, cb): should delete the data for the specified identifier
branchStore is expected to be a simple key-value store interface:
put(key, value, cb)get(key, cb)del(key, cb)
The difference is computed using the graph-difference module.
The common ancestor is computed using the ancestor module.
namehead(cb)refDifference(fromRef, toRef, cb)createStream(refs)->stream
targetDB requires the following set of functions:
head(cb)remoteHead(remoteName, cb)writeStream(stream, cb)setRemoteHead(remoteName, ref, cb)
function readRemoteRev(db, remoteName, cb) {
db.remoteHead(remoteName, function(err, remoteHead) {
db.get(remoteHead, function(err, remoteData) {
cb(null, {head: remoteHead, data: remoteData});
});
});
}
function readLocalRev(db, cb) {
db.head(function(err, localHead) {
db.get(localHead, function(localData) {
cb(null, {head: localHead, data: remoteData});
});
});
}
readRemoteRev(targetDB, 'your-remote-name', function(err, remoteRev) {
readLocalRev(targetDB, function(err, localRev) {
var mergedData = yourMergeFunction(remoteRev.data, localRev.data);
var ancestors = [remoteRev.head, localRev.head];
targetDB.put(mergedData, ancestors, function(err, mergedRef) {
targetDB.setHead(mergedRef, localRev.head, function(err) {
// on err repeat merging with new local head
});
});
});
});##Todo
- list of remotes
- garbage collect history
##Contributors This project was created by Mirko Kiefer (@mirkokiefer).

