(function(root, factory) {
if (typeof define === 'function' && define.amd) {
define(['underscore', 'backbone'], factory);
} else if (typeof exports === 'object') {
module.exports = factory(require('underscore'), require('backbone'));
} else {
root.Torso = root.Torso || {};
root.Torso.Mixins = root.Torso.Mixins || {};
root.Torso.Mixins.cache = factory(root._, root.Backbone);
}
}(this, function(_, Backbone) {
var $ = Backbone.$;
/**
* Custom additions to the Backbone Collection object.
* - safe disposal methods for memory + event management
* - special functional overrides to support ID registration for different views
*
* @mixin cacheMixin
*
* @author ariel.wexler@vecna.com, kent.willis@vecna.com
*
* @see <a href="../annotated/modules/mixins/cacheMixin.html">cacheMixin Annotated Source</a>
*/
var mixin = function(base) {
var cacheMixin, createRequesterCollectionClass;
/**
* Returns a new class of collection that inherits from the parent but not the cacheMixin
* and adds a requesterMixin that connects this cache to it's parent
*
* @class PrivateCollection
* @extends Collection
* @param {external:Backbone-Collection} parent the parent of the private collection
* @param {string} guid the unique code of the owner of this private collection
*/
createRequesterCollectionClass = function(parent, guid) {
return parent.constructor.extend((function(parentClass, parentInstance, ownerKey) {
/**
* A mixin that overrides base collection methods meant for cache's and tailors them
* to a requester.
* @alias PrivateCollection.prototype
*/
var requesterMixin = {
/**
* @returns {Array} array of ids that this collection is tracking
*/
getTrackedIds: function() {
return this.trackedIds;
},
/**
* Will force the cache to fetch just the registered ids of this collection
* @param [options] - argument options
* @param {Array} [options.idsToFetch=collectionTrackedIds] - A list of request Ids, will default to current tracked ids
* @param {Object} [options.setOptions] - if a set is made, then the setOptions will be passed into the set method
* @returns {Promise} promise that will resolve when the fetch is complete
*/
fetch: function(options) {
options = options || {};
options.idsToFetch = options.idsToFetch || this.trackedIds;
options.setOptions = options.setOptions || {remove: false};
return this.__loadWrapper(function() {
if (options.idsToFetch && options.idsToFetch.length) {
return parentInstance.fetchByIds(options);
} else {
return $.Deferred().resolve().promise();
}
});
},
/**
* Will force the cache to fetch a subset of this collection's tracked ids
* @param {Array} ids array of model ids
* @param {Object} [options] if given, will pass the options argument to this.fetch. Note, will not affect options.idsToFetch
* @returns {Promise} promise that will resolve when the fetch is complete
*/
fetchByIds: function(ids, options) {
options = options || {};
options.idsToFetch = _.intersection(ids, this.getTrackedIds());
return this.fetch(options);
},
/**
* Pass a list of ids to begin tracking. This will reset any previous list of ids being tracked.
* Overrides the Id registration system to route via the parent collection
* @param ids The list of ids that this collection wants to track
*/
trackIds: function(ids) {
this.remove(_.difference(this.trackedIds, ids));
parentInstance.registerIds(ids, ownerKey);
this.trackedIds = ids;
},
/**
* Adds a new model to the requester collection and tracks the model.id
* @param {external:Backbone-Model} model the model to be added
*/
addModelAndTrack: function(model) {
this.add(model);
parentInstance.add(model);
this.trackNewId(model.id);
},
/**
* Tracks a new id
* @param {(string|Number)} id the id attribute of the model
*/
trackNewId: function(id) {
this.trackIds(this.getTrackedIds().concat(id));
},
/**
* Will begin tracking the new ids and then ask the cache to fetch them
* This will reset any previous list of ids being tracked.
* @returns the promise of the fetch by ids
*/
trackAndFetch: function(newIds) {
this.trackIds(newIds);
return this.fetch();
},
/**
* Will force the cache to fetch any of this collection's tracked models that are not in the cache
* while not fetching models that are already in the cache. Useful when you want the effeciency of
* pulling models from the cache and don't need all the models to be up-to-date.
*
* If the ids being fetched are already being fetched by the cache, then they will not be re-fetched.
*
* The resulting promise is resolved when ALL items in the process of being fetched have completed.
* The promise will resolve to a unified data property that is a combination of the completion of all of the fetches.
*
* @param {Object} [options] if given, will pass the options argument to this.fetch. Note, will not affect options.idsToFetch
* @returns {Promise} promise that will resolve when the fetch is complete with all of the data that was fetched from the server.
* Will only resolve once all ids have attempted to be fetched from the server.
*/
pull: function(options) {
options = options || {};