fix: create prisma client singleton with immediately invoked function (#12267)
This commit is contained in:
parent
0d1b6ea5b2
commit
e695f75113
|
@ -1,7 +1,7 @@
|
|||
import type { NextMiddleware } from "next-api-middleware";
|
||||
|
||||
import { CONSOLE_URL } from "@calcom/lib/constants";
|
||||
import { customPrisma } from "@calcom/prisma";
|
||||
import prisma, { customPrisma } from "@calcom/prisma";
|
||||
|
||||
const LOCAL_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL;
|
||||
|
||||
|
@ -12,32 +12,41 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => {
|
|||
} = req;
|
||||
// If no custom api Id is provided, attach to request the regular cal.com prisma client.
|
||||
if (!key) {
|
||||
req.prisma = customPrisma();
|
||||
req.prisma = prisma;
|
||||
await next();
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have a key, we check if the deployment matching the key, has a databaseUrl value set.
|
||||
const databaseUrl = await fetch(`${LOCAL_CONSOLE_URL}/api/deployments/database?key=${key}`)
|
||||
.then((res) => res.json())
|
||||
.then((res) => res.databaseUrl);
|
||||
try {
|
||||
// If we have a key, we check if the deployment matching the key, has a databaseUrl value set.
|
||||
const databaseUrl = await fetch(`${LOCAL_CONSOLE_URL}/api/deployments/database?key=${key}`)
|
||||
.then((res) => res.json())
|
||||
.then((res) => res.databaseUrl);
|
||||
|
||||
if (!databaseUrl) {
|
||||
res.status(400).json({ error: "no databaseUrl set up at your instance yet" });
|
||||
return;
|
||||
}
|
||||
req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } });
|
||||
/* @note:
|
||||
if (!databaseUrl) {
|
||||
res.status(400).json({ error: "no databaseUrl set up at your instance yet" });
|
||||
return;
|
||||
}
|
||||
req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } });
|
||||
/* @note:
|
||||
In order to skip verifyApiKey for customPrisma requests,
|
||||
we pass isAdmin true, and userId 0, if we detect them later,
|
||||
we skip verifyApiKey logic and pass onto next middleware instead.
|
||||
*/
|
||||
req.isAdmin = true;
|
||||
req.isCustomPrisma = true;
|
||||
// We don't need the key from here and on. Prevents unrecognized key errors.
|
||||
delete req.query.key;
|
||||
await next();
|
||||
await req.prisma.$disconnect();
|
||||
// @ts-expect-error testing
|
||||
delete req.prisma;
|
||||
req.isAdmin = true;
|
||||
req.isCustomPrisma = true;
|
||||
// We don't need the key from here and on. Prevents unrecognized key errors.
|
||||
delete req.query.key;
|
||||
await next();
|
||||
await req.prisma.$disconnect();
|
||||
// @ts-expect-error testing
|
||||
delete req.prisma;
|
||||
} catch (err) {
|
||||
if (req.prisma) {
|
||||
await req.prisma.$disconnect();
|
||||
// @ts-expect-error testing
|
||||
delete req.prisma;
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -6,66 +6,54 @@ import { bookingReferenceMiddleware } from "./middleware";
|
|||
|
||||
const prismaOptions: Prisma.PrismaClientOptions = {};
|
||||
|
||||
const globalForPrisma = global as unknown as {
|
||||
prismaWithoutClientExtensions: PrismaClientWithoutExtension;
|
||||
prismaWithClientExtensions: PrismaClientWithExtensions;
|
||||
};
|
||||
|
||||
if (!!process.env.NEXT_PUBLIC_DEBUG) prismaOptions.log = ["query", "error", "warn"];
|
||||
|
||||
// Prevents flooding with idle connections
|
||||
const prismaWithoutClientExtensions =
|
||||
globalForPrisma.prismaWithoutClientExtensions || new PrismaClientWithoutExtension(prismaOptions);
|
||||
|
||||
export const customPrisma = (options?: Prisma.PrismaClientOptions) =>
|
||||
new PrismaClientWithoutExtension({ ...prismaOptions, ...options }).$extends(withAccelerate());
|
||||
|
||||
// If any changed on middleware server restart is required
|
||||
// TODO: Migrate it to $extends
|
||||
bookingReferenceMiddleware(prismaWithoutClientExtensions);
|
||||
export const prisma = (function () {
|
||||
// Prevents flooding with idle connections
|
||||
const prismaWithoutClientExtensions = new PrismaClientWithoutExtension(prismaOptions);
|
||||
// If any changed on middleware server restart is required
|
||||
// TODO: Migrate it to $extends
|
||||
bookingReferenceMiddleware(prismaWithoutClientExtensions);
|
||||
|
||||
// FIXME: Due to some reason, there are types failing in certain places due to the $extends. Fix it and then enable it
|
||||
// Specifically we get errors like `Type 'string | Date | null | undefined' is not assignable to type 'Exact<string | Date | null | undefined, string | Date | null | undefined>'`
|
||||
const prismaWithClientExtensions = prismaWithoutClientExtensions
|
||||
//
|
||||
.$extends(withAccelerate());
|
||||
// .$extends({
|
||||
// query: {
|
||||
// $allModels: {
|
||||
// async $allOperations({ model, operation, args, query }) {
|
||||
// const start = performance.now();
|
||||
// /* your custom logic here */
|
||||
// const res = await query(args);
|
||||
// const end = performance.now();
|
||||
// logger.debug("Query Perf: ", `${model}.${operation} took ${(end - start).toFixed(2)}ms\n`);
|
||||
// return res;
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// .$extends({
|
||||
// name: "teamUpdateWithMetadata",
|
||||
// query: {
|
||||
// team: {
|
||||
// async update({ model, operation, args, query }) {
|
||||
// if (args.data.metadata) {
|
||||
// // Prepare args.data with merged metadata
|
||||
// }
|
||||
// return query(args);
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
// FIXME: Due to some reason, there are types failing in certain places due to the $extends. Fix it and then enable it
|
||||
// Specifically we get errors like `Type 'string | Date | null | undefined' is not assignable to type 'Exact<string | Date | null | undefined, string | Date | null | undefined>'`
|
||||
const prismaWithClientExtensions = prismaWithoutClientExtensions
|
||||
//
|
||||
.$extends(withAccelerate());
|
||||
// .$extends({
|
||||
// query: {
|
||||
// $allModels: {
|
||||
// async $allOperations({ model, operation, args, query }) {
|
||||
// const start = performance.now();
|
||||
// /* your custom logic here */
|
||||
// const res = await query(args);
|
||||
// const end = performance.now();
|
||||
// logger.debug("Query Perf: ", `${model}.${operation} took ${(end - start).toFixed(2)}ms\n`);
|
||||
// return res;
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// .$extends({
|
||||
// name: "teamUpdateWithMetadata",
|
||||
// query: {
|
||||
// team: {
|
||||
// async update({ model, operation, args, query }) {
|
||||
// if (args.data.metadata) {
|
||||
// // Prepare args.data with merged metadata
|
||||
// }
|
||||
// return query(args);
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// })
|
||||
return prismaWithClientExtensions;
|
||||
})();
|
||||
|
||||
export const prisma = globalForPrisma.prismaWithClientExtensions || prismaWithClientExtensions;
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
globalForPrisma.prismaWithoutClientExtensions = prismaWithoutClientExtensions;
|
||||
globalForPrisma.prismaWithClientExtensions = prisma;
|
||||
}
|
||||
|
||||
type PrismaClientWithExtensions = typeof prismaWithClientExtensions;
|
||||
export type PrismaClient = PrismaClientWithExtensions;
|
||||
export type PrismaClient = typeof prisma;
|
||||
export default prisma;
|
||||
|
||||
export * from "./selects";
|
||||
|
|
Loading…
Reference in New Issue
Block a user