diff --git a/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.test.ts b/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.test.ts index 68d66af4da..40562ee302 100644 --- a/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.test.ts +++ b/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.test.ts @@ -2,10 +2,9 @@ import { ContactAttributeKey, Prisma } from "@prisma/client"; import { beforeEach, describe, expect, test, vi } from "vitest"; import { prisma } from "@formbricks/database"; import { TContactAttributeKey, TContactAttributeKeyType } from "@formbricks/types/contact-attribute-key"; -import { DatabaseError, OperationNotAllowedError } from "@formbricks/types/errors"; +import { DatabaseError } from "@formbricks/types/errors"; import { TContactAttributeKeyUpdateInput } from "../types/contact-attribute-keys"; import { - createContactAttributeKey, deleteContactAttributeKey, getContactAttributeKey, updateContactAttributeKey, @@ -101,79 +100,6 @@ describe("getContactAttributeKey", () => { }); }); -describe("createContactAttributeKey", () => { - const type: TContactAttributeKeyType = "custom"; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - test("should create and return a new contact attribute key", async () => { - const createdAttributeKey = { ...mockContactAttributeKey, id: "new_cak_id", key: mockKey, type }; - vi.mocked(prisma.contactAttributeKey.count).mockResolvedValue(5); // Below limit - vi.mocked(prisma.contactAttributeKey.create).mockResolvedValue(createdAttributeKey); - - const result = await createContactAttributeKey(mockEnvironmentId, mockKey, type); - - expect(result).toEqual(createdAttributeKey); - expect(prisma.contactAttributeKey.count).toHaveBeenCalledWith({ - where: { environmentId: mockEnvironmentId }, - }); - expect(prisma.contactAttributeKey.create).toHaveBeenCalledWith({ - data: { - key: mockKey, - name: mockKey, // As per implementation - type, - environment: { connect: { id: mockEnvironmentId } }, - }, - }); - }); - - test("should throw OperationNotAllowedError if max attribute classes reached", async () => { - // MAX_ATTRIBUTE_CLASSES_PER_ENVIRONMENT is mocked to 10 - vi.mocked(prisma.contactAttributeKey.count).mockResolvedValue(10); - - await expect(createContactAttributeKey(mockEnvironmentId, mockKey, type)).rejects.toThrow( - OperationNotAllowedError - ); - expect(prisma.contactAttributeKey.count).toHaveBeenCalledWith({ - where: { environmentId: mockEnvironmentId }, - }); - expect(prisma.contactAttributeKey.create).not.toHaveBeenCalled(); - }); - - test("should throw Prisma error if prisma.contactAttributeKey.count fails", async () => { - const errorMessage = "Prisma count error"; - const prismaError = new Prisma.PrismaClientKnownRequestError(errorMessage, { - code: "P1000", - clientVersion: "test", - }); - vi.mocked(prisma.contactAttributeKey.count).mockRejectedValue(prismaError); - - await expect(createContactAttributeKey(mockEnvironmentId, mockKey, type)).rejects.toThrow(prismaError); - }); - - test("should throw DatabaseError if Prisma create fails", async () => { - vi.mocked(prisma.contactAttributeKey.count).mockResolvedValue(5); // Below limit - const errorMessage = "Prisma create error"; - vi.mocked(prisma.contactAttributeKey.create).mockRejectedValue( - new Prisma.PrismaClientKnownRequestError(errorMessage, { code: "P2000", clientVersion: "test" }) - ); - - await expect(createContactAttributeKey(mockEnvironmentId, mockKey, type)).rejects.toThrow(DatabaseError); - await expect(createContactAttributeKey(mockEnvironmentId, mockKey, type)).rejects.toThrow(errorMessage); - }); - - test("should throw generic error if non-Prisma error occurs during create", async () => { - vi.mocked(prisma.contactAttributeKey.count).mockResolvedValue(5); - const errorMessage = "Some other error during create"; - vi.mocked(prisma.contactAttributeKey.create).mockRejectedValue(new Error(errorMessage)); - - await expect(createContactAttributeKey(mockEnvironmentId, mockKey, type)).rejects.toThrow(Error); - await expect(createContactAttributeKey(mockEnvironmentId, mockKey, type)).rejects.toThrow(errorMessage); - }); -}); - describe("deleteContactAttributeKey", () => { beforeEach(() => { vi.clearAllMocks(); diff --git a/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.ts b/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.ts index cccfebe037..b0c068a4db 100644 --- a/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.ts +++ b/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/[contactAttributeKeyId]/lib/contact-attribute-key.ts @@ -1,15 +1,10 @@ -import { MAX_ATTRIBUTE_CLASSES_PER_ENVIRONMENT } from "@/lib/constants"; import { validateInputs } from "@/lib/utils/validate"; import { Prisma } from "@prisma/client"; import { cache as reactCache } from "react"; import { prisma } from "@formbricks/database"; -import { ZId, ZString } from "@formbricks/types/common"; -import { - TContactAttributeKey, - TContactAttributeKeyType, - ZContactAttributeKeyType, -} from "@formbricks/types/contact-attribute-key"; -import { DatabaseError, OperationNotAllowedError } from "@formbricks/types/errors"; +import { ZId } from "@formbricks/types/common"; +import { TContactAttributeKey } from "@formbricks/types/contact-attribute-key"; +import { DatabaseError } from "@formbricks/types/errors"; import { TContactAttributeKeyUpdateInput, ZContactAttributeKeyUpdateInput, @@ -34,48 +29,6 @@ export const getContactAttributeKey = reactCache( } ); -export const createContactAttributeKey = async ( - environmentId: string, - key: string, - type: TContactAttributeKeyType -): Promise => { - validateInputs([environmentId, ZId], [key, ZString], [type, ZContactAttributeKeyType]); - - const contactAttributeKeysCount = await prisma.contactAttributeKey.count({ - where: { - environmentId, - }, - }); - - if (contactAttributeKeysCount >= MAX_ATTRIBUTE_CLASSES_PER_ENVIRONMENT) { - throw new OperationNotAllowedError( - `Maximum number of attribute classes (${MAX_ATTRIBUTE_CLASSES_PER_ENVIRONMENT}) reached for environment ${environmentId}` - ); - } - - try { - const contactAttributeKey = await prisma.contactAttributeKey.create({ - data: { - key, - name: key, - type, - environment: { - connect: { - id: environmentId, - }, - }, - }, - }); - - return contactAttributeKey; - } catch (error) { - if (error instanceof Prisma.PrismaClientKnownRequestError) { - throw new DatabaseError(error.message); - } - throw error; - } -}; - export const deleteContactAttributeKey = async ( contactAttributeKeyId: string ): Promise => { diff --git a/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/lib/contact-attribute-keys.ts b/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/lib/contact-attribute-keys.ts index 51b5df7961..f5c9372da2 100644 --- a/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/lib/contact-attribute-keys.ts +++ b/apps/web/modules/ee/contacts/api/v1/management/contact-attribute-keys/lib/contact-attribute-keys.ts @@ -3,6 +3,7 @@ import { validateInputs } from "@/lib/utils/validate"; import { Prisma } from "@prisma/client"; import { cache as reactCache } from "react"; import { prisma } from "@formbricks/database"; +import { PrismaErrorType } from "@formbricks/database/types/error"; import { ZId, ZString } from "@formbricks/types/common"; import { TContactAttributeKey, @@ -64,6 +65,10 @@ export const createContactAttributeKey = async ( return contactAttributeKey; } catch (error) { if (error instanceof Prisma.PrismaClientKnownRequestError) { + if (error.code === PrismaErrorType.UniqueConstraintViolation) { + throw new DatabaseError("Attribute key already exists"); + } + throw new DatabaseError(error.message); } throw error;