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:
Matti Nannt
2023-09-16 20:53:31 +09:00
committed by GitHub
parent b04acae0ba
commit e86b80cf0f
12 changed files with 215 additions and 280 deletions

View File

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

View File

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

View File

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

View File

@@ -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),

View File

@@ -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) {

View File

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

View File

@@ -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) {

View File

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

View File

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

View File

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

View File

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

View File

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