catalog-backend: add scoped readLocation cache
Co-authored-by: Fredrik Adelöw <freben@gmail.com> Co-authored-by: blam <ben@blam.sh> Co-authored-by: Johan Haals <johan.haals@gmail.com> Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
committed by
Johan Haals
parent
69acb4e7ba
commit
b0e1aa7620
@@ -318,7 +318,7 @@ export class DefaultCatalogProcessingOrchestrator
|
||||
false,
|
||||
context.collector.onEmit,
|
||||
this.options.parser,
|
||||
context.cache.forProcessor(processor),
|
||||
context.cache.forProcessor(processor, target),
|
||||
);
|
||||
if (read) {
|
||||
didRead = true;
|
||||
|
||||
@@ -75,3 +75,44 @@ describe('ProcessorCacheManager', () => {
|
||||
).resolves.toBe('my-new-value');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ScopedProcessorCache', () => {
|
||||
const myProcessor = new MyProcessor();
|
||||
|
||||
it('should forward existing state and collect new state', async () => {
|
||||
const cache = new ProcessorCacheManager({
|
||||
'my-processor': { 'scope-1': { 'my-key': 'my-value' } },
|
||||
});
|
||||
|
||||
const scopedCache1 = cache.forProcessor(myProcessor, 'scope-1');
|
||||
const scopedCache2 = cache.forProcessor(myProcessor, 'scope-2');
|
||||
|
||||
// Should be empty to begin with
|
||||
expect(cache.collect()).toEqual({
|
||||
'my-processor': { 'scope-1': { 'my-key': 'my-value' } },
|
||||
});
|
||||
|
||||
await scopedCache2.set('my-new-key-2', 'my-new-value-2');
|
||||
|
||||
expect(cache.collect()).toEqual({
|
||||
'my-processor': {
|
||||
'scope-1': { 'my-key': 'my-value' },
|
||||
'scope-2': { 'my-new-key-2': 'my-new-value-2' },
|
||||
},
|
||||
});
|
||||
|
||||
await scopedCache1.set('my-new-key', 'my-new-value');
|
||||
|
||||
await expect(scopedCache1.get<string>('my-key')).resolves.toBe('my-value');
|
||||
await expect(
|
||||
scopedCache1.get<string>('my-new-key'),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(cache.collect()).toEqual({
|
||||
'my-processor': {
|
||||
'scope-1': { 'my-new-key': 'my-new-value' },
|
||||
'scope-2': { 'my-new-key-2': 'my-new-value-2' },
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -19,7 +19,7 @@ import { CatalogProcessor } from '../../ingestion/processors';
|
||||
import { CatalogProcessorCache } from '../../ingestion/processors/types';
|
||||
import { isObject } from './util';
|
||||
|
||||
class SingleProcessorCache implements CatalogProcessorCache {
|
||||
class SingleProcessorSubCache implements CatalogProcessorCache {
|
||||
private newState?: JsonObject;
|
||||
|
||||
constructor(private readonly existingState?: JsonObject) {}
|
||||
@@ -46,17 +46,68 @@ class SingleProcessorCache implements CatalogProcessorCache {
|
||||
}
|
||||
}
|
||||
|
||||
class SingleProcessorCache implements CatalogProcessorCache {
|
||||
private newState?: JsonObject;
|
||||
private subCaches: Map<string, SingleProcessorSubCache> = new Map();
|
||||
|
||||
constructor(private readonly existingState?: JsonObject) {}
|
||||
|
||||
async get<ItemType extends JsonValue>(
|
||||
key: string,
|
||||
): Promise<ItemType | undefined> {
|
||||
return this.existingState?.[key] as ItemType | undefined;
|
||||
}
|
||||
|
||||
async set<ItemType extends JsonValue>(
|
||||
key: string,
|
||||
value: ItemType,
|
||||
): Promise<void> {
|
||||
if (!this.newState) {
|
||||
this.newState = {};
|
||||
}
|
||||
|
||||
this.newState[key] = value;
|
||||
}
|
||||
|
||||
withKey(key: string) {
|
||||
const existingSubCache = this.subCaches.get(key);
|
||||
if (existingSubCache) {
|
||||
return existingSubCache;
|
||||
}
|
||||
const existing = this.existingState?.[key];
|
||||
const subCache = new SingleProcessorSubCache(
|
||||
isObject(existing) ? existing : undefined,
|
||||
);
|
||||
this.subCaches.set(key, subCache);
|
||||
return subCache;
|
||||
}
|
||||
|
||||
collect(): JsonObject | undefined {
|
||||
let obj = this.newState ?? this.existingState;
|
||||
for (const [key, subCache] of this.subCaches) {
|
||||
const subCacheValue = subCache.collect();
|
||||
if (subCacheValue) {
|
||||
obj = { ...obj, [key]: subCacheValue };
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProcessorCacheManager {
|
||||
private caches = new Map<string, SingleProcessorCache>();
|
||||
|
||||
constructor(private readonly existingState: JsonObject) {}
|
||||
|
||||
forProcessor(processor: CatalogProcessor): CatalogProcessorCache {
|
||||
forProcessor(
|
||||
processor: CatalogProcessor,
|
||||
key?: string,
|
||||
): CatalogProcessorCache {
|
||||
// constructor name will be deprecated in the future when we make `getProcessorName` required in the implementation
|
||||
const name = processor.getProcessorName?.() ?? processor.constructor.name;
|
||||
const cache = this.caches.get(name);
|
||||
if (cache) {
|
||||
return cache;
|
||||
return key ? cache.withKey(key) : cache;
|
||||
}
|
||||
|
||||
const existing = this.existingState[name];
|
||||
@@ -65,7 +116,7 @@ export class ProcessorCacheManager {
|
||||
isObject(existing) ? existing : undefined,
|
||||
);
|
||||
this.caches.set(name, newCache);
|
||||
return newCache;
|
||||
return key ? newCache.withKey(key) : newCache;
|
||||
}
|
||||
|
||||
collect(): JsonObject {
|
||||
|
||||
Reference in New Issue
Block a user