control-freak-ide/Code/client/build/dgrid/dstore/Cache.js.consoleStripped.js
plastic-hub-dev-node-saturn 538369cff7 latest
2021-05-12 18:35:18 +02:00

198 lines
6.6 KiB
JavaScript

define("dstore/Cache", [
'dojo/_base/array',
'dojo/when',
'dojo/_base/declare',
'dojo/_base/lang',
'./Store',
'./Memory',
'./QueryResults'
], function (arrayUtil, when, declare, lang, Store, Memory, QueryResults) {
// module:
// dstore/Cache
function cachingQuery(type) {
// ensure querying creates a parallel caching store query
return function () {
var subCollection = this.inherited(arguments);
var cachingCollection = this.cachingCollection || this.cachingStore;
subCollection.cachingCollection = cachingCollection[type].apply(cachingCollection, arguments);
subCollection.isValidFetchCache = this.canCacheQuery === true || this.canCacheQuery(type, arguments);
return subCollection;
};
}
function init (store) {
if (!store.cachingStore) {
store.cachingStore = new Memory();
}
store.cachingStore.Model = store.Model;
store.cachingStore.idProperty = store.idProperty;
}
var CachePrototype = {
cachingStore: null,
constructor: function () {
init(this);
},
canCacheQuery: function (method, args) {
// summary:
// Indicates if a queried (filter, sort, etc.) collection should using caching
return false;
},
isAvailableInCache: function () {
// summary:
// Indicates if the collection's cachingCollection is a viable source
// for a fetch
return (this.isValidFetchCache && (this.allLoaded || this.fetchRequest)) ||
this._parent && this._parent.isAvailableInCache();
},
fetch: function () {
return this._fetch(arguments);
},
fetchRange: function () {
return this._fetch(arguments, true);
},
_fetch: function (args, isRange) {
// if the data is available in the cache (via any parent), we use fetch from the caching store
var cachingStore = this.cachingStore;
var cachingCollection = this.cachingCollection || cachingStore;
var store = this;
var available = this.isAvailableInCache();
if (available) {
return new QueryResults(when(available, function () {
// need to double check to make sure the flag hasn't been cleared
// and we really have all data loaded
if (store.isAvailableInCache()) {
return isRange ?
cachingCollection.fetchRange(args[0]) :
cachingCollection.fetch();
} else {
return store.inherited(args);
}
}));
}
var results = this.fetchRequest = this.inherited(args);
when(results, function (results) {
var allLoaded = !isRange;
store.fetchRequest = null;
// store each object before calling the callback
arrayUtil.forEach(results, function (object) {
// store each object before calling the callback
if (!store.isLoaded || store.isLoaded(object)) {
cachingStore.put(object);
} else {
// if anything is not loaded, we can't consider them all loaded
allLoaded = false;
}
});
if (allLoaded) {
store.allLoaded = true;
}
return results;
});
return results;
},
// TODO: for now, all forEach() calls delegate to fetch(), but that may be different
// with IndexedDB, so we may need to intercept forEach as well (and hopefully not
// double load elements.
// isValidFetchCache: boolean
// This flag indicates if a previous fetch can be used as a cache for subsequent
// fetches (in this collection, or downstream).
isValidFetchCache: false,
get: function (id, directives) {
var cachingStore = this.cachingStore;
var masterGet = this.getInherited(arguments);
var masterStore = this;
// if everything is being loaded, we always wait for that to finish
return when(this.fetchRequest, function () {
return when(cachingStore.get(id), function (result) {
if (result !== undefined) {
return result;
} else if (masterGet) {
return when(masterGet.call(masterStore, id, directives), function (result) {
if (result) {
cachingStore.put(result, {id: id});
}
return result;
});
}
});
});
},
add: function (object, directives) {
var cachingStore = this.cachingStore;
return when(this.inherited(arguments), function (result) {
// now put result in cache (note we don't do add, because add may have
// called put() and already added it)
var cachedPutResult =
cachingStore.put(result && typeof result === 'object' ? result : object, directives);
// the result from the add should be dictated by the master store and be unaffected by the cachingStore,
// unless the master store doesn't implement add
return result || cachedPutResult;
});
},
put: function (object, directives) {
// first remove from the cache, so it is empty until we get a response from the master store
var cachingStore = this.cachingStore;
cachingStore.remove((directives && directives.id) || this.getIdentity(object));
return when(this.inherited(arguments), function (result) {
// now put result in cache
var cachedPutResult =
cachingStore.put(result && typeof result === 'object' ? result : object, directives);
// the result from the put should be dictated by the master store and be unaffected by the cachingStore,
// unless the master store doesn't implement put
return result || cachedPutResult;
});
},
remove: function (id, directives) {
var cachingStore = this.cachingStore;
return when(this.inherited(arguments), function (result) {
return when(cachingStore.remove(id, directives), function () {
return result;
});
});
},
evict: function (id) {
// summary:
// Evicts an object from the cache
// any eviction means that we don't have everything loaded anymore
this.allLoaded = false;
return this.cachingStore.remove(id);
},
invalidate: function () {
// summary:
// Invalidates this collection's cache as being a valid source of
// future fetches
this.allLoaded = false;
},
_createSubCollection: function () {
var subCollection = this.inherited(arguments);
subCollection._parent = this;
return subCollection;
},
sort: cachingQuery('sort'),
filter: cachingQuery('filter'),
select: cachingQuery('select'),
_getQuerierFactory: function (type) {
var cachingStore = this.cachingStore;
return this.inherited(arguments) || lang.hitch(cachingStore, cachingStore._getQuerierFactory(type));
}
};
var Cache = declare(null, CachePrototype);
Cache.create = function (target, properties) {
// create a delegate of an existing store with caching
// functionality mixed in
target = declare.safeMixin(lang.delegate(target), CachePrototype);
declare.safeMixin(target, properties);
// we need to initialize it since the constructor won't have been called
init(target);
return target;
};
return Cache;
});