fix: unformatted db errors in contact attribute keys management v1 API (#6102)

This commit is contained in:
Piyush Gupta
2025-06-27 11:18:08 +05:30
committed by GitHub
parent 6328be220a
commit ac46850a24
3 changed files with 9 additions and 125 deletions

View File

@@ -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();

View File

@@ -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<TContactAttributeKey | null> => {
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<TContactAttributeKey> => {

View File

@@ -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;