diff --git a/packages/sdk/src/utils/CachingMap.ts b/packages/sdk/src/utils/CachingMap.ts
deleted file mode 100644
index 8952e12f95..0000000000
--- a/packages/sdk/src/utils/CachingMap.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { MapKey } from '@streamr/utils'
-import pMemoize from 'p-memoize'
-import LRU from '../../vendor/quick-lru'
-
-interface Options
{
- maxSize: number
- maxAge: number
- cacheKey: (args: P) => K
-}
-
-/**
- * Caches into a LRU cache capped at options.maxSize. See documentation for mem/p-memoize.
- * Won't call asyncFn again until options.maxAge or options.maxSize exceeded, or cachedAsyncFn.invalidate() is called.
- * Won't cache rejections.
- *
- * ```js
- * const cache = new CachingMap(asyncFn, opts)
- * await cache.get(key)
- * await cache.get(key)
- * cache.invalidate(() => ...)
- * ```
- */
-export class CachingMap {
-
- private readonly cachedFn: (...args: P) => Promise
- private readonly cache: LRU
- private readonly opts: Options
-
- constructor(
- asyncFn: (...args: P) => Promise,
- opts: Options
- ) {
- this.cache = new LRU({
- maxSize: opts.maxSize,
- maxAge: opts.maxAge
- })
- this.cachedFn = pMemoize(asyncFn, {
- cachePromiseRejection: false,
- cache: this.cache,
- cacheKey: opts.cacheKey
- })
- this.opts = opts
- }
-
- get(...args: P): Promise {
- return this.cachedFn(...args)
- }
-
- set(args: P, value: V): void {
- this.cache.set(this.opts.cacheKey(args), { data: value, maxAge: this.opts.maxAge })
- }
-
- invalidate(predicate: (key: K) => boolean): void {
- for (const key of this.cache.keys()) {
- if (predicate(key)) {
- this.cache.delete(key)
- }
- }
- }
-}
diff --git a/packages/sdk/test/unit/CachingMap.test.ts b/packages/sdk/test/unit/CachingMap.test.ts
deleted file mode 100644
index 271952cb45..0000000000
--- a/packages/sdk/test/unit/CachingMap.test.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import { CachingMap } from '../../src/utils/CachingMap'
-import { wait } from '@streamr/utils'
-
-describe('CachingMap', () => {
-
- let plainFn: jest.Mock, [key1: string, key2: string]>
- let cache: CachingMap
-
- beforeEach(() => {
- plainFn = jest.fn()
- plainFn.mockImplementation(async (key1: string, key2: string) => {
- await wait(100)
- return `${key1}${key2}`.toUpperCase()
- })
- cache = new CachingMap(plainFn as any, {
- maxSize: 10000,
- maxAge: 30 * 60 * 1000,
- cacheKey: ([key1, key2]) => `${key1};${key2}`
- })
- })
-
- it('happy path', async () => {
- const result1 = await cache.get('foo', 'bar')
- const result2 = await cache.get('foo', 'bar')
- expect(result1).toBe('FOOBAR')
- expect(result2).toBe('FOOBAR')
- expect(plainFn).toHaveBeenCalledTimes(1)
- })
-
- it('miss', async () => {
- const result1 = await cache.get('foo', 'x')
- const result2 = await cache.get('foo', 'y')
- expect(result1).toBe('FOOX')
- expect(result2).toBe('FOOY')
- expect(plainFn).toHaveBeenCalledTimes(2)
- })
-
- it('concurrency', async () => {
- const [result1, result2] = await Promise.all([
- cache.get('foo', 'bar'),
- cache.get('foo', 'bar')
- ])
- expect(result1).toBe('FOOBAR')
- expect(result2).toBe('FOOBAR')
- expect(plainFn).toHaveBeenCalledTimes(1)
- })
-
- it('rejections are not cached', async () => {
- plainFn.mockImplementation(async (key1: string, key2: string) => {
- throw new Error(`error ${key1}-${key2}`)
- })
- await expect(cache.get('foo', 'x')).rejects.toEqual(new Error('error foo-x'))
- await expect(cache.get('foo', 'x')).rejects.toEqual(new Error('error foo-x'))
-
- expect(plainFn).toHaveBeenCalledTimes(2) // would be 1 if rejections were cached
- })
-
- it('throws are not cached', async () => {
- plainFn.mockImplementation((key1: string, key2: string) => {
- throw new Error(`error ${key1}-${key2}`)
- })
- await expect(cache.get('foo', 'x')).rejects.toEqual(new Error('error foo-x'))
- await expect(cache.get('foo', 'x')).rejects.toEqual(new Error('error foo-x'))
-
- expect(plainFn).toHaveBeenCalledTimes(2) // would be 1 if throws were cached
- })
-})
diff --git a/packages/sdk/test/unit/CachingMap2.test.ts b/packages/sdk/test/unit/CachingMap2.test.ts
deleted file mode 100644
index 1493c97368..0000000000
--- a/packages/sdk/test/unit/CachingMap2.test.ts
+++ /dev/null
@@ -1,140 +0,0 @@
-import { wait } from '@streamr/utils'
-import { CachingMap } from '../../src/utils/CachingMap'
-
-const DEFAULT_OPTS = {
- maxSize: 10000,
- maxAge: 30 * 60 * 1000,
- cacheKey: (args: any[]) => args[0]
-}
-
-describe('CachingMap', () => {
- it('caches & be cleared', async () => {
- const fn = jest.fn()
- const cache = new CachingMap(fn, DEFAULT_OPTS)
- await cache.get()
- expect(fn).toHaveBeenCalledTimes(1)
- await cache.get()
- expect(fn).toHaveBeenCalledTimes(1)
- await cache.get(1)
- expect(fn).toHaveBeenCalledTimes(2)
- await cache.get(1)
- expect(fn).toHaveBeenCalledTimes(2)
- await cache.get(2)
- expect(fn).toHaveBeenCalledTimes(3)
- await cache.get(1)
- expect(fn).toHaveBeenCalledTimes(3)
- await cache.get(2)
- expect(fn).toHaveBeenCalledTimes(3)
- cache.invalidate((v) => v === 1)
- await cache.get(1)
- expect(fn).toHaveBeenCalledTimes(4)
- cache.invalidate((v) => v === 1)
- await cache.get(1)
- expect(fn).toHaveBeenCalledTimes(5)
- })
-
- it('adopts type of wrapped function', async () => {
- // actually checking via ts-expect-error
- // assertions don't matter,
- async function fn(_s: string): Promise {
- return 3
- }
-
- const cache = new CachingMap(fn, DEFAULT_OPTS)
- const a: number = await cache.get('abc') // ok
- expect(a).toEqual(3)
- // @ts-expect-error not enough args
- await cache.get()
- // @ts-expect-error too many args
- await cache.get('abc', 3)
- // @ts-expect-error wrong argument type
- await cache.get(3)
-
- // @ts-expect-error wrong return type
- const c: string = await cache.get('abc')
- expect(c).toEqual(3)
- cache.invalidate((_d: string) => true)
- const cache2 = new CachingMap(fn, {
- ...DEFAULT_OPTS,
- cacheKey: ([s]) => {
- return s.length
- }
- })
-
- cache2.invalidate((_d: number) => true)
- })
-
- it('does memoize consecutive calls', async () => {
- let i = 0
- const fn = async () => {
- i += 1
- return i
- }
- const memoized = new CachingMap(fn, DEFAULT_OPTS)
- const firstCall = memoized.get()
- const secondCall = memoized.get()
-
- expect(await Promise.all([firstCall, secondCall])).toEqual([1, 1])
- })
-
- it('can not be executed in parallel', async () => {
- const taskId1 = '0xbe406f5e1b7e951cd8e42ab28598671e5b73c3dd/test/75712/Encryption-0'
- const taskId2 = 'd/e/f'
- const calledWith: string[] = []
- const fn = jest.fn(async (key: string) => {
- calledWith.push(key)
- await wait(100)
- return key
- })
-
- const cache = new CachingMap(fn, {
- maxSize: 10000,
- maxAge: 1800000,
- cacheKey: ([v]) => {
- return v
- }
- })
- const task = Promise.all([
- cache.get(taskId1),
- cache.get(taskId2),
- cache.get(taskId1),
- cache.get(taskId2),
- ])
- task.catch(() => {})
- setImmediate(() => {
- cache.get(taskId1)
- cache.get(taskId1)
- cache.get(taskId2)
- cache.get(taskId2)
- })
- process.nextTick(() => {
- cache.get(taskId1)
- cache.get(taskId2)
- cache.get(taskId1)
- cache.get(taskId2)
- })
- setTimeout(() => {
- cache.get(taskId1)
- cache.get(taskId1)
- cache.get(taskId2)
- cache.get(taskId2)
- })
- await wait(10)
- cache.get(taskId2)
- cache.get(taskId2)
- cache.get(taskId1)
- cache.get(taskId1)
- await Promise.all([
- cache.get(taskId1),
- cache.get(taskId2),
- cache.get(taskId1),
- cache.get(taskId2),
- ])
- await task
- expect(fn).toHaveBeenCalledTimes(2)
- expect(calledWith).toEqual([taskId1, taskId2])
- await wait(200)
- expect(fn).toHaveBeenCalledTimes(2)
- expect(calledWith).toEqual([taskId1, taskId2])
- })
-})