From 4a064cfc25d602271c121af5b0919bfcbc0ae66d Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 20 Jun 2023 23:28:18 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20.list()=20me?= =?UTF-8?q?thod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/crud/types.ts | 25 +++------------- src/fsa-crud/FsaCrud.ts | 27 +++++++++++------ src/fsa-crud/__tests__/FsaCrud.test.ts | 40 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 30 deletions(-) diff --git a/src/crud/types.ts b/src/crud/types.ts index 749e9b8d6..05b51e398 100644 --- a/src/crud/types.ts +++ b/src/crud/types.ts @@ -52,19 +52,7 @@ export interface CrudApi { * @param collection Type of the resource, collection name. * @returns List of resources of the given type, and sub-types. */ - list: (collection: CrudCollection) => Promise; - - /** - * Recursively scans all resources of a collection, and sub-collections. Returns - * a cursor to continue scanning. - * - * @param collection Type of the resource, collection name. - * @param cursor Cursor to start scanning from. If empty string, starts from the beginning. - * @returns List of resources of the given type, and sub-collections. Also - * returns a cursor to continue scanning. If the cursor is empty - * string, the scan is complete. - */ - scan: (collection: CrudCollection, cursor?: string | '') => Promise; + list: (collection: CrudCollection) => Promise; } export type CrudCollection = string[]; @@ -73,14 +61,14 @@ export interface CrudPutOptions { throwIf?: 'exists' | 'missing'; } -export interface CrudTypeEntry { +export interface CrudCollectionEntry { /** Kind of the resource, type or item. */ type: 'resource' | 'collection'; /** Name of the resource. */ id: string; } -export interface CrudResourceInfo extends CrudTypeEntry { +export interface CrudResourceInfo extends CrudCollectionEntry { /** Size of the resource in bytes. */ size?: number; /** Timestamp when the resource last modified. */ @@ -91,10 +79,5 @@ export interface CrudResourceInfo extends CrudTypeEntry { export interface CrudScanResult { cursor: string | ''; - list: CrudTypeEntry[]; -} - -export interface CrudScanEntry extends CrudTypeEntry { - /** Collection, which contains this entry. */ - collection: CrudCollection; + list: CrudCollectionEntry[]; } diff --git a/src/fsa-crud/FsaCrud.ts b/src/fsa-crud/FsaCrud.ts index ad39cd991..c45fc1bc9 100644 --- a/src/fsa-crud/FsaCrud.ts +++ b/src/fsa-crud/FsaCrud.ts @@ -138,14 +138,23 @@ export class FsaCrud implements crud.CrudApi { } }; - public readonly list = async (collection: crud.CrudCollection): Promise => { - throw new Error('Not implemented'); - }; - - public readonly scan = async ( - collection: crud.CrudCollection, - cursor?: string | '', - ): Promise => { - throw new Error('Not implemented'); + public readonly list = async (collection: crud.CrudCollection): Promise => { + assertType(collection, 'drop', 'crudfs'); + const [dir] = await this.getDir(collection, false); + const entries: crud.CrudCollectionEntry[] = []; + for await (const [id, handle] of dir.entries()) { + if (handle.kind === 'file') { + entries.push({ + type: 'resource', + id, + }); + } else if (handle.kind === 'directory') { + entries.push({ + type: 'collection', + id, + }); + } + } + return entries; }; } diff --git a/src/fsa-crud/__tests__/FsaCrud.test.ts b/src/fsa-crud/__tests__/FsaCrud.test.ts index 2f1f1980a..2ee2038c5 100644 --- a/src/fsa-crud/__tests__/FsaCrud.test.ts +++ b/src/fsa-crud/__tests__/FsaCrud.test.ts @@ -275,4 +275,44 @@ onlyOnNode20('FsaCrud', () => { expect(snapshot()).toEqual({}); }); }); + + describe('.list()', () => { + test('throws if the collection is not valid', async () => { + const { crud } = setup(); + const [, err] = await of(crud.list(['./..', 'foo'])); + expect(err).toBeInstanceOf(TypeError); + expect((err).message).toBe("Failed to execute 'drop' on 'crudfs': Name is not allowed."); + }); + + test('can retrieve a list of resources and collections at root', async () => { + const { crud } = setup(); + await crud.put(['foo'], 'bar', b('1')); + await crud.put([], 'baz', b('1')); + await crud.put([], 'qux', b('2')); + const list = await crud.list([]); + expect(list.length).toBe(3); + expect(list.find(x => x.id === 'baz')).toMatchObject({ + type: 'resource', + id: 'baz', + }); + expect(list.find(x => x.id === 'qux')).toMatchObject({ + type: 'resource', + id: 'qux', + }); + expect(list.find(x => x.id === 'foo')).toMatchObject({ + type: 'collection', + id: 'foo', + }); + }); + + test('throws when try to list a non-existing collection', async () => { + const { crud } = setup(); + await crud.put(['foo'], 'bar', b('1')); + await crud.put([], 'baz', b('1')); + await crud.put([], 'qux', b('2')); + const [, err] = await of(crud.list(['gg'])); + expect(err).toBeInstanceOf(DOMException); + expect((err).name).toBe('CollectionNotFound'); + }); + }); });