Files
formbricks/packages/lib/services/environment.ts
Matti Nannt e86b80cf0f chore: enable caching in all js endpoints to reduce database calls (#821)
* Move cached functions to services, add new caching to set-attribute

* update set-user-id route

* move remaining cache functions to services, simplify revalidation and keys

* simplify set-attribute further

* fix build errors

* comment out prisma client logging
2023-09-16 20:53:31 +09:00

199 lines
5.2 KiB
TypeScript

import "server-only";
import { prisma } from "@formbricks/database";
import { z } from "zod";
import { Prisma, EnvironmentType } from "@prisma/client";
import { DatabaseError, ResourceNotFoundError, ValidationError } from "@formbricks/types/v1/errors";
import type { TEnvironment, TEnvironmentId, TEnvironmentUpdateInput } from "@formbricks/types/v1/environment";
import { populateEnvironment } from "../utils/createDemoProductHelpers";
import { ZEnvironment, ZEnvironmentUpdateInput, ZId } from "@formbricks/types/v1/environment";
import { validateInputs } from "../utils/validate";
import { cache } from "react";
import { unstable_cache } from "next/cache";
export const getEnvironment = cache(async (environmentId: string): Promise<TEnvironment | null> => {
validateInputs([environmentId, ZId]);
let environmentPrisma;
try {
environmentPrisma = await prisma.environment.findUnique({
where: {
id: environmentId,
},
});
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError("Database operation failed");
}
throw error;
}
try {
const environment = ZEnvironment.parse(environmentPrisma);
return environment;
} catch (error) {
if (error instanceof z.ZodError) {
console.error(JSON.stringify(error.errors, null, 2));
}
throw new ValidationError("Data validation of environment failed");
}
});
export const getEnvironmentCached = (environmentId: string) =>
unstable_cache(
async () => {
return await getEnvironment(environmentId);
},
[environmentId],
{
tags: [environmentId],
revalidate: 30 * 60, // 30 minutes
}
)();
export const getEnvironments = cache(async (productId: string): Promise<TEnvironment[]> => {
validateInputs([productId, ZId]);
let productPrisma;
try {
productPrisma = await prisma.product.findFirst({
where: {
id: productId,
},
include: {
environments: true,
},
});
if (!productPrisma) {
throw new ResourceNotFoundError("Product", productId);
}
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError("Database operation failed");
}
throw error;
}
const environments: TEnvironment[] = [];
for (let environment of productPrisma.environments) {
let targetEnvironment: TEnvironment = ZEnvironment.parse(environment);
environments.push(targetEnvironment);
}
try {
return environments;
} catch (error) {
if (error instanceof z.ZodError) {
console.error(JSON.stringify(error.errors, null, 2));
}
throw new ValidationError("Data validation of environments array failed");
}
});
export const updateEnvironment = async (
environmentId: string,
data: Partial<TEnvironmentUpdateInput>
): Promise<TEnvironment> => {
validateInputs([environmentId, ZId], [data, ZEnvironmentUpdateInput.partial()]);
const newData = { ...data, updatedAt: new Date() };
let updatedEnvironment;
try {
updatedEnvironment = await prisma.environment.update({
where: {
id: environmentId,
},
data: newData,
});
return updatedEnvironment;
} catch (error) {
if (error instanceof Prisma.PrismaClientKnownRequestError) {
throw new DatabaseError("Database operation failed");
}
throw error;
}
};
export const getEnvironmentByUser = async (user: any): Promise<TEnvironment | TEnvironmentId | null> => {
const firstMembership = await prisma.membership.findFirst({
where: {
userId: user.id,
},
select: {
teamId: true,
},
});
if (!firstMembership) {
// create a new team and return environment
const membership = await prisma.membership.create({
data: {
accepted: true,
role: "owner",
user: { connect: { id: user.id } },
team: {
create: {
name: `${user.name}'s Team`,
products: {
create: {
name: "My Product",
environments: {
create: [
{
type: EnvironmentType.production,
...populateEnvironment,
},
{
type: EnvironmentType.development,
...populateEnvironment,
},
],
},
},
},
},
},
},
include: {
team: {
include: {
products: {
include: {
environments: true,
},
},
},
},
},
});
const environment = membership.team.products[0].environments[0];
return environment;
}
const firstProduct = await prisma.product.findFirst({
where: {
teamId: firstMembership.teamId,
},
select: {
id: true,
},
});
if (firstProduct === null) {
return null;
}
const firstEnvironment = await prisma.environment.findFirst({
where: {
productId: firstProduct.id,
type: "production",
},
select: {
id: true,
},
});
if (firstEnvironment === null) {
return null;
}
return firstEnvironment;
};