diff --git a/src/market/RegionalMarketCache.spec.ts b/src/market/RegionalMarketCache.spec.ts new file mode 100644 index 0000000..f5ef567 --- /dev/null +++ b/src/market/RegionalMarketCache.spec.ts @@ -0,0 +1,35 @@ +import { describe, expect, it } from 'vitest' +import { RegionalMarketCache } from './RegionalMarketCache' + +describe('RegionalMarketCache', () => { + it('should cache and retrieve values', async () => { + const cache = new RegionalMarketCache(1000) + + cache.set(1, 1, 'test') + expect(cache.get(1, 1)).toBe('test') + }) + + it('should remove values', async () => { + const cache = new RegionalMarketCache(1000) + + cache.set(1, 1, 'test') + cache.remove(1, 1) + expect(cache.get(1, 1)).toBeUndefined() + }) + + it('should compute values if absent', async () => { + const cache = new RegionalMarketCache(1000) + const value = await cache.computeIfAbsent(1, 1, () => Promise.resolve('test')) + + expect(value).toBe('test') + expect(cache.get(1, 1)).toBe('test') + }) + + it('should expire values', async () => { + const cache = new RegionalMarketCache(1) + + cache.set(1, 1, 'test') + await new Promise(resolve => setTimeout(resolve, 10)) + expect(cache.get(1, 1)).toBeUndefined() + }) +}) \ No newline at end of file diff --git a/src/market/RegionalMarketCache.ts b/src/market/RegionalMarketCache.ts new file mode 100644 index 0000000..f738aa8 --- /dev/null +++ b/src/market/RegionalMarketCache.ts @@ -0,0 +1,50 @@ +class CacheEntry { + public value: T; + public expiration: Date; + + constructor(value: T, expiration: Date) { + this.value = value; + this.expiration = expiration; + } +} + +export type ExpirationSupplier = (v: T) => Date; + +export class RegionalMarketCache { + private cache: Record>>; + private expirationSupplier: (v: T) => Date; + + constructor(expiration: ExpirationSupplier | number) { + this.cache = {}; + this.expirationSupplier = expiration instanceof Function ? expiration : () => new Date(Date.now() + expiration); + } + + public get(regionId: number, typeId: number): T | undefined { + const entry = this.cache[regionId]?.[typeId]; + + if (entry && entry.expiration > new Date()) { + return entry.value; + } + this.remove(regionId, typeId); + return undefined; + } + + public set(regionId: number, typeId: number, value: T): void { + this.cache[regionId] = this.cache[regionId] ?? {}; + this.cache[regionId][typeId] = new CacheEntry(value, this.expirationSupplier(value)); + } + + public remove(regionId: number, typeId: number): void { + delete this.cache[regionId]?.[typeId]; + } + + public async computeIfAbsent(regionId: number, typeId: number, supplier: () => (Promise | T)): Promise { + let value = this.get(regionId, typeId); + + if (!value) { + value = await supplier(); + this.set(regionId, typeId, value); + } + return value; + } +}; \ No newline at end of file diff --git a/src/market/acquisition/AcquisitionQuantilsTooltip.vue b/src/market/acquisition/AcquisitionQuantilsTooltip.vue index 5501b30..a59b763 100644 --- a/src/market/acquisition/AcquisitionQuantilsTooltip.vue +++ b/src/market/acquisition/AcquisitionQuantilsTooltip.vue @@ -1,7 +1,7 @@