[Code Style] Use prototypes in platform

WTD-1482
This commit is contained in:
Victor Woeltjen
2015-08-11 12:54:50 -07:00
parent f377c7cb71
commit b7765ff388
35 changed files with 1331 additions and 1379 deletions

View File

@ -32,10 +32,30 @@ define(
* object are not provided.
* @memberof platform/core
* @constructor
* @param {ModelService} modelService this service to decorate
* @implements {ModelService}
*/
function CachingModelDecorator(modelService) {
var cache = {},
cached = {};
this.cache = {};
this.cached = {};
this.modelService = modelService;
}
// Fast-resolving promise
function fastPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return fastPromise(callback(value));
}
};
}
CachingModelDecorator.prototype.getModels = function (ids) {
var cache = this.cache,
cached = this.cached,
neededIds = ids.filter(function notCached(id) {
return !cached[id];
});
// Update the cached instance of a model to a new value.
// We update in-place to ensure there is only ever one instance
@ -68,30 +88,12 @@ define(
return oldModel;
}
// Fast-resolving promise
function fastPromise(value) {
return (value || {}).then ? value : {
then: function (callback) {
return fastPromise(callback(value));
}
};
}
// Store this model in the cache
function cacheModel(id, model) {
cache[id] = cached[id] ? updateModel(id, model) : model;
cached[id] = true;
}
// Check if an id is not in cache, for lookup filtering
function notCached(id) {
return !cached[id];
}
// Store the provided models in our cache
function cacheAll(models) {
Object.keys(models).forEach(function (id) {
cacheModel(id, models[id]);
cache[id] = cached[id] ?
updateModel(id, models[id]) : models[id];
cached[id] = true;
});
}
@ -100,38 +102,16 @@ define(
return cache;
}
return {
/**
* Get models for these specified string identifiers.
* These will be given as an object containing keys
* and values, where keys are object identifiers and
* values are models.
* This result may contain either a subset or a
* superset of the total objects.
*
* @param {Array<string>} ids the string identifiers for
* models of interest.
* @returns {Promise<object>} a promise for an object
* containing key-value pairs, where keys are
* ids and values are models
* @method
* @memberof platform/core.CachingModelDecorator#
*/
getModels: function (ids) {
var neededIds = ids.filter(notCached);
// Look up if we have unknown IDs
if (neededIds.length > 0) {
return this.modelService.getModels(neededIds)
.then(cacheAll)
.then(giveCache);
}
// Look up if we have unknown IDs
if (neededIds.length > 0) {
return modelService.getModels(neededIds)
.then(cacheAll)
.then(giveCache);
}
// Otherwise, just expose the cache directly
return fastPromise(cache);
}
};
}
// Otherwise, just expose the cache directly
return fastPromise(cache);
};
return CachingModelDecorator;
}

View File

@ -29,33 +29,34 @@ define(
/**
* Adds placeholder domain object models for any models which
* fail to load from the underlying model service.
* @implements {ModelService}
* @constructor
* @memberof platform/core
* @param {ModelService} modelService this service to decorate
* @implements {ModelService}
*/
function MissingModelDecorator(modelService) {
function missingModel(id) {
return {
type: "unknown",
name: "Missing: " + id
};
}
this.modelService = modelService;
}
function missingModel(id) {
return {
getModels: function (ids) {
function addMissingModels(models) {
var result = {};
ids.forEach(function (id) {
result[id] = models[id] || missingModel(id);
});
return result;
}
return modelService.getModels(ids).then(addMissingModels);
}
type: "unknown",
name: "Missing: " + id
};
}
MissingModelDecorator.prototype.getModels = function (ids) {
function addMissingModels(models) {
var result = {};
ids.forEach(function (id) {
result[id] = models[id] || missingModel(id);
});
return result;
}
return this.modelService.getModels(ids).then(addMissingModels);
};
return MissingModelDecorator;
}
);

View File

