layered-loader
Version:
Data loader with support for caching and fallback data sources
132 lines • 5.31 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AbstractFlatCache = void 0;
const AbstractCache_1 = require("./AbstractCache");
class AbstractFlatCache extends AbstractCache_1.AbstractCache {
isGroupCache() {
return false;
}
getInMemoryOnly(loadParams) {
const key = this.cacheKeyFromLoadParamsResolver(loadParams);
if (this.inMemoryCache.ttlLeftBeforeRefreshInMsecs && !this.runningLoads.has(key)) {
const expirationTime = this.inMemoryCache.getExpirationTime(key);
if (expirationTime && expirationTime - Date.now() < this.inMemoryCache.ttlLeftBeforeRefreshInMsecs) {
void this.getAsyncOnly(loadParams);
}
}
return this.inMemoryCache.get(key);
}
getManyInMemoryOnly(keys) {
// Note that it doesn't support preemptive refresh
return this.inMemoryCache.getMany(keys);
}
getAsyncOnly(loadParams) {
const key = this.cacheKeyFromLoadParamsResolver(loadParams);
const existingLoad = this.runningLoads.get(key);
if (existingLoad) {
return existingLoad;
}
const loadingPromise = this.resolveValue(key, loadParams);
this.runningLoads.set(key, loadingPromise);
loadingPromise
.then((resolvedValue) => {
if (resolvedValue !== undefined) {
this.inMemoryCache.set(key, resolvedValue);
}
this.runningLoads.delete(key);
})
.catch(() => {
this.runningLoads.delete(key);
});
return loadingPromise;
}
getManyAsyncOnly(keys, loadParams) {
// This doesn't support deduplication, and never might, as that would affect perf strongly. Maybe as an opt-in option in the future?
const loadingPromise = this.resolveManyValues(keys, loadParams);
return loadingPromise.then((result) => {
for (let i = 0; i < result.resolvedValues.length; i++) {
const resolvedValue = result.resolvedValues[i];
const id = this.cacheKeyFromValueResolver(resolvedValue);
this.inMemoryCache.set(id, resolvedValue);
}
return result;
});
}
get(loadParams) {
const inMemoryValue = this.getInMemoryOnly(loadParams);
if (inMemoryValue !== undefined) {
return Promise.resolve(inMemoryValue);
}
return this.getAsyncOnly(loadParams);
}
getMany(keys, loadParams) {
const inMemoryValues = this.getManyInMemoryOnly(keys);
// everything is in memory, hurray
if (inMemoryValues.unresolvedKeys.length === 0) {
return Promise.resolve(inMemoryValues.resolvedValues);
}
return this.getManyAsyncOnly(inMemoryValues.unresolvedKeys, loadParams).then((asyncRetrievedValues) => {
return [...inMemoryValues.resolvedValues, ...asyncRetrievedValues.resolvedValues];
});
}
async resolveValue(key, _loadParams) {
if (this.asyncCache) {
const cachedValue = await this.asyncCache.get(key).catch((err) => {
this.loadErrorHandler(err, key, this.asyncCache, this.logger);
});
if (cachedValue !== undefined) {
return cachedValue;
}
}
return undefined;
}
async resolveManyValues(keys, _loadParams) {
if (this.asyncCache) {
return this.asyncCache.getMany(keys).catch((err) => {
this.loadErrorHandler(err, keys.toString(), this.asyncCache, this.logger);
return {
unresolvedKeys: keys,
resolvedValues: [],
};
});
}
return {
unresolvedKeys: keys,
resolvedValues: [],
};
}
async invalidateCacheFor(key) {
this.inMemoryCache.delete(key);
if (this.asyncCache) {
await this.asyncCache.delete(key).catch((err) => {
this.cacheUpdateErrorHandler(err, undefined, this.asyncCache, this.logger);
});
}
this.runningLoads.delete(key);
if (this.notificationPublisher) {
this.notificationPublisher.delete(key).catch((err) => {
this.notificationPublisher.errorHandler(err, this.notificationPublisher.channel, this.logger);
});
}
}
async invalidateCacheForMany(keys) {
if (this.asyncCache) {
await this.asyncCache.deleteMany(keys).catch((err) => {
/* c8 ignore next 1 */
this.cacheUpdateErrorHandler(err, undefined, this.asyncCache, this.logger);
});
}
for (let i = 0; i < keys.length; i++) {
this.inMemoryCache.delete(keys[i]);
this.runningLoads.delete(keys[i]);
}
if (this.notificationPublisher) {
this.notificationPublisher.deleteMany(keys).catch((err) => {
/* c8 ignore next 1 */
this.notificationPublisher.errorHandler(err, this.notificationPublisher.channel, this.logger);
});
}
}
}
exports.AbstractFlatCache = AbstractFlatCache;
//# sourceMappingURL=AbstractFlatCache.js.map