diff --git a/packages/api/src/modules/predicate/services.ts b/packages/api/src/modules/predicate/services.ts index 81754853e..c23496fa7 100644 --- a/packages/api/src/modules/predicate/services.ts +++ b/packages/api/src/modules/predicate/services.ts @@ -16,6 +16,7 @@ import { IPagination, Pagination, PaginationParams } from '@src/utils/pagination import { Predicate, User, Workspace } from '@models/index'; import GeneralError, { ErrorTypes } from '@utils/error/GeneralError'; +import { BadRequest } from '@utils/error'; import Internal from '@utils/error/Internal'; import App from '@src/server/app'; @@ -61,6 +62,32 @@ export class PredicateService implements IPredicateService { 'p.version', ]; + private static async validateUniqueName( + name: string, + workspaceId: string, + type: ErrorTypes, + predicateId?: string, + ): Promise { + const query = Predicate.createQueryBuilder('p') + .where('LOWER(p.name) = LOWER(:name)', { name }) + .andWhere('p.workspace_id = :workspaceId', { workspaceId }) + .andWhere('p.deletedAt IS NULL'); + + if (predicateId) { + query.andWhere('p.id != :predicateId', { predicateId }); + } + + const exists = await query.getOne(); + + if (exists) { + throw new BadRequest({ + type, + title: 'Predicate name already exists', + detail: `A predicate with name "${name}" already exists in this workspace`, + }); + } + } + filter(filter: IPredicateFilterParams) { this._filter = filter; return this; @@ -83,6 +110,12 @@ export class PredicateService implements IPredicateService { workspace: Workspace, ): Promise { try { + await PredicateService.validateUniqueName( + payload.name, + workspace.id, + ErrorTypes.Create, + ); + const userService = new UserService(); const config = JSON.parse(payload.configurable); @@ -132,6 +165,7 @@ export class PredicateService implements IPredicateService { // return predicate; } catch (e) { console.log(e); + if (e instanceof BadRequest) throw e; throw new Internal({ type: ErrorTypes.Internal, title: 'Error on predicate creation', @@ -399,7 +433,10 @@ export class PredicateService implements IPredicateService { payload?: Partial, ): Promise { try { - const currentPredicate = await this.findById(id); + const currentPredicate = await Predicate.findOne({ + where: { id }, + relations: ['workspace'], + }); if (!currentPredicate) { throw new NotFound({ @@ -409,6 +446,15 @@ export class PredicateService implements IPredicateService { }); } + if (payload?.name && payload.name !== currentPredicate.name) { + await PredicateService.validateUniqueName( + payload.name, + currentPredicate.workspace.id, + ErrorTypes.Update, + currentPredicate.id, + ); + } + const updatedPredicate = await Predicate.merge(currentPredicate, { name: payload?.name, description: payload?.description,