diff --git a/lib/graph/file.graph.ts b/lib/graph/file.graph.ts index 86e5c2c..ece5db8 100644 --- a/lib/graph/file.graph.ts +++ b/lib/graph/file.graph.ts @@ -10,7 +10,7 @@ import { uuidType, } from '../interfaces'; import { StorageFile } from './storage.file'; -import { AsyncTaskQueue, uuid } from '../utils'; +import { AsyncTaskQueue, uuid, createError } from '../utils'; class FileGraphIml implements FileGraphAbstract { constructor( @@ -93,8 +93,9 @@ class FileGraphIml implements FileGraphAbstract { const index = ids.indexOf(vertex.id); if (index === -1) return; const nextVertexId = ids[index + 1]; - if (nextVertexId && !vertex.links.includes(nextVertexId)) + if (nextVertexId && !vertex.links.includes(nextVertexId)) { return { links: [...vertex.links, nextVertexId] }; + } }; const updateResult = await this.storageFile.updateLine(updater); @@ -107,12 +108,14 @@ class FileGraphIml implements FileGraphAbstract { ): Promise { return this.updateArc(targetVertexId, vertex => { if (vertex.id !== sourceVertexId) return; - if (!vertex.links.includes(targetVertexId)) - return { links: [...vertex.links, targetVertexId] }; - - throw new Error( - `targetVertexId: ${targetVertexId} already exists in vertex ${sourceVertexId}`, - ); + if (vertex.links.includes(targetVertexId)) { + throw createError( + 'TARGET_VERTEX_ALREADY_EXISTS', + targetVertexId, + sourceVertexId, + ); + } + return { links: [...vertex.links, targetVertexId] }; }); } @@ -122,12 +125,14 @@ class FileGraphIml implements FileGraphAbstract { ): Promise { return this.updateArc(targetVertexId, vertex => { if (vertex.id !== sourceVertexId) return; - if (vertex.links.includes(targetVertexId)) - return { links: vertex.links.filter(v => v !== targetVertexId) }; - - throw new Error( - `targetVertexId: ${targetVertexId} don't exists in vertex ${sourceVertexId}`, - ); + if (!vertex.links.includes(targetVertexId)) { + throw createError( + 'TARGET_VERTEX_DOES_NOT_EXIST', + targetVertexId, + sourceVertexId, + ); + } + return { links: vertex.links.filter(v => v !== targetVertexId) }; }); } @@ -138,8 +143,9 @@ class FileGraphIml implements FileGraphAbstract { const targetVertexExists = await this.findOne( vertex => vertex.id === sourceVertexId, ); - if (!targetVertexExists) - throw new Error(`Target vertex with ID "${targetVertexId}" not found`); + if (!targetVertexExists) { + throw createError('TARGET_VERTEX_NOT_FOUND', targetVertexId); + } return targetVertexExists.links.includes(targetVertexId); } @@ -148,13 +154,11 @@ class FileGraphIml implements FileGraphAbstract { vertexId: uuidType, maxLevel: number, ): Promise[]> { - if (maxLevel < 0) throw new Error('Level must be a non-negative integer.'); + if (maxLevel < 0) throw createError('NEGATIVE_LEVEL'); const startingVertex = await this.findOne( vertex => vertex.id === vertexId, ); - - if (!startingVertex) - throw new Error(`Vertex with id ${vertexId} not found.`); + if (!startingVertex) throw createError('VERTEX_NOT_FOUND', vertexId); const resultVertices: IVertexTree[] = []; const queue = [{ vertex: startingVertex, currentLevel: 0 }]; @@ -187,8 +191,9 @@ class FileGraphIml implements FileGraphAbstract { const targetVertexExists = await this.findOne( vertex => vertex.id === targetVertexId, ); - if (!targetVertexExists) - throw new Error(`Target vertex with ID "${targetVertexId}" not found`); + if (!targetVertexExists) { + throw createError('TARGET_VERTEX_NOT_FOUND', targetVertexId); + } const updateResult = await this.storageFile.updateLine(updater); return updateResult; diff --git a/lib/utils/errors.ts b/lib/utils/errors.ts new file mode 100644 index 0000000..b97cadd --- /dev/null +++ b/lib/utils/errors.ts @@ -0,0 +1,25 @@ +import { uuidType } from '../interfaces'; + +const ERRORS = { + VERTEX_NOT_FOUND: (id: uuidType) => `Vertex with id ${id} not found.`, + TARGET_VERTEX_NOT_FOUND: (id: uuidType) => + `Target vertex with ID "${id}" not found.`, + TARGET_VERTEX_DOES_NOT_EXIST: (targetId: uuidType, sourceId: uuidType) => + `targetVertexId: ${targetId} don't exist in vertex ${sourceId}`, + TARGET_VERTEX_ALREADY_EXISTS: (targetId: uuidType, sourceId: uuidType) => + `targetVertexId: ${targetId} already exists in vertex ${sourceId}`, + NEGATIVE_LEVEL: 'Level must be a non-negative integer.', +}; + +const createError = (type: keyof typeof ERRORS, ...args: any[]) => { + const errorTemplate: string | ((...args: any[]) => string) = ERRORS[type]; + if (!errorTemplate) throw new Error('Unknown error type'); + + return new Error( + typeof errorTemplate === 'function' + ? errorTemplate(...args) + : errorTemplate, + ); +}; + +export { createError }; diff --git a/lib/utils/index.ts b/lib/utils/index.ts index 4af1ae8..a31a4f8 100644 --- a/lib/utils/index.ts +++ b/lib/utils/index.ts @@ -1,3 +1,4 @@ export * from './uuid'; export * from './async-task-queue'; export * from './merge-vertex'; +export * from './errors'; diff --git a/test/graph.test.ts b/test/graph.test.ts index b0eda48..dde300c 100644 --- a/test/graph.test.ts +++ b/test/graph.test.ts @@ -2,6 +2,7 @@ import assert from 'node:assert'; import { before, describe, it } from 'node:test'; import { FileGraph, IUuidArray, uuidType } from 'lib'; import { writeFileSync } from 'node:fs'; +import { createError } from 'lib/utils'; const pathGraph = 'data.txt'; const graph = FileGraph(pathGraph); @@ -163,10 +164,7 @@ describe('Links operations', () => { await graph.findUpToLevel('A' as uuidType, -1); assert.fail('Expected error not thrown'); } catch (error) { - assert.strictEqual( - error.message, - 'Level must be a non-negative integer.', - ); + assert.strictEqual(error.message, createError('NEGATIVE_LEVEL').message); } }); @@ -177,7 +175,7 @@ describe('Links operations', () => { } catch (error) { assert.strictEqual( error.message, - 'Vertex with id NonExistentVertex not found.', + createError('VERTEX_NOT_FOUND', 'NonExistentVertex').message, ); } });