[Persistence] Handle overwrite/cancel

Handle Overwrite/Cancel more correctly when revision conflicts
are detected. WTD-1033.
This commit is contained in:
Victor Woeltjen
2015-03-20 14:39:47 -07:00
parent 513c06a81b
commit 1174f746f7
4 changed files with 59 additions and 19 deletions

View File

@ -22,13 +22,26 @@ define(
* @constructor * @constructor
*/ */
function PersistenceCapability(persistenceService, SPACE, domainObject) { function PersistenceCapability(persistenceService, SPACE, domainObject) {
// Cache modified timestamp
var modified = domainObject.getModel().modified;
// Update a domain object's model upon refresh // Update a domain object's model upon refresh
function updateModel(model) { function updateModel(model) {
modified = model.modified;
return domainObject.useCapability("mutation", function () { return domainObject.useCapability("mutation", function () {
return model; return model;
}); });
} }
// For refresh; update a domain object model, only if there
// are no unsaved changes.
function maybeUpdateModel(model) {
// Only update the model if there are no pending changes
if (domainObject.getModel().modified === modified) {
updateModel(model);
}
}
return { return {
/** /**
* Persist any changes which have been made to this * Persist any changes which have been made to this
@ -37,12 +50,18 @@ define(
* if persistence is successful, and rejected * if persistence is successful, and rejected
* if not. * if not.
*/ */
persist: function () { persist: function (hard) {
return persistenceService.updateObject( return persistenceService.updateObject(
SPACE, SPACE,
domainObject.getId(), domainObject.getId(),
domainObject.getModel() domainObject.getModel(),
); { check: !hard }
).then(function (value) {
if (value) {
modified = domainObject.getModel().modified;
}
return value;
});
}, },
/** /**
* Update this domain object to match the latest from * Update this domain object to match the latest from
@ -50,12 +69,12 @@ define(
* @returns {Promise} a promise which will be resolved * @returns {Promise} a promise which will be resolved
* when the update is complete * when the update is complete
*/ */
refresh: function () { refresh: function (hard) {
return persistenceService.readObject( return persistenceService.readObject(
SPACE, SPACE,
domainObject.getId(), domainObject.getId(),
{ cache: false } // Disallow cached reads { cache: false } // Disallow cached reads
).then(updateModel); ).then(hard ? updateModel : maybeUpdateModel);
}, },
/** /**
* Get the space in which this domain object is persisted; * Get the space in which this domain object is persisted;

View File

@ -116,9 +116,9 @@ define(
* @returns {Promise.<boolean>} an indicator of the success or * @returns {Promise.<boolean>} an indicator of the success or
* failure of this request * failure of this request
*/ */
createObject: function (space, key, value) { createObject: function (space, key, value, options) {
addToCache(space, key, value); addToCache(space, key, value);
return persistenceService.createObject(space, key, value); return persistenceService.createObject(space, key, value, options);
}, },
/** /**
* Read an object from a specific space. This will read from a * Read an object from a specific space. This will read from a
@ -132,10 +132,15 @@ define(
* in this space) * in this space)
*/ */
readObject: function (space, key, options) { readObject: function (space, key, options) {
var force = (options || {}).cache === false; // Ignore cache upon request
return (cache[space] && cache[space][key] && !force) ? if ((options || {}).cache === false) {
return persistenceService.readObject(space, key, options);
}
// Otherwise, use the cache if it's there (and put new
// values into the cache, as well.)
return (cache[space] && cache[space][key]) ?
fastPromise(cache[space][key].value) : fastPromise(cache[space][key].value) :
persistenceService.readObject(space, key) persistenceService.readObject(space, key, options)
.then(putCache(space, key)); .then(putCache(space, key));
}, },
/** /**
@ -149,9 +154,12 @@ define(
* @returns {Promise.<boolean>} an indicator of the success or * @returns {Promise.<boolean>} an indicator of the success or
* failure of this request * failure of this request
*/ */
updateObject: function (space, key, value) { updateObject: function (space, key, value, options) {
return persistenceService.updateObject(space, key, value, options)
.then(function (result) {
addToCache(space, key, value); addToCache(space, key, value);
return persistenceService.updateObject(space, key, value); return result;
});
}, },
/** /**
* Delete an object in a specific space. This will * Delete an object in a specific space. This will
@ -164,7 +172,7 @@ define(
* @returns {Promise.<boolean>} an indicator of the success or * @returns {Promise.<boolean>} an indicator of the success or
* failure of this request * failure of this request
*/ */
deleteObject: function (space, key, value) { deleteObject: function (space, key, value, options) {
if (cache[space]) { if (cache[space]) {
delete cache[space][key]; delete cache[space][key];
} }

View File

@ -155,11 +155,12 @@ define(
* of the success (true) or failure (false) of this * of the success (true) or failure (false) of this
* operation * operation
*/ */
updateObject: function (space, key, value) { updateObject: function (space, key, value, options) {
var check = (options || {}).check;
function checkUpdate(response) { function checkUpdate(response) {
return checkResponse(response, key); return checkResponse(response, key);
} }
return put(key, value, { version: revs[key] }) return put(key, value, check && { version: revs[key] })
.then(checkUpdate); .then(checkUpdate);
}, },
/** /**

View File

@ -22,10 +22,10 @@ define(
// Issue a new persist call for the domain object associated with // Issue a new persist call for the domain object associated with
// this failure. // this failure.
function persist(failure) { function persist(failure) {
var undecoratedPersistence = var decoratedPersistence =
failure.domainObject.getCapability('persistence'); failure.domainObject.getCapability('persistence');
return undecoratedPersistence && return decoratedPersistence &&
undecoratedPersistence.persist(); decoratedPersistence.persist(true);
} }
// Retry persistence for this set of failed attempts // Retry persistence for this set of failed attempts
@ -38,6 +38,16 @@ define(
}); });
} }
// Discard changes for a failed refresh
function discard(failure) {
return failure.persistence.refresh(true);
}
// Discard changes associated with a failed save
function discardAll(failures) {
return $q.all(failures.map(discard));
}
// Handle failures in persistence // Handle failures in persistence
function handleFailures(failures) { function handleFailures(failures) {
// Prepare dialog for display // Prepare dialog for display
@ -49,6 +59,8 @@ define(
// If so, try again // If so, try again
if (key === PersistenceFailureConstants.OVERWRITE_KEY) { if (key === PersistenceFailureConstants.OVERWRITE_KEY) {
return retry(revisionErrors); return retry(revisionErrors);
} else {
return discardAll(revisionErrors);
} }
} }