From 9a7fd37c1394f7757827fe6673344d4ee3dfbc8d Mon Sep 17 00:00:00 2001 From: streamich Date: Tue, 20 Jun 2023 22:28:37 +0200 Subject: [PATCH] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20implement=20.del()=20met?= =?UTF-8?q?hod?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/crud/types.ts | 4 +- src/fsa-crud/FsaCrud.ts | 17 +++++--- src/fsa-crud/__tests__/FsaCrud.test.ts | 55 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/src/crud/types.ts b/src/crud/types.ts index 431935731..e3b90583d 100644 --- a/src/crud/types.ts +++ b/src/crud/types.ts @@ -23,8 +23,10 @@ export interface CrudApi { * * @param collection Type of the resource, collection name. * @param id Id of the resource, document name. + * @param silent When true, does not throw an error if the collection or + * resource does not exist. Default is false. */ - del: (collection: CrudCollection, id: string) => Promise; + del: (collection: CrudCollection, id: string, silent?: boolean) => Promise; /** * Fetches information about a resource. diff --git a/src/fsa-crud/FsaCrud.ts b/src/fsa-crud/FsaCrud.ts index 714833038..985979b10 100644 --- a/src/fsa-crud/FsaCrud.ts +++ b/src/fsa-crud/FsaCrud.ts @@ -19,11 +19,11 @@ export class FsaCrud implements crud.CrudApi { } } - protected async getFile(collection: crud.CrudCollection, id: string): Promise { + protected async getFile(collection: crud.CrudCollection, id: string): Promise<[dir: fsa.IFileSystemDirectoryHandle, file: fsa.IFileSystemFileHandle]> { const dir = await this.getDir(collection, false); try { const file = await dir.getFileHandle(id, {create: false}); - return file; + return [dir, file]; } catch (error) { if (error.name === 'NotFoundError') throw new DOMException(`Resource "${id}" in /${collection.join('/')} not found`, 'ResourceNotFound'); @@ -68,14 +68,21 @@ export class FsaCrud implements crud.CrudApi { public readonly get = async (collection: crud.CrudCollection, id: string): Promise => { assertType(collection, 'get', 'crudfs'); assertName(id, 'get', 'crudfs'); - const file = await this.getFile(collection, id); + const [, file] = await this.getFile(collection, id); const blob = await file.getFile(); const buffer = await blob.arrayBuffer(); return new Uint8Array(buffer); }; - public readonly del = async (collection: crud.CrudCollection, id: string): Promise => { - throw new Error('Not implemented'); + public readonly del = async (collection: crud.CrudCollection, id: string, silent?: boolean): Promise => { + assertType(collection, 'get', 'crudfs'); + assertName(id, 'get', 'crudfs'); + try { + const [dir] = await this.getFile(collection, id); + await dir.removeEntry(id, {recursive: false}); + } catch (error) { + if (!silent) throw error; + } }; public readonly info = async (collection: crud.CrudCollection, id?: string): Promise => { diff --git a/src/fsa-crud/__tests__/FsaCrud.test.ts b/src/fsa-crud/__tests__/FsaCrud.test.ts index 5377e2642..2003d878f 100644 --- a/src/fsa-crud/__tests__/FsaCrud.test.ts +++ b/src/fsa-crud/__tests__/FsaCrud.test.ts @@ -111,4 +111,59 @@ onlyOnNode20('FsaCrud', () => { expect(blob).toStrictEqual(b('abc')); }); }); + + describe('.del()', () => { + test('throws if the type is not valid', async () => { + const {crud} = setup(); + const [, err] = await of(crud.del(['', 'foo'], 'bar')); + expect(err).toBeInstanceOf(TypeError); + }); + + test('throws if id is not valid', async () => { + const {crud} = setup(); + const [, err] = await of(crud.del(['foo'], '')); + expect(err).toBeInstanceOf(TypeError); + }); + + + describe('when collection does not exist', () => { + test('throws by default', async () => { + const {crud} = setup(); + const [, err] = await of(crud.del(['foo'], 'bar')); + expect(err).toBeInstanceOf(DOMException); + expect((err).name).toBe('CollectionNotFound'); + }); + + test('does not throw when "silent" flag set', async () => { + const {crud} = setup(); + await crud.del(['foo'], 'bar', true); + }); + }); + + describe('when collection is found but resource is not', () => { + test('throws by default', async () => { + const {crud} = setup(); + await crud.put(['foo'], 'bar', b('abc')); + const [, err] = await of(crud.del(['foo'], 'baz')); + expect(err).toBeInstanceOf(DOMException); + expect((err).name).toBe('ResourceNotFound'); + }); + + test('does not throw when "silent" flag set', async () => { + const {crud} = setup(); + await crud.put(['foo'], 'bar', b('abc')); + await crud.del(['foo'], 'baz', true); + }); + }); + + test('deletes an existing resource', async () => { + const {crud} = setup(); + await crud.put(['foo'], 'bar', b('abc')); + await crud.get(['foo'], 'bar'); + await crud.del(['foo'], 'bar'); + const [, err] = await of(crud.get(['foo'], 'bar')); + expect(err).toBeInstanceOf(DOMException); + expect((err).name).toBe('ResourceNotFound'); + }); + }); });