Only persist latest mutated model. (#2295)

* Only persist latest mutated model. Fixes #2277

* Updated tests

* Fixed style issues
This commit is contained in:
Andrew Henry 2019-02-22 13:45:44 -08:00 committed by Deep Tailor
parent a8ba3b3fdb
commit 98c8e19d93
4 changed files with 52 additions and 65 deletions

View File

@ -77,14 +77,19 @@ define([], function () {
return promiseFn().then(nextFn); return promiseFn().then(nextFn);
}; };
} }
/**
if (!this.isScheduled(id)) { * Clear any existing persistence calls for object with given ID. This ensures only the most recent persistence
this.clearTransactionFns[id] = * call is executed. This should prevent stale objects being persisted and overwriting fresh ones.
this.transactionService.addToTransaction( */
chain(onCommit, release), if (this.isScheduled(id)) {
chain(onCancel, release) this.clearTransactionsFor(id);
);
} }
this.clearTransactionFns[id] =
this.transactionService.addToTransaction(
chain(onCommit, release),
chain(onCancel, release)
);
}; };
/** /**

View File

@ -93,24 +93,33 @@ define(
expect(mockOnCancel).toHaveBeenCalled(); expect(mockOnCancel).toHaveBeenCalled();
}); });
it("ignores subsequent calls for the same object", function () { describe("Adds callbacks to transaction", function () {
manager.addToTransaction( beforeEach(function () {
testId, spyOn(manager, 'clearTransactionsFor');
jasmine.createSpy(), manager.clearTransactionsFor.and.callThrough();
jasmine.createSpy() });
);
expect(mockTransactionService.addToTransaction.calls.count())
.toEqual(1);
});
it("accepts subsequent calls for other objects", function () { it("and clears pending calls if same object", function () {
manager.addToTransaction( manager.addToTransaction(
'other-id', testId,
jasmine.createSpy(), jasmine.createSpy(),
jasmine.createSpy() jasmine.createSpy()
); );
expect(mockTransactionService.addToTransaction.calls.count()) expect(manager.clearTransactionsFor).toHaveBeenCalledWith(testId);
.toEqual(2); });
it("and does not clear pending calls if different object", function () {
manager.addToTransaction(
'other-id',
jasmine.createSpy(),
jasmine.createSpy()
);
expect(manager.clearTransactionsFor).not.toHaveBeenCalled();
});
afterEach(function () {
expect(mockTransactionService.addToTransaction.calls.count()).toEqual(2);
});
}); });
it("does not remove callbacks from the transaction", function () { it("does not remove callbacks from the transaction", function () {

View File

@ -43,20 +43,10 @@ define([], function () {
var mutationTopic = topic('mutation'); var mutationTopic = topic('mutation');
mutationTopic.listen(function (domainObject) { mutationTopic.listen(function (domainObject) {
var persistence = domainObject.getCapability('persistence'); var persistence = domainObject.getCapability('persistence');
var wasActive = transactionService.isActive();
cacheService.put(domainObject.getId(), domainObject.getModel()); cacheService.put(domainObject.getId(), domainObject.getModel());
if (hasChanged(domainObject)) { if (hasChanged(domainObject)) {
if (!wasActive) {
transactionService.startTransaction();
}
persistence.persist(); persistence.persist();
if (!wasActive) {
transactionService.commit();
}
} }
}); });
} }

View File

@ -83,44 +83,27 @@ define(
.toHaveBeenCalledWith(jasmine.any(Function)); .toHaveBeenCalledWith(jasmine.any(Function));
}); });
[false, true].forEach(function (isActive) { it("calls persist if the model has changed", function () {
var verb = isActive ? "is" : "isn't"; mockModel.persisted = Date.now();
function onlyWhenInactive(expectation) { //Mark the model dirty by setting the mutated date later than the last persisted date.
return isActive ? expectation.not : expectation; mockModel.modified = mockModel.persisted + 1;
}
describe("when a transaction " + verb + " active", function () { mockMutationTopic.listen.calls.mostRecent()
var innerVerb = isActive ? "does" : "doesn't"; .args[0](mockDomainObject);
beforeEach(function () { expect(mockPersistence.persist).toHaveBeenCalled();
mockTransactionService.isActive.and.returnValue(isActive); });
});
describe("and mutation occurs", function () { it("does not call persist if the model has not changed", function () {
beforeEach(function () { mockModel.persisted = Date.now();
mockMutationTopic.listen.calls.mostRecent()
.args[0](mockDomainObject);
});
mockModel.modified = mockModel.persisted;
it(innerVerb + " start a new transaction", function () { mockMutationTopic.listen.calls.mostRecent()
onlyWhenInactive( .args[0](mockDomainObject);
expect(mockTransactionService.startTransaction)
).toHaveBeenCalled();
});
it("calls persist", function () { expect(mockPersistence.persist).not.toHaveBeenCalled();
expect(mockPersistence.persist).toHaveBeenCalled();
});
it(innerVerb + " immediately commit", function () {
onlyWhenInactive(
expect(mockTransactionService.commit)
).toHaveBeenCalled();
});
});
});
}); });
}); });
} }