UNPKG

@dasch-swiss/dsp-js

Version:
113 lines 4.47 kB
import { of, map, shareReplay, take, tap } from 'rxjs'; /** * Generic cache class. * Fetches information of a specific type from Knora once and caches it. * Fetches also dependencies of a requested element (non-blocking). * Works also with multiple async requests for the same key, also if not cached yet. * * @category Internal */ export class GenericCache { constructor() { /** * Cache object: key -> value. */ this.cache = {}; } /** * Gets a specific item from the cache. * If not cached yet, the information will be retrieved from DSP-API. * * @param key the id of the item to be returned. * @param isDependency true if the item to be returned * is a dependency of another item (recursive call to this method). */ getItem(key, isDependency = false) { // If the key already exists, // return the associated Observable. if (this.cache[key] !== undefined) { return this.cache[key]; } // store the observable in the cache // the next request for the same key will immediately get the observable // also if the request has not finished yet this.cache[key] = this.requestItemFromKnora(key, isDependency).pipe( // only one item is expected take(1), // DSP-API may return several elements for the request (optimization) tap((items) => { if (items.length === 0) throw Error(`No items returned from DSP-API for ${key}`); // the first item is expected to be the requested item if (key !== this.getKeyOfItem(items[0])) throw Error(`First item of items returned from DSP-API is expected to be {$key}`); // save all additional items returned for this request this.saveAdditionalItems(items.slice(1)); // request dependencies of all items this.requestDependencies(items); }), // only write the requested item to the cache for the given key map((res) => res[0]), // make it a `ReplaySubject` so that all subscribers // will get the latest and only emitted value // // side effects (dependency handling, optimization) will only be performed once // // failed observables will be retried upon the next subscription shareReplay({ refCount: false, bufferSize: 1 })); // return the observable immediately (sync) return this.cache[key]; } /** * Deletes an existing entry in the cache and requests information from DSP-API. * * @param key the id of the information to be returned. * @return the item. */ reloadItem(key) { if (this.cache[key] !== undefined) delete this.cache[key]; return this.getItem(key); } /** * Handle additional items that were resolved with a request. * * @param items dependencies that have been retrieved. */ saveAdditionalItems(items) { // Write all available items to the cache (only for non existing keys) // Analyze dependencies of available items. items.forEach((item) => { // Get key of item const itemKey = this.getKeyOfItem(item); // Only write an additional item to the cache // if there is not entry for it yet // item for `key` has already been handled if (this.cache[itemKey] === undefined) { this.cache[itemKey] = of(item); } }); } /** * Requests dependencies of the items retrieved from DSP-API. * * @param items items returned from DSP-API to a request. */ requestDependencies(items) { items.forEach((item) => { // get items this item depends on this.getDependenciesOfItem(item) .filter((depKey) => { // ignore dependencies already taken care of return Object.keys(this.cache).indexOf(depKey) === -1; }) .forEach((depKey) => { // Request each dependency from the cache // Dependencies will be fetched independently (non-blocking). // Subscribe because the Observable is lazy this.getItem(depKey, true).subscribe(); }); }); } } //# sourceMappingURL=GenericCache.js.map