@ -29,67 +29,71 @@ define(
function () {
"use strict";
/**
* Allow domain object models to be looked up by their identifiers.
*
* @interface ModelService
*/
/**
* Get domain object models.
*
* This may provide either a superset or a subset of the models
* requested. Absence of a model means it does not exist within
* this service instance.
*
* @method ModelService#getModels
* @param {string[]} ids identifiers for models desired.
* @returns {Promise.<Object>} a promise for an object mapping
* string identifiers to domain object models.
*/
/**
* Allows multiple services which provide models for domain objects
* to be treated as one.
*
* @memberof platform/core
* @constructor
* @param {ModelProvider[]} providers the model providers to be
* @implements {ModelService}
* @param $q Angular's $q, for promises
* @param {ModelService[]} providers the model providers to be
* aggregated
*/
function ModelAggregator($q, providers) {
// Pick a domain object model to use, favoring the one
// with the most recent timestamp
function pick(a, b) {
var aModified = (a || {}).modified || Number.NEGATIVE_INFINITY,
bModified = (b || {}).modified || Number.NEGATIVE_INFINITY;
return (aModified > bModified) ? a : (b || a);
}
// Merge results from multiple providers into one
// large result object.
function mergeModels(provided, ids) {
var result = {};
ids.forEach(function (id) {
provided.forEach(function (models) {
if (models[id]) {
result[id] = pick(result[id], models[id]);
}
});
});
return result;
}
return {
/**
* Get models with the specified identifiers.
*
* This will invoke the `getModels()` method of all providers
* given at constructor-time, and aggregate the result into
* one object.
*
* Note that the returned object may contain a subset or a
* superset of the models requested.
*
* @param {string[]} ids an array of domain object identifiers
* @returns {Promise.<object>} a promise for an object
* containing key-value pairs,
* where keys are object identifiers and values
* are object models.
* @memberof platform/core.ModelAggregator#
*/
getModels: function (ids) {
return $q.all(providers.map(function (provider) {
return provider.getModels(ids);
})).then(function (provided) {
return mergeModels(provided, ids);
});
}
};
this.providers = providers;
this.$q = $q;
}
// Pick a domain object model to use, favoring the one
// with the most recent timestamp
function pick(a, b) {
var aModified = (a || {}).modified || Number.NEGATIVE_INFINITY,
bModified = (b || {}).modified || Number.NEGATIVE_INFINITY;
return (aModified > bModified) ? a : (b || a);
}
// Merge results from multiple providers into one
// large result object.
function mergeModels(provided, ids) {
var result = {};
ids.forEach(function (id) {
provided.forEach(function (models) {
if (models[id]) {
result[id] = pick(result[id], models[id]);
}
});
});
return result;
}
ModelAggregator.prototype.getModels = function (ids) {
return this.$q.all(this.providers.map(function (provider) {
return provider.getModels(ids);
})).then(function (provided) {
return mergeModels(provided, ids);
});
};
return ModelAggregator;
}
);

View File

