UNPKG

layered-loader

Version:

Data loader with support for caching and fallback data sources

148 lines 6.21 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AbstractGroupCache = void 0; const AbstractCache_1 = require("./AbstractCache"); class AbstractGroupCache extends AbstractCache_1.AbstractCache { isGroupCache() { return true; } async invalidateCacheForGroup(group) { if (this.asyncCache) { await this.asyncCache.deleteGroup(group).catch((err) => { this.cacheUpdateErrorHandler(err, `group: ${group}`, this.asyncCache, this.logger); }); } this.inMemoryCache.deleteGroup(group); this.runningLoads.delete(group); if (this.notificationPublisher) { void this.notificationPublisher.deleteGroup(group).catch((err) => { this.notificationPublisher.errorHandler(err, this.notificationPublisher.channel, this.logger); }); } } getInMemoryOnly(loadParams, group) { const key = this.cacheKeyFromLoadParamsResolver(loadParams); if (this.inMemoryCache.ttlLeftBeforeRefreshInMsecs) { const groupLoads = this.resolveGroupLoads(group); if (!groupLoads.has(key)) { const expirationTime = this.inMemoryCache.getExpirationTimeFromGroup(key, group); if (expirationTime && expirationTime - Date.now() < this.inMemoryCache.ttlLeftBeforeRefreshInMsecs) { void this.getAsyncOnly(loadParams, group); } } } return this.inMemoryCache.getFromGroup(key, group); } getManyInMemoryOnly(keys, group) { // Note that it doesn't support preemptive refresh return this.inMemoryCache.getManyFromGroup(keys, group); } getAsyncOnly(loadParams, group) { const key = this.cacheKeyFromLoadParamsResolver(loadParams); const groupLoads = this.resolveGroupLoads(group); const existingLoad = groupLoads.get(key); if (existingLoad) { return existingLoad; } const loadingPromise = this.resolveGroupValue(key, group, loadParams); groupLoads.set(key, loadingPromise); loadingPromise .then((resolvedValue) => { if (resolvedValue !== undefined) { this.inMemoryCache.setForGroup(key, resolvedValue, group); } this.deleteGroupRunningLoad(groupLoads, group, key); }) .catch(() => { this.deleteGroupRunningLoad(groupLoads, group, key); }); return loadingPromise; } getManyAsyncOnly(keys, group, loadParams) { // This doesn't support deduplication, and never might, as that would affect perf strongly. Maybe as an opt-in option in the future? return this.resolveManyGroupValues(keys, group, loadParams).then((result) => { for (let i = 0; i < result.resolvedValues.length; i++) { const resolvedValue = result.resolvedValues[i]; const id = this.cacheKeyFromValueResolver(resolvedValue); this.inMemoryCache.setForGroup(id, resolvedValue, group); } return result; }); } get(loadParams, group) { const key = this.cacheKeyFromLoadParamsResolver(loadParams); const inMemoryValue = this.getInMemoryOnly(loadParams, group); if (inMemoryValue !== undefined) { return Promise.resolve(inMemoryValue); } return this.getAsyncOnly(loadParams, group); } getMany(keys, group, loadParams) { const inMemoryValues = this.getManyInMemoryOnly(keys, group); // everything is in memory, hurray if (inMemoryValues.unresolvedKeys.length === 0) { return Promise.resolve(inMemoryValues.resolvedValues); } return this.getManyAsyncOnly(inMemoryValues.unresolvedKeys, group, loadParams).then((asyncRetrievedValues) => { return [...inMemoryValues.resolvedValues, ...asyncRetrievedValues.resolvedValues]; }); } async invalidateCacheFor(key, group) { this.inMemoryCache.deleteFromGroup(key, group); if (this.asyncCache) { await this.asyncCache.deleteFromGroup(key, group).catch((err) => { this.cacheUpdateErrorHandler(err, undefined, this.asyncCache, this.logger); }); } const groupLoads = this.resolveGroupLoads(group); this.deleteGroupRunningLoad(groupLoads, group, key); if (this.notificationPublisher) { void this.notificationPublisher.deleteFromGroup(key, group).catch((err) => { this.notificationPublisher.errorHandler(err, this.notificationPublisher.channel, this.logger); }); } } async resolveGroupValue(key, group, _loadParams) { if (this.asyncCache) { const cachedValue = await this.asyncCache.getFromGroup(key, group).catch((err) => { this.loadErrorHandler(err, key, this.asyncCache, this.logger); }); if (cachedValue !== undefined) { return cachedValue; } } return undefined; } async resolveManyGroupValues(keys, group, _loadParams) { if (this.asyncCache) { return this.asyncCache.getManyFromGroup(keys, group).catch((err) => { this.loadErrorHandler(err, keys.toString(), this.asyncCache, this.logger); return { unresolvedKeys: keys, resolvedValues: [], }; }); } return { unresolvedKeys: keys, resolvedValues: [], }; } resolveGroupLoads(group) { const load = this.runningLoads.get(group); if (load) { return load; } const loadCache = new Map(); this.runningLoads.set(group, loadCache); return loadCache; } deleteGroupRunningLoad(groupLoads, group, key) { groupLoads.delete(key); if (groupLoads.size === 0) { this.runningLoads.delete(group); } } } exports.AbstractGroupCache = AbstractGroupCache; //# sourceMappingURL=AbstractGroupCache.js.map