Merge remote-tracking branch 'github-open/open97' into open-master
This commit is contained in:
@@ -63,7 +63,12 @@
|
||||
"provides": "modelService",
|
||||
"type": "provider",
|
||||
"implementation": "models/PersistedModelProvider.js",
|
||||
"depends": [ "persistenceService", "$q", "PERSISTENCE_SPACE" ]
|
||||
"depends": [
|
||||
"persistenceService",
|
||||
"$q",
|
||||
"PERSISTENCE_SPACE",
|
||||
"ADDITIONAL_PERSISTENCE_SPACES"
|
||||
]
|
||||
},
|
||||
{
|
||||
"provides": "modelService",
|
||||
@@ -218,6 +223,17 @@
|
||||
"composition": []
|
||||
}
|
||||
}
|
||||
],
|
||||
"constants": [
|
||||
{
|
||||
"key": "PERSISTENCE_SPACE",
|
||||
"value": "mct"
|
||||
},
|
||||
{
|
||||
"key": "ADDITIONAL_PERSISTENCE_SPACES",
|
||||
"value": [],
|
||||
"description": "An array of additional persistence spaces to load models from."
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,66 @@ define(
|
||||
this.domainObject = domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a domain object to the composition of the field.
|
||||
* This mutates but does not persist the modified object.
|
||||
*
|
||||
* If no index is given, this is added to the end of the composition.
|
||||
*
|
||||
* @param {DomainObject|string} domainObject the domain object to add,
|
||||
* or simply its identifier
|
||||
* @param {number} [index] the index at which to add the object
|
||||
* @returns {Promise.<DomainObject>} a promise for the added object
|
||||
* in its new context
|
||||
*/
|
||||
CompositionCapability.prototype.add = function (domainObject, index) {
|
||||
var self = this,
|
||||
id = typeof domainObject === 'string' ?
|
||||
domainObject : domainObject.getId(),
|
||||
model = self.domainObject.getModel(),
|
||||
composition = model.composition,
|
||||
oldIndex = composition.indexOf(id);
|
||||
|
||||
// Find the object with the above id, used to contextualize
|
||||
function findObject(objects) {
|
||||
var i;
|
||||
for (i = 0; i < objects.length; i += 1) {
|
||||
if (objects[i].getId() === id) {
|
||||
return objects[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function contextualize(mutationResult) {
|
||||
return mutationResult && self.invoke().then(findObject);
|
||||
}
|
||||
|
||||
function addIdToModel(model) {
|
||||
// Pick a specific index if needed.
|
||||
index = isNaN(index) ? composition.length : index;
|
||||
// Also, don't put past the end of the array
|
||||
index = Math.min(composition.length, index);
|
||||
|
||||
// Remove the existing instance of the id
|
||||
if (oldIndex !== -1) {
|
||||
model.composition.splice(oldIndex, 1);
|
||||
}
|
||||
|
||||
// ...and add it back at the appropriate index.
|
||||
model.composition.splice(index, 0, id);
|
||||
}
|
||||
|
||||
// If no index has been specified already and the id is already
|
||||
// present, nothing to do. If the id is already at that index,
|
||||
// also nothing to do, so cancel mutation.
|
||||
if ((isNaN(index) && oldIndex !== -1) || (index === oldIndex)) {
|
||||
return contextualize(true);
|
||||
}
|
||||
|
||||
return this.domainObject.useCapability('mutation', addIdToModel)
|
||||
.then(contextualize);
|
||||
};
|
||||
|
||||
/**
|
||||
* Request the composition of this object.
|
||||
* @returns {Promise.<DomainObject[]>} a list of all domain
|
||||
|
||||
@@ -39,23 +39,37 @@ define(
|
||||
* @param {PersistenceService} persistenceService the service in which
|
||||
* domain object models are persisted.
|
||||
* @param $q Angular's $q service, for working with promises
|
||||
* @param {string} SPACE the name of the persistence space from which
|
||||
* models should be retrieved.
|
||||
* @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) {
|
||||
function PersistedModelProvider(persistenceService, $q, space, spaces) {
|
||||
this.persistenceService = persistenceService;
|
||||
this.$q = $q;
|
||||
this.space = space;
|
||||
this.spaces = [space].concat(spaces || []);
|
||||
}
|
||||
|
||||
// Take the most recently modified model, for cases where
|
||||
// multiple persistence spaces return models.
|
||||
function takeMostRecent(modelA, modelB) {
|
||||
return (!modelB || modelB.modified === undefined) ? modelA :
|
||||
(!modelA || modelA.modified === undefined) ? modelB :
|
||||
modelB.modified > modelA.modified ? modelB :
|
||||
modelA;
|
||||
}
|
||||
|
||||
PersistedModelProvider.prototype.getModels = function (ids) {
|
||||
var persistenceService = this.persistenceService,
|
||||
$q = this.$q,
|
||||
space = this.space;
|
||||
spaces = this.spaces;
|
||||
|
||||
// Load a single object model from persistence
|
||||
// Load a single object model from any persistence spaces
|
||||
function loadModel(id) {
|
||||
return persistenceService.readObject(space, id);
|
||||
return $q.all(spaces.map(function (space) {
|
||||
return persistenceService.readObject(space, id);
|
||||
})).then(function (models) {
|
||||
return models.reduce(takeMostRecent);
|
||||
});
|
||||
}
|
||||
|
||||
// Package the result as id->model
|
||||
|
||||
@@ -51,7 +51,7 @@ define(
|
||||
// so support that, but don't introduce complication of
|
||||
// native promises.
|
||||
function mockPromise(value) {
|
||||
return {
|
||||
return (value || {}).then ? value : {
|
||||
then: function (callback) {
|
||||
return mockPromise(callback(value));
|
||||
}
|
||||
@@ -123,6 +123,98 @@ define(
|
||||
|
||||
});
|
||||
|
||||
it("allows domain objects to be added", function () {
|
||||
var result,
|
||||
testModel = { composition: [] },
|
||||
mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS);
|
||||
|
||||
mockDomainObject.getModel.andReturn(testModel);
|
||||
mockObjectService.getObjects.andReturn(mockPromise({a: mockChild}));
|
||||
mockChild.getCapability.andReturn(undefined);
|
||||
mockChild.getId.andReturn('a');
|
||||
|
||||
mockDomainObject.useCapability.andCallFake(function (key, mutator) {
|
||||
if (key === 'mutation') {
|
||||
mutator(testModel);
|
||||
return mockPromise(true);
|
||||
}
|
||||
});
|
||||
|
||||
composition.add(mockChild).then(function (domainObject) {
|
||||
result = domainObject;
|
||||
});
|
||||
|
||||
expect(testModel.composition).toEqual(['a']);
|
||||
|
||||
// Should have returned the added object in its new context
|
||||
expect(result.getId()).toEqual('a');
|
||||
expect(result.getCapability('context')).toBeDefined();
|
||||
expect(result.getCapability('context').getParent())
|
||||
.toEqual(mockDomainObject);
|
||||
});
|
||||
|
||||
it("does not re-add IDs which are already present", function () {
|
||||
var result,
|
||||
testModel = { composition: [ 'a' ] },
|
||||
mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS);
|
||||
|
||||
mockDomainObject.getModel.andReturn(testModel);
|
||||
mockObjectService.getObjects.andReturn(mockPromise({a: mockChild}));
|
||||
mockChild.getCapability.andReturn(undefined);
|
||||
mockChild.getId.andReturn('a');
|
||||
|
||||
mockDomainObject.useCapability.andCallFake(function (key, mutator) {
|
||||
if (key === 'mutation') {
|
||||
mutator(testModel);
|
||||
return mockPromise(true);
|
||||
}
|
||||
});
|
||||
|
||||
composition.add(mockChild).then(function (domainObject) {
|
||||
result = domainObject;
|
||||
});
|
||||
|
||||
// Still just 'a'
|
||||
expect(testModel.composition).toEqual(['a']);
|
||||
|
||||
// Should have returned the added object in its new context
|
||||
expect(result.getId()).toEqual('a');
|
||||
expect(result.getCapability('context')).toBeDefined();
|
||||
expect(result.getCapability('context').getParent())
|
||||
.toEqual(mockDomainObject);
|
||||
});
|
||||
|
||||
it("can add objects at a specified index", function () {
|
||||
var result,
|
||||
testModel = { composition: [ 'a', 'b', 'c' ] },
|
||||
mockChild = jasmine.createSpyObj("child", DOMAIN_OBJECT_METHODS);
|
||||
|
||||
mockDomainObject.getModel.andReturn(testModel);
|
||||
mockObjectService.getObjects.andReturn(mockPromise({a: mockChild}));
|
||||
mockChild.getCapability.andReturn(undefined);
|
||||
mockChild.getId.andReturn('a');
|
||||
|
||||
mockDomainObject.useCapability.andCallFake(function (key, mutator) {
|
||||
if (key === 'mutation') {
|
||||
mutator(testModel);
|
||||
return mockPromise(true);
|
||||
}
|
||||
});
|
||||
|
||||
composition.add(mockChild, 1).then(function (domainObject) {
|
||||
result = domainObject;
|
||||
});
|
||||
|
||||
// Still just 'a'
|
||||
expect(testModel.composition).toEqual(['b', 'a', 'c']);
|
||||
|
||||
// Should have returned the added object in its new context
|
||||
expect(result.getId()).toEqual('a');
|
||||
expect(result.getCapability('context')).toBeDefined();
|
||||
expect(result.getCapability('context').getParent())
|
||||
.toEqual(mockDomainObject);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -32,7 +32,9 @@ define(
|
||||
describe("The persisted model provider", function () {
|
||||
var mockQ,
|
||||
mockPersistenceService,
|
||||
SPACE = "some space",
|
||||
SPACE = "space0",
|
||||
spaces = [ "space1" ],
|
||||
modTimes,
|
||||
provider;
|
||||
|
||||
function mockPromise(value) {
|
||||
@@ -51,12 +53,14 @@ define(
|
||||
}
|
||||
|
||||
beforeEach(function () {
|
||||
modTimes = {};
|
||||
mockQ = { when: mockPromise, all: mockAll };
|
||||
mockPersistenceService = {
|
||||
readObject: function (space, id) {
|
||||
return mockPromise({
|
||||
space: space,
|
||||
id: id
|
||||
id: id,
|
||||
modified: (modTimes[space] || {})[id]
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -64,7 +68,8 @@ define(
|
||||
provider = new PersistedModelProvider(
|
||||
mockPersistenceService,
|
||||
mockQ,
|
||||
SPACE
|
||||
SPACE,
|
||||
spaces
|
||||
);
|
||||
});
|
||||
|
||||
@@ -82,6 +87,24 @@ define(
|
||||
});
|
||||
});
|
||||
|
||||
it("reads object models from multiple spaces", function () {
|
||||
var models;
|
||||
|
||||
modTimes.space1 = {
|
||||
'x': 12321
|
||||
};
|
||||
|
||||
provider.getModels(["a", "x", "zz"]).then(function (m) {
|
||||
models = m;
|
||||
});
|
||||
|
||||
expect(models).toEqual({
|
||||
a: { space: SPACE, id: "a" },
|
||||
x: { space: 'space1', id: "x", modified: 12321 },
|
||||
zz: { space: SPACE, id: "zz" }
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
);
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user