diff --git a/src/storage/keyvalue/JsonResourceStorage.ts b/src/storage/keyvalue/JsonResourceStorage.ts index 247efd49b..1b120a88e 100644 --- a/src/storage/keyvalue/JsonResourceStorage.ts +++ b/src/storage/keyvalue/JsonResourceStorage.ts @@ -1,6 +1,7 @@ import { BasicRepresentation } from '../../ldp/representation/BasicRepresentation'; import type { ResourceIdentifier } from '../../ldp/representation/ResourceIdentifier'; import { NotFoundHttpError } from '../../util/errors/NotFoundHttpError'; +import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError'; import { readableToString } from '../../util/StreamUtil'; import type { ResourceStore } from '../ResourceStore'; import type { KeyValueStorage } from './KeyValueStorage'; @@ -61,4 +62,9 @@ export class JsonResourceStorage implements KeyValueStorage { * @returns If there was a value to delete. */ delete: (key: TKey) => Promise; + + /** + * An iterable of entries in the storage. + */ + entries: () => AsyncIterableIterator<[TKey, TValue]>; } diff --git a/src/storage/keyvalue/MemoryMapStorage.ts b/src/storage/keyvalue/MemoryMapStorage.ts index ad1bbf534..fc5294ddd 100644 --- a/src/storage/keyvalue/MemoryMapStorage.ts +++ b/src/storage/keyvalue/MemoryMapStorage.ts @@ -28,4 +28,10 @@ export class MemoryMapStorage implements KeyValueStorage { return this.data.delete(key); } + + public async* entries(): AsyncIterableIterator<[TKey, TValue]> { + for (const entry of this.data.entries()) { + yield entry; + } + } } diff --git a/src/storage/keyvalue/ResourceIdentifierStorage.ts b/src/storage/keyvalue/ResourceIdentifierStorage.ts index e513bcb51..58af6e364 100644 --- a/src/storage/keyvalue/ResourceIdentifierStorage.ts +++ b/src/storage/keyvalue/ResourceIdentifierStorage.ts @@ -30,4 +30,10 @@ export class ResourceIdentifierStorage implements KeyValueStorage { return this.source.delete(key.path); } + + public async* entries(): AsyncIterableIterator<[ResourceIdentifier, T]> { + for await (const [ path, value ] of this.source.entries()) { + yield [{ path }, value ]; + } + } } diff --git a/test/unit/storage/keyvalue/JsonResourceStorage.test.ts b/test/unit/storage/keyvalue/JsonResourceStorage.test.ts index c86f858b9..32fae6eec 100644 --- a/test/unit/storage/keyvalue/JsonResourceStorage.test.ts +++ b/test/unit/storage/keyvalue/JsonResourceStorage.test.ts @@ -4,6 +4,7 @@ import type { ResourceIdentifier } from '../../../../src/ldp/representation/Reso import { JsonResourceStorage } from '../../../../src/storage/keyvalue/JsonResourceStorage'; import type { ResourceStore } from '../../../../src/storage/ResourceStore'; import { NotFoundHttpError } from '../../../../src/util/errors/NotFoundHttpError'; +import { NotImplementedHttpError } from '../../../../src/util/errors/NotImplementedHttpError'; import { readableToString } from '../../../../src/util/StreamUtil'; describe('A JsonResourceStorage', (): void => { @@ -44,6 +45,7 @@ describe('A JsonResourceStorage', (): void => { it('returns data if it was set beforehand.', async(): Promise => { await expect(storage.set(identifier1, 'apple')).resolves.toBe(storage); await expect(storage.get(identifier1)).resolves.toBe('apple'); + expect(storage.entries).toThrow(NotImplementedHttpError); }); it('can check if data is present.', async(): Promise => { diff --git a/test/unit/storage/keyvalue/MemoryMapStorage.test.ts b/test/unit/storage/keyvalue/MemoryMapStorage.test.ts index da2a967b9..9a41e5b4a 100644 --- a/test/unit/storage/keyvalue/MemoryMapStorage.test.ts +++ b/test/unit/storage/keyvalue/MemoryMapStorage.test.ts @@ -17,6 +17,7 @@ describe('A MemoryMapStorage', (): void => { it('returns data if it was set beforehand.', async(): Promise => { await expect(storage.set(identifier1, 'apple')).resolves.toBe(storage); await expect(storage.get(identifier1)).resolves.toBe('apple'); + await expect(storage.entries().next()).resolves.toEqual({ done: false, value: [ identifier1, 'apple' ]}); }); it('can check if data is present.', async(): Promise => { diff --git a/test/unit/storage/keyvalue/ResourceIdentifierStorage.test.ts b/test/unit/storage/keyvalue/ResourceIdentifierStorage.test.ts index d1b26d2ed..aaabc88c3 100644 --- a/test/unit/storage/keyvalue/ResourceIdentifierStorage.test.ts +++ b/test/unit/storage/keyvalue/ResourceIdentifierStorage.test.ts @@ -13,6 +13,9 @@ describe('A ResourceIdentifierStorage', (): void => { has: jest.fn(), set: jest.fn(), delete: jest.fn(), + entries: jest.fn(async function* (): any { + yield [ 'a', 1 ]; + }), }; storage = new ResourceIdentifierStorage(source); }); @@ -33,5 +36,8 @@ describe('A ResourceIdentifierStorage', (): void => { await storage.delete(identifier); expect(source.delete).toHaveBeenCalledTimes(1); expect(source.delete).toHaveBeenLastCalledWith(path); + + await storage.entries().next(); + expect(source.entries).toHaveBeenCalledTimes(1); }); }); diff --git a/test/unit/util/locking/GreedyReadWriteLocker.test.ts b/test/unit/util/locking/GreedyReadWriteLocker.test.ts index 81a88e7f8..900317f16 100644 --- a/test/unit/util/locking/GreedyReadWriteLocker.test.ts +++ b/test/unit/util/locking/GreedyReadWriteLocker.test.ts @@ -52,7 +52,7 @@ describe('A GreedyReadWriteLocker', (): void => { has: async(identifier: ResourceIdentifier): Promise => map.has(identifier.path), set: async(identifier: ResourceIdentifier, value: number): Promise => map.set(identifier.path, value), delete: async(identifier: ResourceIdentifier): Promise => map.delete(identifier.path), - }; + } as any; locker = new GreedyReadWriteLocker(sourceLocker, storage); });