blob: 2753ea6fe7af05ee29d5cbcd30d516a10b7a1ca6 [file] [log] [blame]
'use strict';
var Promise = require('./deps/promise');
var explain404 = require('./deps/explain404');
var pouchCollate = require('pouchdb-collate');
var collate = pouchCollate.collate;
function updateCheckpoint(db, id, checkpoint, returnValue) {
return db.get(id).catch(function (err) {
if (err.status === 404) {
if (db.type() === 'http') {
explain404(
'PouchDB is just checking if a remote checkpoint exists.');
}
return {_id: id};
}
throw err;
}).then(function (doc) {
if (returnValue.cancelled) {
return;
}
doc.last_seq = checkpoint;
return db.put(doc).catch(function (err) {
if (err.status === 409) {
// retry; someone is trying to write a checkpoint simultaneously
return updateCheckpoint(db, id, checkpoint, returnValue);
}
throw err;
});
});
}
function Checkpointer(src, target, id, returnValue) {
this.src = src;
this.target = target;
this.id = id;
this.returnValue = returnValue;
}
Checkpointer.prototype.writeCheckpoint = function (checkpoint) {
var self = this;
return this.updateTarget(checkpoint).then(function () {
return self.updateSource(checkpoint);
});
};
Checkpointer.prototype.updateTarget = function (checkpoint) {
return updateCheckpoint(this.target, this.id, checkpoint, this.returnValue);
};
Checkpointer.prototype.updateSource = function (checkpoint) {
var self = this;
if (this.readOnlySource) {
return Promise.resolve(true);
}
return updateCheckpoint(this.src, this.id, checkpoint, this.returnValue)
.catch(function (err) {
var isForbidden = typeof err.status === 'number' &&
Math.floor(err.status / 100) === 4;
if (isForbidden) {
self.readOnlySource = true;
return true;
}
throw err;
});
};
Checkpointer.prototype.getCheckpoint = function () {
var self = this;
return self.target.get(self.id).then(function (targetDoc) {
return self.src.get(self.id).then(function (sourceDoc) {
if (collate(targetDoc.last_seq, sourceDoc.last_seq) === 0) {
return sourceDoc.last_seq;
}
return 0;
}, function (err) {
if (err.status === 404 && targetDoc.last_seq) {
return self.src.put({
_id: self.id,
last_seq: 0
}).then(function () {
return 0;
}, function (err) {
if (err.status === 401) {
self.readOnlySource = true;
return targetDoc.last_seq;
}
return 0;
});
}
throw err;
});
}).catch(function (err) {
if (err.status !== 404) {
throw err;
}
return 0;
});
};
module.exports = Checkpointer;