@data-client/normalizr
Version:
Normalizes and denormalizes JSON according to schema for Redux and Flux applications
126 lines (121 loc) • 15.4 kB
JavaScript
export default class GlobalCache {
constructor(getEntity, getCache, resultCache) {
this.dependencies = [];
this.cycleCache = new Map();
this.cycleIndex = -1;
this.localCache = new Map();
this._getEntity = getEntity;
this._getCache = getCache;
this._resultCache = resultCache;
}
getEntity(pk, schema, entity, computeValue) {
const key = schema.key;
const {
localCacheKey,
cycleCacheKey
} = this.getCacheKey(key);
if (!localCacheKey.get(pk)) {
const globalCache = this._getCache(pk, schema);
const [cacheValue, cachePath] = globalCache.get(entity, this._getEntity);
// TODO: what if this just returned the deps - then we don't need to store them
if (cachePath) {
localCacheKey.set(pk, cacheValue.value);
// TODO: can we store the cache values instead of tracking *all* their sources?
// this is only used for setting endpoints cache correctly. if we got this far we will def need to set as we would have already tried getting it
this.dependencies.push(...cacheValue.dependencies);
return cacheValue.value;
}
// if we don't find in denormalize cache then do full denormalize
else {
const trackingIndex = this.dependencies.length;
cycleCacheKey.set(pk, trackingIndex);
this.dependencies.push({
path: {
key,
pk
},
entity
});
/** NON-GLOBAL_CACHE CODE */
computeValue(localCacheKey);
/** /END NON-GLOBAL_CACHE CODE */
cycleCacheKey.delete(pk);
// if in cycle, use the start of the cycle to track all deps
// otherwise, we use our own trackingIndex
const localKey = this.dependencies.slice(this.cycleIndex === -1 ? trackingIndex : this.cycleIndex);
const cacheValue = {
dependencies: localKey,
value: localCacheKey.get(pk)
};
globalCache.set(localKey, cacheValue);
// start of cycle - reset cycle detection
if (this.cycleIndex === trackingIndex) {
this.cycleIndex = -1;
}
}
} else {
// cycle detected
if (cycleCacheKey.has(pk)) {
this.cycleIndex = cycleCacheKey.get(pk);
} else {
// with no cycle, globalCacheEntry will have already been set
this.dependencies.push({
path: {
key,
pk
},
entity
});
}
}
return localCacheKey.get(pk);
}
getCacheKey(key) {
if (!this.localCache.has(key)) {
this.localCache.set(key, new Map());
}
if (!this.cycleCache.has(key)) {
this.cycleCache.set(key, new Map());
}
const localCacheKey = this.localCache.get(key);
const cycleCacheKey = this.cycleCache.get(key);
return {
localCacheKey,
cycleCacheKey
};
}
/** Cache varies based on input (=== aka reference) */
getResults(input, cachable, computeValue) {
if (!cachable) {
return {
data: computeValue(),
paths: this.paths()
};
}
let [data, paths] = this._resultCache.get(input, this._getEntity);
if (paths === undefined) {
data = computeValue();
// we want to do this before we add our 'input' entry
paths = this.paths();
// for the first entry, `path` is ignored so empty members is fine
this.dependencies.unshift({
path: {
key: '',
pk: ''
},
entity: input
});
this._resultCache.set(this.dependencies, data);
} else {
paths.shift();
}
return {
data,
paths
};
}
paths() {
return this.dependencies.map(dep => dep.path);
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJHbG9iYWxDYWNoZSIsImNvbnN0cnVjdG9yIiwiZ2V0RW50aXR5IiwiZ2V0Q2FjaGUiLCJyZXN1bHRDYWNoZSIsImRlcGVuZGVuY2llcyIsImN5Y2xlQ2FjaGUiLCJNYXAiLCJjeWNsZUluZGV4IiwibG9jYWxDYWNoZSIsIl9nZXRFbnRpdHkiLCJfZ2V0Q2FjaGUiLCJfcmVzdWx0Q2FjaGUiLCJwayIsInNjaGVtYSIsImVudGl0eSIsImNvbXB1dGVWYWx1ZSIsImtleSIsImxvY2FsQ2FjaGVLZXkiLCJjeWNsZUNhY2hlS2V5IiwiZ2V0Q2FjaGVLZXkiLCJnZXQiLCJnbG9iYWxDYWNoZSIsImNhY2hlVmFsdWUiLCJjYWNoZVBhdGgiLCJzZXQiLCJ2YWx1ZSIsInB1c2giLCJ0cmFja2luZ0luZGV4IiwibGVuZ3RoIiwicGF0aCIsImRlbGV0ZSIsImxvY2FsS2V5Iiwic2xpY2UiLCJoYXMiLCJnZXRSZXN1bHRzIiwiaW5wdXQiLCJjYWNoYWJsZSIsImRhdGEiLCJwYXRocyIsInVuZGVmaW5lZCIsInVuc2hpZnQiLCJzaGlmdCIsIm1hcCIsImRlcCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tZW1vL2dsb2JhbENhY2hlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgR2V0RW50aXR5Q2FjaGUgfSBmcm9tICcuL2VudGl0aWVzQ2FjaGUuanMnO1xuaW1wb3J0IHsgRW5kcG9pbnRzQ2FjaGUgfSBmcm9tICcuL3R5cGVzLmpzJztcbmltcG9ydCBXZWFrRGVwZW5kZW5jeU1hcCwgeyB0eXBlIERlcCB9IGZyb20gJy4vV2Vha0RlcGVuZGVuY3lNYXAuanMnO1xuaW1wb3J0IHR5cGUgQ2FjaGUgZnJvbSAnLi4vZGVub3JtYWxpemUvY2FjaGUuanMnO1xuaW1wb3J0IHR5cGUgeyBJTlZBTElEIH0gZnJvbSAnLi4vZGVub3JtYWxpemUvc3ltYm9sLmpzJztcbmltcG9ydCB0eXBlIHsgRW50aXR5SW50ZXJmYWNlLCBFbnRpdHlQYXRoIH0gZnJvbSAnLi4vaW50ZXJmYWNlLmpzJztcbmltcG9ydCB0eXBlIHsgRGVub3JtR2V0RW50aXR5IH0gZnJvbSAnLi90eXBlcy5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEdsb2JhbENhY2hlIGltcGxlbWVudHMgQ2FjaGUge1xuICBwcml2YXRlIGRlcGVuZGVuY2llczogRGVwPEVudGl0eVBhdGg+W10gPSBbXTtcbiAgcHJpdmF0ZSBjeWNsZUNhY2hlOiBNYXA8c3RyaW5nLCBNYXA8c3RyaW5nLCBudW1iZXI+PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBjeWNsZUluZGV4ID0gLTE7XG4gIHByaXZhdGUgbG9jYWxDYWNoZTogTWFwPHN0cmluZywgTWFwPHN0cmluZywgYW55Pj4gPSBuZXcgTWFwKCk7XG5cbiAgZGVjbGFyZSBwcml2YXRlIF9nZXRDYWNoZTogR2V0RW50aXR5Q2FjaGU7XG5cbiAgZGVjbGFyZSBwcml2YXRlIF9nZXRFbnRpdHk6IERlbm9ybUdldEVudGl0eTtcbiAgZGVjbGFyZSBwcml2YXRlIF9yZXN1bHRDYWNoZTogRW5kcG9pbnRzQ2FjaGU7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgZ2V0RW50aXR5OiBEZW5vcm1HZXRFbnRpdHksXG4gICAgZ2V0Q2FjaGU6IEdldEVudGl0eUNhY2hlLFxuICAgIHJlc3VsdENhY2hlOiBFbmRwb2ludHNDYWNoZSxcbiAgKSB7XG4gICAgdGhpcy5fZ2V0RW50aXR5ID0gZ2V0RW50aXR5O1xuICAgIHRoaXMuX2dldENhY2hlID0gZ2V0Q2FjaGU7XG4gICAgdGhpcy5fcmVzdWx0Q2FjaGUgPSByZXN1bHRDYWNoZTtcbiAgfVxuXG4gIGdldEVudGl0eShcbiAgICBwazogc3RyaW5nLFxuICAgIHNjaGVtYTogRW50aXR5SW50ZXJmYWNlLFxuICAgIGVudGl0eTogYW55LFxuICAgIGNvbXB1dGVWYWx1ZTogKGxvY2FsQ2FjaGVLZXk6IE1hcDxzdHJpbmcsIGFueT4pID0+IHZvaWQsXG4gICk6IG9iamVjdCB8IHVuZGVmaW5lZCB8IHR5cGVvZiBJTlZBTElEIHtcbiAgICBjb25zdCBrZXkgPSBzY2hlbWEua2V5O1xuICAgIGNvbnN0IHsgbG9jYWxDYWNoZUtleSwgY3ljbGVDYWNoZUtleSB9ID0gdGhpcy5nZXRDYWNoZUtleShrZXkpO1xuXG4gICAgaWYgKCFsb2NhbENhY2hlS2V5LmdldChwaykpIHtcbiAgICAgIGNvbnN0IGdsb2JhbENhY2hlOiBXZWFrRGVwZW5kZW5jeU1hcDxcbiAgICAgICAgRW50aXR5UGF0aCxcbiAgICAgICAgb2JqZWN0LFxuICAgICAgICBFbnRpdHlDYWNoZVZhbHVlXG4gICAgICA+ID0gdGhpcy5fZ2V0Q2FjaGUocGssIHNjaGVtYSk7XG4gICAgICBjb25zdCBbY2FjaGVWYWx1ZSwgY2FjaGVQYXRoXSA9IGdsb2JhbENhY2hlLmdldChlbnRpdHksIHRoaXMuX2dldEVudGl0eSk7XG4gICAgICAvLyBUT0RPOiB3aGF0IGlmIHRoaXMganVzdCByZXR1cm5lZCB0aGUgZGVwcyAtIHRoZW4gd2UgZG9uJ3QgbmVlZCB0byBzdG9yZSB0aGVtXG5cbiAgICAgIGlmIChjYWNoZVBhdGgpIHtcbiAgICAgICAgbG9jYWxDYWNoZUtleS5zZXQocGssIGNhY2hlVmFsdWUudmFsdWUpO1xuICAgICAgICAvLyBUT0RPOiBjYW4gd2Ugc3RvcmUgdGhlIGNhY2hlIHZhbHVlcyBpbnN0ZWFkIG9mIHRyYWNraW5nICphbGwqIHRoZWlyIHNvdXJjZXM/XG4gICAgICAgIC8vIHRoaXMgaXMgb25seSB1c2VkIGZvciBzZXR0aW5nIGVuZHBvaW50cyBjYWNoZSBjb3JyZWN0bHkuIGlmIHdlIGdvdCB0aGlzIGZhciB3ZSB3aWxsIGRlZiBuZWVkIHRvIHNldCBhcyB3ZSB3b3VsZCBoYXZlIGFscmVhZHkgdHJpZWQgZ2V0dGluZyBpdFxuICAgICAgICB0aGlzLmRlcGVuZGVuY2llcy5wdXNoKC4uLmNhY2hlVmFsdWUuZGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuIGNhY2hlVmFsdWUudmFsdWU7XG4gICAgICB9XG4gICAgICAvLyBpZiB3ZSBkb24ndCBmaW5kIGluIGRlbm9ybWFsaXplIGNhY2hlIHRoZW4gZG8gZnVsbCBkZW5vcm1hbGl6ZVxuICAgICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IHRyYWNraW5nSW5kZXggPSB0aGlzLmRlcGVuZGVuY2llcy5sZW5ndGg7XG4gICAgICAgIGN5Y2xlQ2FjaGVLZXkuc2V0KHBrLCB0cmFja2luZ0luZGV4KTtcbiAgICAgICAgdGhpcy5kZXBlbmRlbmNpZXMucHVzaCh7IHBhdGg6IHsga2V5LCBwayB9LCBlbnRpdHkgfSk7XG5cbiAgICAgICAgLyoqIE5PTi1HTE9CQUxfQ0FDSEUgQ09ERSAqL1xuICAgICAgICBjb21wdXRlVmFsdWUobG9jYWxDYWNoZUtleSk7XG4gICAgICAgIC8qKiAvRU5EIE5PTi1HTE9CQUxfQ0FDSEUgQ09ERSAqL1xuXG4gICAgICAgIGN5Y2xlQ2FjaGVLZXkuZGVsZXRlKHBrKTtcbiAgICAgICAgLy8gaWYgaW4gY3ljbGUsIHVzZSB0aGUgc3RhcnQgb2YgdGhlIGN5Y2xlIHRvIHRyYWNrIGFsbCBkZXBzXG4gICAgICAgIC8vIG90aGVyd2lzZSwgd2UgdXNlIG91ciBvd24gdHJhY2tpbmdJbmRleFxuICAgICAgICBjb25zdCBsb2NhbEtleSA9IHRoaXMuZGVwZW5kZW5jaWVzLnNsaWNlKFxuICAgICAgICAgIHRoaXMuY3ljbGVJbmRleCA9PT0gLTEgPyB0cmFja2luZ0luZGV4IDogdGhpcy5jeWNsZUluZGV4LFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBjYWNoZVZhbHVlOiBFbnRpdHlDYWNoZVZhbHVlID0ge1xuICAgICAgICAgIGRlcGVuZGVuY2llczogbG9jYWxLZXksXG4gICAgICAgICAgdmFsdWU6IGxvY2FsQ2FjaGVLZXkuZ2V0KHBrKSxcbiAgICAgICAgfTtcbiAgICAgICAgZ2xvYmFsQ2FjaGUuc2V0KGxvY2FsS2V5LCBjYWNoZVZhbHVlKTtcblxuICAgICAgICAvLyBzdGFydCBvZiBjeWNsZSAtIHJlc2V0IGN5Y2xlIGRldGVjdGlvblxuICAgICAgICBpZiAodGhpcy5jeWNsZUluZGV4ID09PSB0cmFja2luZ0luZGV4KSB7XG4gICAgICAgICAgdGhpcy5jeWNsZUluZGV4ID0gLTE7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gY3ljbGUgZGV0ZWN0ZWRcbiAgICAgIGlmIChjeWNsZUNhY2hlS2V5LmhhcyhwaykpIHtcbiAgICAgICAgdGhpcy5jeWNsZUluZGV4ID0gY3ljbGVDYWNoZUtleS5nZXQocGspITtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHdpdGggbm8gY3ljbGUsIGdsb2JhbENhY2hlRW50cnkgd2lsbCBoYXZlIGFscmVhZHkgYmVlbiBzZXRcbiAgICAgICAgdGhpcy5kZXBlbmRlbmNpZXMucHVzaCh7IHBhdGg6IHsga2V5LCBwayB9LCBlbnRpdHkgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBsb2NhbENhY2hlS2V5LmdldChwayk7XG4gIH1cblxuICBwcml2YXRlIGdldENhY2hlS2V5KGtleTogc3RyaW5nKSB7XG4gICAgaWYgKCF0aGlzLmxvY2FsQ2FjaGUuaGFzKGtleSkpIHtcbiAgICAgIHRoaXMubG9jYWxDYWNoZS5zZXQoa2V5LCBuZXcgTWFwKCkpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuY3ljbGVDYWNoZS5oYXMoa2V5KSkge1xuICAgICAgdGhpcy5jeWNsZUNhY2hlLnNldChrZXksIG5ldyBNYXAoKSk7XG4gICAgfVxuICAgIGNvbnN0IGxvY2FsQ2FjaGVLZXkgPSB0aGlzLmxvY2FsQ2FjaGUuZ2V0KGtleSkhO1xuICAgIGNvbnN0IGN5Y2xlQ2FjaGVLZXkgPSB0aGlzLmN5Y2xlQ2FjaGUuZ2V0KGtleSkhO1xuICAgIHJldHVybiB7IGxvY2FsQ2FjaGVLZXksIGN5Y2xlQ2FjaGVLZXkgfTtcbiAgfVxuXG4gIC8qKiBDYWNoZSB2YXJpZXMgYmFzZWQgb24gaW5wdXQgKD09PSBha2EgcmVmZXJlbmNlKSAqL1xuICBnZXRSZXN1bHRzKFxuICAgIGlucHV0OiBhbnksXG4gICAgY2FjaGFibGU6IGJvb2xlYW4sXG4gICAgY29tcHV0ZVZhbHVlOiAoKSA9PiBhbnksXG4gICk6IHtcbiAgICBkYXRhOiBhbnk7XG4gICAgcGF0aHM6IEVudGl0eVBhdGhbXTtcbiAgfSB7XG4gICAgaWYgKCFjYWNoYWJsZSkge1xuICAgICAgcmV0dXJuIHsgZGF0YTogY29tcHV0ZVZhbHVlKCksIHBhdGhzOiB0aGlzLnBhdGhzKCkgfTtcbiAgICB9XG5cbiAgICBsZXQgW2RhdGEsIHBhdGhzXSA9IHRoaXMuX3Jlc3VsdENhY2hlLmdldChpbnB1dCwgdGhpcy5fZ2V0RW50aXR5KTtcblxuICAgIGlmIChwYXRocyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBkYXRhID0gY29tcHV0ZVZhbHVlKCk7XG4gICAgICAvLyB3ZSB3YW50IHRvIGRvIHRoaXMgYmVmb3JlIHdlIGFkZCBvdXIgJ2lucHV0JyBlbnRyeVxuICAgICAgcGF0aHMgPSB0aGlzLnBhdGhzKCk7XG4gICAgICAvLyBmb3IgdGhlIGZpcnN0IGVudHJ5LCBgcGF0aGAgaXMgaWdub3JlZCBzbyBlbXB0eSBtZW1iZXJzIGlzIGZpbmVcbiAgICAgIHRoaXMuZGVwZW5kZW5jaWVzLnVuc2hpZnQoeyBwYXRoOiB7IGtleTogJycsIHBrOiAnJyB9LCBlbnRpdHk6IGlucHV0IH0pO1xuICAgICAgdGhpcy5fcmVzdWx0Q2FjaGUuc2V0KHRoaXMuZGVwZW5kZW5jaWVzLCBkYXRhKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcGF0aHMuc2hpZnQoKTtcbiAgICB9XG4gICAgcmV0dXJuIHsgZGF0YSwgcGF0aHMgfTtcbiAgfVxuXG4gIHByb3RlY3RlZCBwYXRocygpIHtcbiAgICByZXR1cm4gdGhpcy5kZXBlbmRlbmNpZXMubWFwKGRlcCA9PiBkZXAucGF0aCk7XG4gIH1cbn1cblxuaW50ZXJmYWNlIEVudGl0eUNhY2hlVmFsdWUge1xuICBkZXBlbmRlbmNpZXM6IERlcDxFbnRpdHlQYXRoPltdO1xuICB2YWx1ZTogb2JqZWN0IHwgdHlwZW9mIElOVkFMSUQgfCB1bmRlZmluZWQ7XG59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