mirror of
https://github.com/formbricks/formbricks.git
synced 2026-01-06 00:49:42 -06:00
fix: unformatted db errors in contact attribute keys management v1 API (#6102)
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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> => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user