@ -35,61 +35,47 @@ define(
*
* @memberof platform/core
* @constructor
* @implements {ModelService}
* @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.
*/
function PersistedModelProvider(persistenceService, $q, SPACE) {
// Load a single object model from persistence
function loadModel(id) {
return persistenceService.readObject(SPACE, id);
}
// Promise all persisted models (in id->model form)
function promiseModels(ids) {
// Package the result as id->model
function packageResult(models) {
var result = {};
ids.forEach(function (id, index) {
result[id] = models[index];
});
return result;
}
// Filter out "namespaced" identifiers; these are
// not expected to be found in database. See WTD-659.
ids = ids.filter(function (id) {
return id.indexOf(":") === -1;
});
// Give a promise for all persistence lookups...
return $q.all(ids.map(loadModel)).then(packageResult);
}
return {
/**
* Get models with the specified identifiers.
*
* This will invoke the underlying persistence service to
* retrieve object models which match the provided
* identifiers.
*
* Note that the returned object may contain a subset or a
* superset of the models requested.
*
* @param {string[]} ids an array of domain object identifiers
* @returns {Promise.<object>} a promise for an object
* containing key-value pairs,
* where keys are object identifiers and values
* are object models.
* @memberof platform/core.PersistedModelProvider#
*/
getModels: promiseModels
};
function PersistedModelProvider(persistenceService, $q, space) {
this.persistenceService = persistenceService;
this.$q = $q;
this.space = space;
}
PersistedModelProvider.prototype.getModels = function (ids) {
var persistenceService = this.persistenceService,
$q = this.$q,
space = this.space;
// Load a single object model from persistence
function loadModel(id) {
return persistenceService.readObject(space, id);
}
// Package the result as id->model
function packageResult(models) {
var result = {};
ids.forEach(function (id, index) {
result[id] = models[index];
});
return result;
}
// Filter out "namespaced" identifiers; these are
// not expected to be found in database. See WTD-659.
ids = ids.filter(function (id) {
return id.indexOf(":") === -1;
});
// Give a promise for all persistence lookups...
return $q.all(ids.map(loadModel)).then(packageResult);
};
return PersistedModelProvider;
}

View File

@ -41,42 +41,31 @@ define(
*
* @memberof platform/core
* @constructor
* @implements {ModelService}
* @param {Array} roots all `roots[]` extensions
* @param $q Angular's $q, for promises
* @param $log Anuglar's $log, for logging
*/
function RootModelProvider(roots, $q, $log) {
// Pull out identifiers to used as ROOT's
var ids = roots.map(function (root) { return root.id; }),
baseProvider = new StaticModelProvider(roots, $q, $log);
var ids = roots.map(function (root) { return root.id; });
function addRoot(models) {
models.ROOT = {
name: "The root object",
type: "root",
composition: ids
};
return models;
}
return {
/**
* Get models with the specified identifiers.
*
* Note that the returned object may contain a subset or a
* superset of the models requested.
*
* @param {string[]} ids an array of domain object identifiers
* @returns {Promise.<object>} a promise for an object
* containing key-value pairs,
* where keys are object identifiers and values
* are object models.
* @memberof platform/core.RootModelProvider#
*/
getModels: function (ids) {
return baseProvider.getModels(ids).then(addRoot);
}
this.baseProvider = new StaticModelProvider(roots, $q, $log);
this.rootModel = {
name: "The root object",
type: "root",
composition: ids
};
}
RootModelProvider.prototype.getModels = function (ids) {
var rootModel = this.rootModel;
return this.baseProvider.getModels(ids).then(function (models) {
models.ROOT = rootModel;
return models;
});
};
return RootModelProvider;
}
);

View File

@ -41,7 +41,7 @@ define(
// Skip models which don't look right
if (typeof model !== 'object' ||
typeof model.id !== 'string' ||
typeof model.model !== 'object') {
typeof model.model !== 'object') {
$log.warn([
"Skipping malformed domain object model exposed by ",
((model || {}).bundle || {}).path
@ -54,34 +54,19 @@ define(
// Prepoulate maps with models to make subsequent lookup faster.
models.forEach(addModelToMap);
return {
/**
* Get models for these specified string identifiers.
* These will be given as an object containing keys
* and values, where keys are object identifiers and
* values are models.
* This result may contain either a subset or a
* superset of the total objects.
*
* @param {Array<string>} ids the string identifiers for
* models of interest.
* @returns {Promise<object>} a promise for an object
* containing key-value pairs, where keys are
* ids and values are models
* @method
* @memberof StaticModelProvider#
* @memberof platform/core.StaticModelProvider#
*/
getModels: function (ids) {
var result = {};
ids.forEach(function (id) {
result[id] = modelMap[id];
});
return $q.when(result);
}
};
this.modelMap = modelMap;
this.$q = $q;
}
StaticModelProvider.prototype.getModels = function (ids) {
var modelMap = this.modelMap,
result = {};
ids.forEach(function (id) {
result[id] = modelMap[id];
});
return this.$q.when(result);
};
return StaticModelProvider;
}
);