UNPKG

@data-client/normalizr

Version:

Normalizes and denormalizes JSON according to schema for Redux and Flux applications

126 lines (121 loc) 15.4 kB
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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