From f5a4a370f9c5a3123552b620ae88586c359b9d7c Mon Sep 17 00:00:00 2001 From: Victor Woeltjen Date: Fri, 25 Sep 2015 11:36:48 -0700 Subject: [PATCH] [Persistence] Add persisted timestamp ...to any domain object models loaded from persistence which do not have one. The presence of this timestamp is necessary for the persistence capability to determine whether an object should be created or updated when a request to persist is made. nasa/openmctweb#139. --- platform/core/bundle.json | 1 + .../core/src/models/PersistedModelProvider.js | 23 ++++++- .../test/models/PersistedModelProviderSpec.js | 65 +++++++++++++++---- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/platform/core/bundle.json b/platform/core/bundle.json index 952daf5570..330ac1c2b9 100644 --- a/platform/core/bundle.json +++ b/platform/core/bundle.json @@ -66,6 +66,7 @@ "depends": [ "persistenceService", "$q", + "now", "PERSISTENCE_SPACE", "ADDITIONAL_PERSISTENCE_SPACES" ] diff --git a/platform/core/src/models/PersistedModelProvider.js b/platform/core/src/models/PersistedModelProvider.js index a10f818179..c5e2927a96 100644 --- a/platform/core/src/models/PersistedModelProvider.js +++ b/platform/core/src/models/PersistedModelProvider.js @@ -39,14 +39,16 @@ define( * @param {PersistenceService} persistenceService the service in which * domain object models are persisted. * @param $q Angular's $q service, for working with promises + * @param {function} now a function which provides the current time * @param {string} space the name of the persistence space(s) * from which models should be retrieved. * @param {string} spaces additional persistence spaces to use */ - function PersistedModelProvider(persistenceService, $q, space, spaces) { + function PersistedModelProvider(persistenceService, $q, now, space, spaces) { this.persistenceService = persistenceService; this.$q = $q; this.spaces = [space].concat(spaces || []); + this.now = now; } // Take the most recently modified model, for cases where @@ -61,7 +63,9 @@ define( PersistedModelProvider.prototype.getModels = function (ids) { var persistenceService = this.persistenceService, $q = this.$q, - spaces = this.spaces; + spaces = this.spaces, + space = this.space, + now = this.now; // Load a single object model from any persistence spaces function loadModel(id) { @@ -72,11 +76,24 @@ define( }); } + // Ensure that models read from persistence have some + // sensible timestamp indicating they've been persisted. + function addPersistedTimestamp(model) { + if (model && (model.persisted === undefined)) { + model.persisted = model.modified !== undefined ? + model.modified : now(); + } + + return model; + } + // Package the result as id->model function packageResult(models) { var result = {}; ids.forEach(function (id, index) { - result[id] = models[index]; + if (models[index]) { + result[id] = addPersistedTimestamp(models[index]); + } }); return result; } diff --git a/platform/core/test/models/PersistedModelProviderSpec.js b/platform/core/test/models/PersistedModelProviderSpec.js index 8dcb58a400..81769834bf 100644 --- a/platform/core/test/models/PersistedModelProviderSpec.js +++ b/platform/core/test/models/PersistedModelProviderSpec.js @@ -35,6 +35,7 @@ define( SPACE = "space0", spaces = [ "space1" ], modTimes, + mockNow, provider; function mockPromise(value) { @@ -55,19 +56,33 @@ define( beforeEach(function () { modTimes = {}; mockQ = { when: mockPromise, all: mockAll }; - mockPersistenceService = { - readObject: function (space, id) { + mockPersistenceService = jasmine.createSpyObj( + 'persistenceService', + [ + 'createObject', + 'readObject', + 'updateObject', + 'deleteObject', + 'listSpaces', + 'listObjects' + ] + ); + mockNow = jasmine.createSpy("now"); + + mockPersistenceService.readObject + .andCallFake(function (space, id) { return mockPromise({ space: space, id: id, - modified: (modTimes[space] || {})[id] + modified: (modTimes[space] || {})[id], + persisted: 0 }); - } - }; + }); provider = new PersistedModelProvider( mockPersistenceService, mockQ, + mockNow, SPACE, spaces ); @@ -81,12 +96,13 @@ define( }); expect(models).toEqual({ - a: { space: SPACE, id: "a" }, - x: { space: SPACE, id: "x" }, - zz: { space: SPACE, id: "zz" } + a: { space: SPACE, id: "a", persisted: 0 }, + x: { space: SPACE, id: "x", persisted: 0 }, + zz: { space: SPACE, id: "zz", persisted: 0 } }); }); + it("reads object models from multiple spaces", function () { var models; @@ -99,9 +115,36 @@ define( }); expect(models).toEqual({ - a: { space: SPACE, id: "a" }, - x: { space: 'space1', id: "x", modified: 12321 }, - zz: { space: SPACE, id: "zz" } + a: { space: SPACE, id: "a", persisted: 0 }, + x: { space: 'space1', id: "x", modified: 12321, persisted: 0 }, + zz: { space: SPACE, id: "zz", persisted: 0 } + }); + }); + + + it("ensures that persisted timestamps are present", function () { + var mockCallback = jasmine.createSpy("callback"), + testModels = { + a: { modified: 123, persisted: 1984, name: "A" }, + b: { persisted: 1977, name: "B" }, + c: { modified: 42, name: "C" }, + d: { name: "D" } + }; + + mockPersistenceService.readObject.andCallFake( + function (space, id) { + return mockPromise(testModels[id]); + } + ); + mockNow.andReturn(12321); + + provider.getModels(Object.keys(testModels)).then(mockCallback); + + expect(mockCallback).toHaveBeenCalledWith({ + a: { modified: 123, persisted: 1984, name: "A" }, + b: { persisted: 1977, name: "B" }, + c: { modified: 42, persisted: 42, name: "C" }, + d: { persisted: 12321, name: "D" } }); });