feat: Setups prisma accelerate (#11324)

pull/11450/head
Omar López 2023-09-19 14:02:57 -07:00 committed by GitHub
parent 21a0b67b5a
commit 560ec244e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 150 additions and 49 deletions

View File

@ -1,7 +1,7 @@
import { PrismaClient } from "@prisma/client";
import type { NextMiddleware } from "next-api-middleware";
import { CONSOLE_URL } from "@calcom/lib/constants";
import { customPrisma } from "@calcom/prisma";
const LOCAL_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL;
@ -12,7 +12,7 @@ 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 = new PrismaClient();
req.prisma = customPrisma();
await next();
return;
}
@ -26,7 +26,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => {
res.status(400).json({ error: "no databaseUrl set up at your instance yet" });
return;
}
req.prisma = new PrismaClient({ datasources: { db: { url: databaseUrl } } });
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,

2
apps/api/next.d.ts vendored
View File

@ -1,7 +1,7 @@
import type { Session } from "next-auth";
import type { NextApiRequest as BaseNextApiRequest } from "next/types";
import type { PrismaClient } from "@calcom/prisma/client";
import type { PrismaClient } from "@calcom/prisma";
export type * from "next/types";

View File

@ -2,7 +2,7 @@ import type { NextApiRequest } from "next";
import { HttpError } from "@calcom/lib/http-error";
import { defaultResponder } from "@calcom/lib/server";
import type { PrismaClient } from "@calcom/prisma/client";
import type { PrismaClient } from "@calcom/prisma";
import { schemaEventTypeReadPublic } from "~/lib/validations/event-type";
import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId";

View File

