mirror of
https://github.com/formbricks/formbricks.git
synced 2025-12-30 10:19:51 -06:00
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
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
import { getSurveys } from "@/app/api/v1/js/surveys";
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { getActionClasses } from "@formbricks/lib/services/actionClass";
|
||||
import { getPerson, selectPerson, transformPrismaPerson } from "@formbricks/lib/services/person";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/services/product";
|
||||
import { extendSession } from "@formbricks/lib/services/session";
|
||||
import { WEBAPP_URL } from "@formbricks/lib/constants";
|
||||
import { createAttributeClass, getAttributeClassByNameCached } from "@formbricks/lib/services/attributeClass";
|
||||
import { getPersonCached } from "@formbricks/lib/services/person";
|
||||
import { TJsState, ZJsPeopleAttributeInput } from "@formbricks/types/v1/js";
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { NextResponse } from "next/server";
|
||||
@@ -32,45 +30,25 @@ export async function POST(req: Request, { params }): Promise<NextResponse> {
|
||||
|
||||
const { environmentId, sessionId, key, value } = inputValidation.data;
|
||||
|
||||
const existingPerson = await getPerson(personId);
|
||||
const existingPerson = await getPersonCached(personId);
|
||||
|
||||
if (!existingPerson) {
|
||||
return responses.notFoundResponse("Person", personId, true);
|
||||
}
|
||||
|
||||
// find attribute class
|
||||
let attributeClass = await prisma.attributeClass.findUnique({
|
||||
where: {
|
||||
name_environmentId: {
|
||||
name: key,
|
||||
environmentId,
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
let attributeClass = await getAttributeClassByNameCached(environmentId, key);
|
||||
|
||||
// create new attribute class if not found
|
||||
if (attributeClass === null) {
|
||||
attributeClass = await prisma.attributeClass.create({
|
||||
data: {
|
||||
name: key,
|
||||
type: "code",
|
||||
environment: {
|
||||
connect: {
|
||||
id: environmentId,
|
||||
},
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
});
|
||||
attributeClass = await createAttributeClass(environmentId, key, "code");
|
||||
}
|
||||
|
||||
if (!attributeClass) {
|
||||
return responses.internalServerErrorResponse("Unable to create attribute class", true);
|
||||
}
|
||||
|
||||
// upsert attribute (update or create)
|
||||
const attribute = await prisma.attribute.upsert({
|
||||
await prisma.attribute.upsert({
|
||||
where: {
|
||||
attributeClassId_personId: {
|
||||
attributeClassId: attributeClass.id,
|
||||
@@ -93,40 +71,27 @@ export async function POST(req: Request, { params }): Promise<NextResponse> {
|
||||
},
|
||||
value,
|
||||
},
|
||||
select: {
|
||||
person: {
|
||||
select: selectPerson,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const person = transformPrismaPerson(attribute.person);
|
||||
// revalidate person
|
||||
revalidateTag(personId);
|
||||
|
||||
if (person) {
|
||||
// revalidate person
|
||||
revalidateTag(person.id);
|
||||
const syncRes = await fetch(`${WEBAPP_URL}/api/v1/js/sync`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
environmentId,
|
||||
personId,
|
||||
sessionId,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!syncRes.ok) {
|
||||
throw new Error("Unable to get latest state from sync");
|
||||
}
|
||||
|
||||
// get/create rest of the state
|
||||
const [session, surveys, noCodeActionClasses, product] = await Promise.all([
|
||||
extendSession(sessionId),
|
||||
getSurveys(environmentId, person),
|
||||
getActionClasses(environmentId),
|
||||
getProductByEnvironmentId(environmentId),
|
||||
]);
|
||||
const syncJson = await syncRes.json();
|
||||
const state: TJsState = syncJson.data;
|
||||
|
||||
if (!product) {
|
||||
return responses.notFoundResponse("ProductByEnvironmentId", environmentId, true);
|
||||
}
|
||||
|
||||
// return state
|
||||
const state: TJsState = {
|
||||
person,
|
||||
session,
|
||||
surveys,
|
||||
noCodeActionClasses: noCodeActionClasses.filter((actionClass) => actionClass.type === "noCode"),
|
||||
product,
|
||||
};
|
||||
return responses.successResponse({ ...state }, true);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { getSurveys } from "@/app/api/v1/js/surveys";
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { getActionClasses } from "@formbricks/lib/services/actionClass";
|
||||
import { WEBAPP_URL } from "@formbricks/lib/constants";
|
||||
import { deletePerson, selectPerson, transformPrismaPerson } from "@formbricks/lib/services/person";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/services/product";
|
||||
import { extendSession } from "@formbricks/lib/services/session";
|
||||
import { TJsState, ZJsPeopleUserIdInput } from "@formbricks/types/v1/js";
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { NextResponse } from "next/server";
|
||||
@@ -66,6 +63,7 @@ export async function POST(req: Request, { params }): Promise<NextResponse> {
|
||||
|
||||
// delete old person
|
||||
await deletePerson(personId);
|
||||
|
||||
returnedPerson = existingPerson;
|
||||
} else {
|
||||
// update person with userId
|
||||
@@ -99,26 +97,22 @@ export async function POST(req: Request, { params }): Promise<NextResponse> {
|
||||
revalidateTag(person.id);
|
||||
}
|
||||
|
||||
// get/create rest of the state
|
||||
const [session, surveys, noCodeActionClasses, product] = await Promise.all([
|
||||
extendSession(sessionId),
|
||||
getSurveys(environmentId, person),
|
||||
getActionClasses(environmentId),
|
||||
getProductByEnvironmentId(environmentId),
|
||||
]);
|
||||
const syncRes = await fetch(`${WEBAPP_URL}/api/v1/js/sync`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
environmentId,
|
||||
personId,
|
||||
sessionId,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!product) {
|
||||
return responses.notFoundResponse("ProductByEnvironmentId", environmentId, true);
|
||||
if (!syncRes.ok) {
|
||||
throw new Error("Unable to get latest state from sync");
|
||||
}
|
||||
|
||||
// return state
|
||||
const state: TJsState = {
|
||||
person,
|
||||
session,
|
||||
surveys,
|
||||
noCodeActionClasses: noCodeActionClasses.filter((actionClass) => actionClass.type === "noCode"),
|
||||
product,
|
||||
};
|
||||
const syncJson = await syncRes.json();
|
||||
const state: TJsState = syncJson.data;
|
||||
|
||||
return responses.successResponse({ ...state }, true);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
|
||||
@@ -2,6 +2,29 @@ import { prisma } from "@formbricks/database";
|
||||
import { selectSurvey } from "@formbricks/lib/services/survey";
|
||||
import { TPerson } from "@formbricks/types/v1/people";
|
||||
import { TSurvey } from "@formbricks/types/v1/surveys";
|
||||
import { unstable_cache } from "next/cache";
|
||||
|
||||
const getSurveysCacheTags = (environmentId: string, personId: string): string[] => [
|
||||
`env-${environmentId}-surveys`,
|
||||
`env-${environmentId}-product`,
|
||||
personId,
|
||||
];
|
||||
|
||||
const getSurveysCacheKey = (environmentId: string, personId: string): string[] => [
|
||||
`env-${environmentId}-person-${personId}-syncSurveys`,
|
||||
];
|
||||
|
||||
export const getSurveysCached = (environmentId: string, person: TPerson) =>
|
||||
unstable_cache(
|
||||
async () => {
|
||||
return await getSurveys(environmentId, person);
|
||||
},
|
||||
getSurveysCacheKey(environmentId, person.id),
|
||||
{
|
||||
tags: getSurveysCacheTags(environmentId, person.id),
|
||||
revalidate: 30 * 60,
|
||||
}
|
||||
)();
|
||||
|
||||
export const getSurveys = async (environmentId: string, person: TPerson): Promise<TSurvey[]> => {
|
||||
// get recontactDays from product
|
||||
|
||||
@@ -1,37 +1,21 @@
|
||||
import { getSurveys } from "@/app/api/v1/js/surveys";
|
||||
import { getSurveysCached } from "@/app/api/v1/js/surveys";
|
||||
import { responses } from "@/lib/api/response";
|
||||
import { transformErrorToDetails } from "@/lib/api/validator";
|
||||
import { getActionClasses } from "@formbricks/lib/services/actionClass";
|
||||
import { getEnvironment } from "@formbricks/lib/services/environment";
|
||||
import { createPerson, getPerson } from "@formbricks/lib/services/person";
|
||||
import { getProductByEnvironmentId } from "@formbricks/lib/services/product";
|
||||
import { createSession, extendSession, getSession } from "@formbricks/lib/services/session";
|
||||
import { getActionClassesCached } from "@formbricks/lib/services/actionClass";
|
||||
import { getEnvironmentCached } from "@formbricks/lib/services/environment";
|
||||
import { createPerson, getPersonCached } from "@formbricks/lib/services/person";
|
||||
import { getProductByEnvironmentIdCached } from "@formbricks/lib/services/product";
|
||||
import { createSession, extendSession, getSessionCached } from "@formbricks/lib/services/session";
|
||||
import { captureTelemetry } from "@formbricks/lib/telemetry";
|
||||
import { TJsState, ZJsSyncInput } from "@formbricks/types/v1/js";
|
||||
import { TPerson } from "@formbricks/types/v1/people";
|
||||
import { TSession } from "@formbricks/types/v1/sessions";
|
||||
import { unstable_cache } from "next/cache";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
const captureNewSessionTelemetry = async (jsVersion?: string): Promise<void> => {
|
||||
await captureTelemetry("session created", { jsVersion: jsVersion ?? "unknown" });
|
||||
};
|
||||
|
||||
const getEnvironmentCacheKey = (environmentId: string): string[] => ["environment", environmentId];
|
||||
const getPersonCacheKey = (personId: string): string[] => ["person", personId];
|
||||
const getSessionCacheKey = (sessionId: string): string[] => ["session", sessionId];
|
||||
const getSurveysCacheKey = (environmentId: string, personId: string): string[] => [
|
||||
"surveys",
|
||||
`env-${environmentId}-surveys`,
|
||||
`env-${environmentId}-product`,
|
||||
"person",
|
||||
personId,
|
||||
];
|
||||
const getProductCacheKey = (environmentId: string): string[] => [`env-${environmentId}-product`];
|
||||
const getActionClassesCacheKey = (environmentId: string): string[] => [`env-${environmentId}-actionClasses`];
|
||||
|
||||
const halfHourSeconds = 30 * 60;
|
||||
|
||||
export async function OPTIONS(): Promise<NextResponse> {
|
||||
return responses.successResponse({}, true);
|
||||
}
|
||||
@@ -54,17 +38,6 @@ export async function POST(req: Request): Promise<NextResponse> {
|
||||
const { environmentId, personId, sessionId } = inputValidation.data;
|
||||
|
||||
// check if environment exists
|
||||
const getEnvironmentCached = unstable_cache(
|
||||
async (environmentId: string) => {
|
||||
return await getEnvironment(environmentId);
|
||||
},
|
||||
getEnvironmentCacheKey(environmentId),
|
||||
{
|
||||
tags: getEnvironmentCacheKey(environmentId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const environment = await getEnvironmentCached(environmentId);
|
||||
|
||||
if (!environment) {
|
||||
@@ -82,39 +55,6 @@ export async function POST(req: Request): Promise<NextResponse> {
|
||||
// create a new session
|
||||
const session = await createSession(person.id);
|
||||
|
||||
const getSurveysCached = unstable_cache(
|
||||
async (environmentId: string, person: TPerson) => {
|
||||
return await getSurveys(environmentId, person);
|
||||
},
|
||||
getSurveysCacheKey(environmentId, person.id),
|
||||
{
|
||||
tags: getSurveysCacheKey(environmentId, person.id),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const getActionClassesCached = unstable_cache(
|
||||
async (environmentId: string) => {
|
||||
return await getActionClasses(environmentId);
|
||||
},
|
||||
getActionClassesCacheKey(environmentId),
|
||||
{
|
||||
tags: getActionClassesCacheKey(environmentId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const getProductByEnvironmentIdCached = unstable_cache(
|
||||
async (environmentId: string) => {
|
||||
return await getProductByEnvironmentId(environmentId);
|
||||
},
|
||||
getProductCacheKey(environmentId),
|
||||
{
|
||||
tags: getProductCacheKey(environmentId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
// get/create rest of the state
|
||||
|
||||
const [surveys, noCodeActionClasses, product] = await Promise.all([
|
||||
@@ -144,17 +84,6 @@ export async function POST(req: Request): Promise<NextResponse> {
|
||||
let person: TPerson | null;
|
||||
// check if person exists
|
||||
|
||||
const getPersonCached = unstable_cache(
|
||||
async (personId: string) => {
|
||||
return await getPerson(personId);
|
||||
},
|
||||
getPersonCacheKey(personId),
|
||||
{
|
||||
tags: getPersonCacheKey(personId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
person = await getPersonCached(personId);
|
||||
if (!person) {
|
||||
// create a new person
|
||||
@@ -164,39 +93,6 @@ export async function POST(req: Request): Promise<NextResponse> {
|
||||
// create a new session
|
||||
const session = await createSession(person.id);
|
||||
|
||||
const getSurveysCached = unstable_cache(
|
||||
async (environmentId: string, person: TPerson) => {
|
||||
return await getSurveys(environmentId, person);
|
||||
},
|
||||
getSurveysCacheKey(environmentId, person.id),
|
||||
{
|
||||
tags: getSurveysCacheKey(environmentId, person.id),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const getActionClassesCached = unstable_cache(
|
||||
async (environmentId: string) => {
|
||||
return await getActionClasses(environmentId);
|
||||
},
|
||||
getActionClassesCacheKey(environmentId),
|
||||
{
|
||||
tags: getActionClassesCacheKey(environmentId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const getProductByEnvironmentIdCached = unstable_cache(
|
||||
async (environmentId: string) => {
|
||||
return await getProductByEnvironmentId(environmentId);
|
||||
},
|
||||
getProductCacheKey(environmentId),
|
||||
{
|
||||
tags: getProductCacheKey(environmentId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const [surveys, noCodeActionClasses, product] = await Promise.all([
|
||||
getSurveysCached(environmentId, person),
|
||||
getActionClassesCached(environmentId),
|
||||
@@ -226,33 +122,11 @@ export async function POST(req: Request): Promise<NextResponse> {
|
||||
let person: TPerson | null;
|
||||
let session: TSession | null;
|
||||
|
||||
const getSessionCached = unstable_cache(
|
||||
async (sessionId: string) => {
|
||||
return await getSession(sessionId);
|
||||
},
|
||||
getSessionCacheKey(sessionId),
|
||||
{
|
||||
tags: getSessionCacheKey(sessionId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
session = await getSessionCached(sessionId);
|
||||
|
||||
if (!session) {
|
||||
// check if person exits
|
||||
|
||||
const getPersonCached = unstable_cache(
|
||||
async (personId: string) => {
|
||||
return await getPerson(personId);
|
||||
},
|
||||
getPersonCacheKey(personId),
|
||||
{
|
||||
tags: getPersonCacheKey(personId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
person = await getPersonCached(personId);
|
||||
|
||||
if (!person) {
|
||||
@@ -265,16 +139,6 @@ export async function POST(req: Request): Promise<NextResponse> {
|
||||
} else {
|
||||
// session exists
|
||||
// check if person exists (should always exist, but just in case)
|
||||
const getPersonCached = unstable_cache(
|
||||
async (personId: string) => {
|
||||
return await getPerson(personId);
|
||||
},
|
||||
getPersonCacheKey(personId),
|
||||
{
|
||||
tags: getPersonCacheKey(personId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
person = await getPersonCached(personId);
|
||||
if (!person) {
|
||||
@@ -300,39 +164,6 @@ export async function POST(req: Request): Promise<NextResponse> {
|
||||
}
|
||||
}
|
||||
|
||||
const getSurveysCached = unstable_cache(
|
||||
async (environmentId: string, person: TPerson) => {
|
||||
return await getSurveys(environmentId, person);
|
||||
},
|
||||
getSurveysCacheKey(environmentId, person.id),
|
||||
{
|
||||
tags: getSurveysCacheKey(environmentId, person.id),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const getActionClassesCached = unstable_cache(
|
||||
async (environmentId: string) => {
|
||||
return await getActionClasses(environmentId);
|
||||
},
|
||||
getActionClassesCacheKey(environmentId),
|
||||
{
|
||||
tags: getActionClassesCacheKey(environmentId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
const getProductByEnvironmentIdCached = unstable_cache(
|
||||
async (environmentId: string) => {
|
||||
return await getProductByEnvironmentId(environmentId);
|
||||
},
|
||||
getProductCacheKey(environmentId),
|
||||
{
|
||||
tags: getProductCacheKey(environmentId),
|
||||
revalidate: halfHourSeconds,
|
||||
}
|
||||
);
|
||||
|
||||
// get/create rest of the state
|
||||
const [surveys, noCodeActionClasses, product] = await Promise.all([
|
||||
getSurveysCached(environmentId, person),
|
||||
|
||||
@@ -3,11 +3,16 @@ import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { TActionClass, TActionClassInput, ZActionClassInput } from "@formbricks/types/v1/actionClasses";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { cache } from "react";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
import { cache } from "react";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
|
||||
const getActionClassesCacheTag = (environmentId: string): string => `env-${environmentId}-actionClasses`;
|
||||
const getActionClassesCacheKey = (environmentId: string): string[] => [
|
||||
getActionClassesCacheTag(environmentId),
|
||||
];
|
||||
|
||||
const select = {
|
||||
id: true,
|
||||
@@ -39,6 +44,18 @@ export const getActionClasses = cache(async (environmentId: string): Promise<TAc
|
||||
}
|
||||
});
|
||||
|
||||
export const getActionClassesCached = (environmentId: string) =>
|
||||
unstable_cache(
|
||||
async () => {
|
||||
return await getActionClasses(environmentId);
|
||||
},
|
||||
getActionClassesCacheKey(environmentId),
|
||||
{
|
||||
tags: getActionClassesCacheKey(environmentId),
|
||||
revalidate: 30 * 60, // 30 minutes
|
||||
}
|
||||
)();
|
||||
|
||||
export const deleteActionClass = async (
|
||||
environmentId: string,
|
||||
actionClassId: string
|
||||
@@ -54,7 +71,7 @@ export const deleteActionClass = async (
|
||||
if (result === null) throw new ResourceNotFoundError("Action", actionClassId);
|
||||
|
||||
// revalidate cache
|
||||
revalidateTag(`env-${environmentId}-actionClasses`);
|
||||
revalidateTag(getActionClassesCacheTag(environmentId));
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -84,7 +101,7 @@ export const createActionClass = async (
|
||||
});
|
||||
|
||||
// revalidate cache
|
||||
revalidateTag(`env-${environmentId}-actionClasses`);
|
||||
revalidateTag(getActionClassesCacheTag(environmentId));
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
@@ -115,7 +132,7 @@ export const updateActionClass = async (
|
||||
});
|
||||
|
||||
// revalidate cache
|
||||
revalidateTag(`env-${environmentId}-actionClasses`);
|
||||
revalidateTag(getActionClassesCacheTag(environmentId));
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import "server-only";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import {
|
||||
TAttributeClass,
|
||||
TAttributeClassType,
|
||||
TAttributeClassUpdateInput,
|
||||
ZAttributeClassUpdateInput,
|
||||
} from "@formbricks/types/v1/attributeClasses";
|
||||
@@ -10,6 +11,13 @@ import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { DatabaseError } from "@formbricks/types/v1/errors";
|
||||
import { cache } from "react";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
|
||||
const attributeClassesCacheTag = (environmentId: string): string => `env-${environmentId}-attributeClasses`;
|
||||
|
||||
const getAttributeClassesCacheKey = (environmentId: string): string[] => [
|
||||
attributeClassesCacheTag(environmentId),
|
||||
];
|
||||
|
||||
export const transformPrismaAttributeClass = (attributeClass: any): TAttributeClass | null => {
|
||||
if (attributeClass === null) {
|
||||
@@ -43,6 +51,7 @@ export const getAttributeClasses = cache(async (environmentId: string): Promise<
|
||||
throw new DatabaseError(`Database error when fetching attributeClasses for environment ${environmentId}`);
|
||||
}
|
||||
});
|
||||
|
||||
export const updatetAttributeClass = async (
|
||||
attributeClassId: string,
|
||||
data: Partial<TAttributeClassUpdateInput>
|
||||
@@ -60,12 +69,25 @@ export const updatetAttributeClass = async (
|
||||
});
|
||||
const transformedAttributeClass: TAttributeClass | null = transformPrismaAttributeClass(attributeClass);
|
||||
|
||||
revalidateTag(attributeClassesCacheTag(attributeClass.environmentId));
|
||||
return transformedAttributeClass;
|
||||
} catch (error) {
|
||||
throw new DatabaseError(`Database error when updating attribute class with id ${attributeClassId}`);
|
||||
}
|
||||
};
|
||||
|
||||
export const getAttributeClassByNameCached = async (environmentId: string, name: string) =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
return await getAttributeClassByName(environmentId, name);
|
||||
},
|
||||
getAttributeClassesCacheKey(environmentId),
|
||||
{
|
||||
tags: getAttributeClassesCacheKey(environmentId),
|
||||
revalidate: 30 * 60, // 30 minutes
|
||||
}
|
||||
)();
|
||||
|
||||
export const getAttributeClassByName = cache(
|
||||
async (environmentId: string, name: string): Promise<TAttributeClass | null> => {
|
||||
const attributeClass = await prisma.attributeClass.findFirst({
|
||||
@@ -77,3 +99,22 @@ export const getAttributeClassByName = cache(
|
||||
return transformPrismaAttributeClass(attributeClass);
|
||||
}
|
||||
);
|
||||
|
||||
export const createAttributeClass = async (
|
||||
environmentId: string,
|
||||
name: string,
|
||||
type: TAttributeClassType
|
||||
): Promise<TAttributeClass | null> => {
|
||||
const attributeClass = await prisma.attributeClass.create({
|
||||
data: {
|
||||
name,
|
||||
type,
|
||||
environment: {
|
||||
connect: {
|
||||
id: environmentId,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return transformPrismaAttributeClass(attributeClass);
|
||||
};
|
||||
|
||||
@@ -5,12 +5,13 @@ import {
|
||||
TDisplaysWithSurveyName,
|
||||
ZDisplayInput,
|
||||
} from "@formbricks/types/v1/displays";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
|
||||
import { transformPrismaPerson } from "./person";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { revalidateTag } from "next/cache";
|
||||
import { cache } from "react";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { transformPrismaPerson } from "./person";
|
||||
|
||||
const selectDisplay = {
|
||||
id: true,
|
||||
@@ -65,6 +66,10 @@ export const createDisplay = async (displayInput: TDisplayInput): Promise<TDispl
|
||||
person: displayPrisma.person ? transformPrismaPerson(displayPrisma.person) : null,
|
||||
};
|
||||
|
||||
if (displayInput.personId) {
|
||||
revalidateTag(displayInput.personId);
|
||||
}
|
||||
|
||||
return display;
|
||||
} catch (error) {
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
|
||||
@@ -8,6 +8,7 @@ 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]);
|
||||
@@ -38,6 +39,18 @@ export const getEnvironment = cache(async (environmentId: string): Promise<TEnvi
|
||||
}
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { DatabaseError, ResourceNotFoundError } from "@formbricks/types/v1/errors";
|
||||
import { TPerson } from "@formbricks/types/v1/people";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
import { cache } from "react";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { getAttributeClassByName } from "./attributeClass";
|
||||
import { revalidateTag } from "next/cache";
|
||||
|
||||
export const selectPerson = {
|
||||
id: true,
|
||||
@@ -86,6 +86,20 @@ export const getPerson = cache(async (personId: string): Promise<TPerson | null>
|
||||
}
|
||||
});
|
||||
|
||||
const getPersonCacheKey = (personId: string): string[] => [personId];
|
||||
|
||||
export const getPersonCached = async (personId: string) =>
|
||||
await unstable_cache(
|
||||
async () => {
|
||||
return await getPerson(personId);
|
||||
},
|
||||
getPersonCacheKey(personId),
|
||||
{
|
||||
tags: getPersonCacheKey(personId),
|
||||
revalidate: 30 * 60, // 30 minutes
|
||||
}
|
||||
)();
|
||||
|
||||
export const getPeople = cache(async (environmentId: string): Promise<TPerson[]> => {
|
||||
validateInputs([environmentId, ZId]);
|
||||
try {
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
import "server-only";
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { z } from "zod";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { ZProduct, ZProductUpdateInput } from "@formbricks/types/v1/product";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { DatabaseError, ValidationError } from "@formbricks/types/v1/errors";
|
||||
import type { TProduct, TProductUpdateInput } from "@formbricks/types/v1/product";
|
||||
import { ZProduct, ZProductUpdateInput } from "@formbricks/types/v1/product";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
import { cache } from "react";
|
||||
import "server-only";
|
||||
import { z } from "zod";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { revalidateTag } from "next/cache";
|
||||
|
||||
const getProductCacheTag = (environmentId: string): string => `env-${environmentId}-product`;
|
||||
const getProductCacheKey = (environmentId: string): string[] => [getProductCacheTag(environmentId)];
|
||||
|
||||
const selectProduct = {
|
||||
id: true,
|
||||
@@ -73,6 +76,18 @@ export const getProductByEnvironmentId = cache(async (environmentId: string): Pr
|
||||
}
|
||||
});
|
||||
|
||||
export const getProductByEnvironmentIdCached = (environmentId: string) =>
|
||||
unstable_cache(
|
||||
async () => {
|
||||
return await getProductByEnvironmentId(environmentId);
|
||||
},
|
||||
getProductCacheKey(environmentId),
|
||||
{
|
||||
tags: getProductCacheKey(environmentId),
|
||||
revalidate: 30 * 60, // 30 minutes
|
||||
}
|
||||
)();
|
||||
|
||||
export const updateProduct = async (
|
||||
productId: string,
|
||||
inputProduct: Partial<TProductUpdateInput>
|
||||
@@ -100,7 +115,7 @@ export const updateProduct = async (
|
||||
|
||||
product.environments.forEach((environment) => {
|
||||
// revalidate environment cache
|
||||
revalidateTag(`env-${environment.id}-product`);
|
||||
revalidateTag(getProductCacheTag(environment.id));
|
||||
});
|
||||
|
||||
return product;
|
||||
@@ -142,7 +157,8 @@ export const deleteProduct = cache(async (productId: string): Promise<TProduct>
|
||||
if (product) {
|
||||
product.environments.forEach((environment) => {
|
||||
// revalidate product cache
|
||||
revalidateTag(`env-${environment.id}-product`);
|
||||
revalidateTag(getProductCacheTag(environment.id));
|
||||
revalidateTag(environment.id);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@formbricks/database";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { DatabaseError } from "@formbricks/types/v1/errors";
|
||||
import { TSession, TSessionWithActions } from "@formbricks/types/v1/sessions";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { revalidateTag, unstable_cache } from "next/cache";
|
||||
import { cache } from "react";
|
||||
import { validateInputs } from "../utils/validate";
|
||||
import { ZId } from "@formbricks/types/v1/environment";
|
||||
import { revalidateTag } from "next/cache";
|
||||
|
||||
const select = {
|
||||
id: true,
|
||||
@@ -40,6 +40,18 @@ export const getSession = async (sessionId: string): Promise<TSession | null> =>
|
||||
}
|
||||
};
|
||||
|
||||
export const getSessionCached = (sessionId: string) =>
|
||||
unstable_cache(
|
||||
async () => {
|
||||
return await getSession(sessionId);
|
||||
},
|
||||
[sessionId],
|
||||
{
|
||||
tags: [sessionId],
|
||||
revalidate: 30 * 60, // 30 minutes
|
||||
}
|
||||
)();
|
||||
|
||||
export const getSessionWithActionsOfPerson = async (
|
||||
personId: string
|
||||
): Promise<TSessionWithActions[] | null> => {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
import z from "zod";
|
||||
|
||||
export const ZAttributeClassType = z.enum(["code", "noCode", "automatic"]);
|
||||
|
||||
export type TAttributeClassType = z.infer<typeof ZAttributeClassType>;
|
||||
|
||||
export const ZAttributeClass = z.object({
|
||||
id: z.string().cuid2(),
|
||||
createdAt: z.date(),
|
||||
updatedAt: z.date(),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
type: z.enum(["code", "noCode", "automatic"]),
|
||||
type: ZAttributeClassType,
|
||||
environmentId: z.string(),
|
||||
archived: z.boolean(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user