@ -23,6 +23,7 @@ const MOCK_DATA: Mockdata = {
describe("Check Booking Limits Tests", () => {
it("Should return no errors", async () => {
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.booking.count.mockResolvedValue(0);
expect(
checkBookingLimits(MOCK_DATA.bookingLimits, MOCK_DATA.startDate, MOCK_DATA.id)
@ -30,6 +31,7 @@ describe("Check Booking Limits Tests", () => {
});
it("Should throw an error", async () => {
// Mock there being two a day
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.booking.count.mockResolvedValue(2);
expect(
checkBookingLimits(MOCK_DATA.bookingLimits, MOCK_DATA.startDate, MOCK_DATA.id)
@ -37,6 +39,7 @@ describe("Check Booking Limits Tests", () => {
});
it("Should pass with multiple booking limits", async () => {
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.booking.count.mockResolvedValue(0);
expect(
checkBookingLimits(
@ -50,6 +53,7 @@ describe("Check Booking Limits Tests", () => {
).resolves.toBeTruthy();
});
it("Should pass with multiple booking limits with one undefined", async () => {
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.booking.count.mockResolvedValue(0);
expect(
checkBookingLimits(
@ -63,6 +67,7 @@ describe("Check Booking Limits Tests", () => {
).resolves.toBeTruthy();
});
it("Should handle mutiple limits correctly", async () => {
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.booking.count.mockResolvedValue(1);
expect(
checkBookingLimit({
@ -72,6 +77,7 @@ describe("Check Booking Limits Tests", () => {
eventId: MOCK_DATA.id,
})
).resolves.not.toThrow();
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.booking.count.mockResolvedValue(3);
expect(
checkBookingLimit({

View File

@ -13,6 +13,7 @@ import { getDate, getGoogleCalendarCredential, createBookingScenario } from "../
// TODO: Mock properly
prismaMock.eventType.findUnique.mockResolvedValue(null);
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.user.findMany.mockResolvedValue([]);
vi.mock("@calcom/lib/constants", () => ({

View File

@ -10,6 +10,7 @@ import type { CompleteEventType, CompleteWorkflowsOnEventTypes } from "@calcom/p
const mockFindFirstEventType = (data?: Partial<CompleteEventType>) => {
const eventType = buildEventType(data as Partial<EventType>);
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.eventType.findFirst.mockResolvedValue(eventType as EventType);
return eventType;
};
@ -30,6 +31,7 @@ describe("handleChildrenEventTypes", () => {
describe("Shortcircuits", () => {
it("Returns message 'No managed event type'", async () => {
mockFindFirstEventType();
// @ts-expect-error Prisma v5 typings are not yet available
const result = await updateChildrenEventTypes({
eventTypeId: 1,
oldEventType: { children: [], team: { name: "" } },
@ -38,6 +40,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(result.newUserIds).toEqual(undefined);
@ -57,6 +60,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(result.newUserIds).toEqual(undefined);
@ -82,6 +86,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(result.newUserIds).toEqual(undefined);
@ -111,6 +116,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(prismaMock.eventType.create).toHaveBeenCalledWith({
@ -157,6 +163,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: "somestring",
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(prismaMock.eventType.update).toHaveBeenCalledWith({
@ -190,6 +197,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(result.newUserIds).toEqual([]);
@ -214,6 +222,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
// Have been called
@ -244,6 +253,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(prismaMock.eventType.create).toHaveBeenCalledWith({
@ -290,6 +300,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(prismaMock.eventType.update).toHaveBeenCalledWith({
@ -348,6 +359,7 @@ describe("handleChildrenEventTypes", () => {
currentUserId: 1,
hashedLink: undefined,
connectedLink: null,
// @ts-expect-error Prisma v5 typings are not yet available
prisma: prismaMock,
});
expect(prismaMock.eventType.create).toHaveBeenCalledWith({

View File

@ -36,6 +36,7 @@ it("can find lucky user with maximize availability", async () => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
prismaMock.user.findMany.mockResolvedValue(users);
// @ts-expect-error Prisma v5 typings are not yet available
prismaMock.booking.findMany.mockResolvedValue([]);
await expect(

View File

@ -176,9 +176,11 @@ async function addBookings(bookings: InputBooking[], eventTypes: InputEventType[
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
prismaMock.booking.findMany.mockImplementation((findManyArg) => {
// @ts-expect-error Prisma v5 breaks this
const where = findManyArg?.where || {};
return new Promise((resolve) => {
resolve(
// @ts-expect-error Prisma v5 breaks this
bookings
// We can improve this filter to support the entire where clause but that isn't necessary yet. So, handle what we know we pass to `findMany` and is needed
.filter((booking) => {
@ -222,6 +224,7 @@ async function addBookings(bookings: InputBooking[], eventTypes: InputEventType[
async function addWebhooks(webhooks: InputWebhook[]) {
prismaMock.webhook.findMany.mockResolvedValue(
// @ts-expect-error Prisma v5 breaks this
webhooks.map((webhook) => {
return {
...webhook,
@ -242,13 +245,16 @@ function addUsers(users: InputUser[]) {
// @ts-ignore
prismaMock.user.findUniqueOrThrow.mockImplementation((findUniqueArgs) => {
return new Promise((resolve) => {
// @ts-expect-error Prisma v5 breaks this
resolve({
// @ts-expect-error Prisma v5 breaks this
email: `IntegrationTestUser${findUniqueArgs?.where.id}@example.com`,
} as unknown as PrismaUser);
});
});
prismaMock.user.findMany.mockResolvedValue(
// @ts-expect-error Prisma v5 breaks this
users.map((user) => {
return {
...user,
@ -265,6 +271,7 @@ export async function createBookingScenario(data: ScenarioData) {
const eventType = addEventTypes(data.eventTypes, data.users);
if (data.apps) {
// @ts-expect-error Prisma v5 breaks this
prismaMock.app.findMany.mockResolvedValue(data.apps as PrismaApp[]);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
@ -562,9 +569,8 @@ export function getScenarioData({
}
export function mockEnableEmailFeature() {
// @ts-expect-error Prisma v5 breaks this
prismaMock.feature.findMany.mockResolvedValue([
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
{
slug: "emails",
// It's a kill switch
@ -574,8 +580,7 @@ export function mockEnableEmailFeature() {
}
export function mockNoTranslations() {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
// @ts-expect-error FIXME
i18nMock.getTranslation.mockImplementation(() => {
return new Promise((resolve) => {
const identityFn = (key: string) => key;

View File

@ -74,6 +74,7 @@ test("Calendar Cache is being called", async () => {
// First call won't have a cache
.mockResolvedValueOnce(null)
// Second call will have a cache
// @ts-expect-error expects a "null" here due to previous call
.mockResolvedValueOnce(calendarCacheResponse);
// prismaMock.calendarCache.create.mock.

View File

@ -50,6 +50,8 @@ export async function getServerSession(options: {
where: {
email: token.email.toLowerCase(),
},
// TODO: Re-enable once we get confirmation from compliance that this is okay.
// cacheStrategy: { ttl: 60, swr: 1 },
});
if (!user) {

View File

@ -1,13 +1,8 @@
import type {
Account,
IdentityProvider,
Prisma,
PrismaClient,
User,
VerificationToken,
} from "@prisma/client";
import type { Account, IdentityProvider, Prisma, User, VerificationToken } from "@prisma/client";
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library";
import type { PrismaClient } from "@calcom/prisma";
import { identityProviderNameMap } from "./identityProviderNameMap";
/** @return { import("next-auth/adapters").Adapter } */

View File

@ -82,7 +82,8 @@ const getUserAdminTeams = async ({
name: user.name || "me",
logo: user?.avatar === "" ? null : user?.avatar,
isUser: true,
...(includeCredentials && { credentials: user.credentials }),
credentials: includeCredentials ? [] : user.credentials,
parent: null,
};
teams.unshift(userObject);
}

View File

@ -1,5 +1,6 @@
import type { Prisma } from "@prisma/client";
import { PrismaClient as PrismaClientWithoutExtension } from "@prisma/client";
import { withAccelerate } from "@prisma/extension-accelerate";
import { bookingReferenceMiddleware } from "./middleware";
@ -14,8 +15,8 @@ if (!!process.env.NEXT_PUBLIC_DEBUG) prismaOptions.log = ["query", "error", "war
const prismaWithoutClientExtensions = new PrismaClientWithoutExtension(prismaOptions);
export const customPrisma = (options: Prisma.PrismaClientOptions) =>
new PrismaClientWithoutExtension({ ...prismaOptions, ...options });
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
@ -23,7 +24,10 @@ 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({
const prismaWithClientExtensions = prismaWithoutClientExtensions
//
.$extends(withAccelerate());
// .$extends({
// query: {
// $allModels: {
// async $allOperations({ model, operation, args, query }) {
@ -51,7 +55,7 @@ bookingReferenceMiddleware(prismaWithoutClientExtensions);
// },
// })
const prismaWithClientExtensions = prismaWithoutClientExtensions;
// const prismaWithClientExtensions = prismaWithoutClientExtensions;
export const prisma = (globalThis.prisma as typeof prismaWithClientExtensions) || prismaWithClientExtensions;
@ -59,7 +63,7 @@ if (process.env.NODE_ENV !== "production") {
globalThis.prisma = prisma;
}
export type PrismaClient = typeof prisma;
export type PrismaClient = typeof prismaWithClientExtensions;
export default prisma;
export * from "./selects";

View File

@ -24,9 +24,10 @@
},
"dependencies": {
"@calcom/lib": "*",
"@prisma/client": "^5.0.0",
"@prisma/generator-helper": "^5.0.0",
"prisma": "^5.0.0",
"@prisma/client": "^5.2.0",
"@prisma/extension-accelerate": "^0.6.2",
"@prisma/generator-helper": "^5.2.0",
"prisma": "^5.2.0",
"ts-node": "^10.9.1",
"zod": "^3.22.2",
"zod-prisma": "^0.5.4"

118
yarn.lock
View File

@ -3354,7 +3354,7 @@ __metadata:
"@calcom/ui": "*"
"@headlessui/react": ^1.5.0
"@heroicons/react": ^1.0.6
"@prisma/client": ^5.0.0
"@prisma/client": ^5.3.0
"@tailwindcss/forms": ^0.5.2
"@types/node": 16.9.1
"@types/react": 18.0.26
@ -3366,7 +3366,7 @@ __metadata:
next-auth: ^4.22.1
next-i18next: ^13.2.2
postcss: ^8.4.18
prisma: ^5.0.0
prisma: ^5.3.0
prisma-field-encryption: ^1.4.0
react: ^18.2.0
react-chartjs-2: ^4.0.1
@ -3853,10 +3853,11 @@ __metadata:
resolution: "@calcom/prisma@workspace:packages/prisma"
dependencies:
"@calcom/lib": "*"
"@prisma/client": ^5.0.0
"@prisma/generator-helper": ^5.0.0
"@prisma/client": ^5.2.0
"@prisma/extension-accelerate": ^0.6.2
"@prisma/generator-helper": ^5.2.0
npm-run-all: ^4.1.5
prisma: ^5.0.0
prisma: ^5.2.0
ts-node: ^10.9.1
zod: ^3.22.2
zod-prisma: ^0.5.4
@ -7794,17 +7795,31 @@ __metadata:
languageName: node
linkType: hard
"@prisma/client@npm:^5.0.0":
version: 5.0.0
resolution: "@prisma/client@npm:5.0.0"
"@prisma/client@npm:^5.2.0":
version: 5.2.0
resolution: "@prisma/client@npm:5.2.0"
dependencies:
"@prisma/engines-version": 4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584
"@prisma/engines-version": 5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f
peerDependencies:
prisma: "*"
peerDependenciesMeta:
prisma:
optional: true
checksum: 332c2af44e880ffc9dd1223992bf6f45910094c7a3a540cbbfdda45d6caf3e82998376338abdf85e34a12f1082ae932f2385d6396c62fe4bba7ec6b84de54466
checksum: ad523b7a54e31d365ecac7bdb89f5a89f62e616f5f567f5dd5060e86b122253a4652ea778c0ccbab31906e2170110e808839fbae7ee91a4fd16a8282ee86f5f1
languageName: node
linkType: hard
"@prisma/client@npm:^5.3.0":
version: 5.3.0
resolution: "@prisma/client@npm:5.3.0"
dependencies:
"@prisma/engines-version": 5.3.0-36.e90b936d84779543cbe0e494bc8b9d7337fad8e4
peerDependencies:
prisma: "*"
peerDependenciesMeta:
prisma:
optional: true
checksum: 7c12db57dfd07e86841876a7e91ee2307071b6b9e7afed061acac1171ef1f12599fd65ca144abd09ab1e00123304d2103adc9106c73cef61a366cd234ccc9683
languageName: node
linkType: hard
@ -7830,17 +7845,51 @@ __metadata:
languageName: node
linkType: hard
"@prisma/engines-version@npm:4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584":
version: 4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584
resolution: "@prisma/engines-version@npm:4.17.0-26.6b0aef69b7cdfc787f822ecd7cdc76d5f1991584"
checksum: 8fcbceef3b554ee7fa404bead50be5286412a097b21723272aff298b289caf2802b01b84bb85c4c9f3b592eeac114c8d6e79db083f271dc8c54f453b4a515233
"@prisma/debug@npm:5.2.0":
version: 5.2.0
resolution: "@prisma/debug@npm:5.2.0"
dependencies:
"@types/debug": 4.1.8
debug: 4.3.4
strip-ansi: 6.0.1
checksum: 49b71106afb9666fc3c95cd4368bc7664a6deb9b9be15e9de98af5e78b56c6d7df1ff8a8a2dcdceac330f6d32f94d10c503ee55d60b5b9b4df36ac438da66004
languageName: node
linkType: hard
"@prisma/engines@npm:5.0.0":
version: 5.0.0
resolution: "@prisma/engines@npm:5.0.0"
checksum: 31271d85c29709059f91051d4cef7acf874014ba0128b674ca2f842e5fac61d3011e9db246dfa67ba4803081d36dbc9e31492716bab677128588343c92117b2b
"@prisma/engines-version@npm:5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f":
version: 5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f
resolution: "@prisma/engines-version@npm:5.2.0-25.2804dc98259d2ea960602aca6b8e7fdc03c1758f"
checksum: 7a0fde44dad7902aef0035a30073c8e3178bccbaf65f688583cf3db94e36d160fd0a52cae8b6422b670facdbd4201861e1d6e2c7371d57ef27b58a2e1c524213
languageName: node
linkType: hard
"@prisma/engines-version@npm:5.3.0-36.e90b936d84779543cbe0e494bc8b9d7337fad8e4":
version: 5.3.0-36.e90b936d84779543cbe0e494bc8b9d7337fad8e4
resolution: "@prisma/engines-version@npm:5.3.0-36.e90b936d84779543cbe0e494bc8b9d7337fad8e4"
checksum: 7c3680bc4e3147755b7efc094d6b0ad11ba1c59eb0436f81016e8f0b1da886cc7a4bce9dccfe9599811cf986558694ec1b0b60f21c1215bd6cc0e42e3a03569f
languageName: node
linkType: hard
"@prisma/engines@npm:5.2.0":
version: 5.2.0
resolution: "@prisma/engines@npm:5.2.0"
checksum: c4d0a424b211ab5f02c977bd87e03a151a7d297d8448b08ef9de931a0dcebbbea76cdefc15a17fd06dacac692b164fd88b32c23eb84f7822dbaf3d0885b700a7
languageName: node
linkType: hard
"@prisma/engines@npm:5.3.0":
version: 5.3.0
resolution: "@prisma/engines@npm:5.3.0"
checksum: 4735c7a2b1f01a47f5a870cc4bbfaca5632df8a712d20d371e707e9a8d32f92fb808a2031c78504459bdebc562f67156fa8334c258ea47adf073ef4143b52e7f
languageName: node
linkType: hard
"@prisma/extension-accelerate@npm:^0.6.2":
version: 0.6.2
resolution: "@prisma/extension-accelerate@npm:0.6.2"
peerDependencies:
"@prisma/client": ">=4.16.1"
checksum: bf506942660bd7cff1de0280932be3a9b4233cf6acb7cb07cdd8fcc0e0f2e30a23b261db3a7470b36eaaa1737d14ca59fc72024cab7899ddebfc4aa2056c9838
languageName: node
linkType: hard
@ -7856,6 +7905,18 @@ __metadata:
languageName: node
linkType: hard
"@prisma/generator-helper@npm:^5.2.0":
version: 5.2.0
resolution: "@prisma/generator-helper@npm:5.2.0"
dependencies:
"@prisma/debug": 5.2.0
"@types/cross-spawn": 6.0.2
cross-spawn: 7.0.3
kleur: 4.1.5
checksum: aa3a617026917135f767a22b0c77582cd14f46de76a842898cf8923e9c49cf32ae2d519fe953d39355bf2fbdf9015ad5cb720b60d66bc0a437ffcdb1fec1c57a
languageName: node
linkType: hard
"@prisma/generator-helper@npm:~3.8.1":
version: 3.8.1
resolution: "@prisma/generator-helper@npm:3.8.1"
@ -30812,14 +30873,25 @@ __metadata:
languageName: node
linkType: hard
"prisma@npm:^5.0.0":
version: 5.0.0
resolution: "prisma@npm:5.0.0"
"prisma@npm:^5.2.0":
version: 5.2.0
resolution: "prisma@npm:5.2.0"
dependencies:
"@prisma/engines": 5.0.0
"@prisma/engines": 5.2.0
bin:
prisma: build/index.js
checksum: fdc62377853d25b4db664c736fd0b08d2b0c6db5752e6f6c6ec3bda77634cfb79e6f49d52d4b8f54ddb8ec9c28fc3fb0c13f95caf61085447d0929e258af9284
checksum: 8b99ab5a5f801c72b2eb1809db980bd104dfd699cb14c5d5db5b675566c89e46501267399bb2f02bc3ea8fb86fc2f029cccd7178768109dc4d198bc93552b1da
languageName: node
linkType: hard
"prisma@npm:^5.3.0":
version: 5.3.0
resolution: "prisma@npm:5.3.0"
dependencies:
"@prisma/engines": 5.3.0
bin:
prisma: build/index.js
checksum: e33cb0b7cb6f10693131782d82dec178a4f13d9f8ea5ac39c206e41d3c1957c3e41c3a16bab95ef6572fde1e852f68b780b351a11204e989bcee7d1b91276dfb
languageName: node
linkType: hard