Skip to content

feat: prisma DB multi-tenancy (cal.eu) #21364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 95 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 80 commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
ef098b3
feat: Initial implentation of prisma clients store
zomars May 16, 2025
824a57a
Update prismaStore.ts
zomars May 16, 2025
da77ede
Create withPrismaDataForPage.ts
zomars May 16, 2025
f01f5b1
Update page.tsx
zomars May 16, 2025
2f057c5
Create withPrismaPage.tsx
zomars May 16, 2025
9844789
Update page.tsx
zomars May 16, 2025
802e9cb
Update withPrismaPage.tsx
zomars May 17, 2025
0f2c8bb
feat: integrate prismaStore with tRPC procedures for tenant selection
devin-ai-integration[bot] May 19, 2025
1b7f885
feat: integrate prismaStore with tRPC, deprecate global prisma instance
devin-ai-integration[bot] May 19, 2025
9a2568d
fix: update types for tenant-aware Prisma client
devin-ai-integration[bot] May 19, 2025
383bd7c
feat: implement tenant-aware Prisma migration patterns
devin-ai-integration[bot] May 19, 2025
f054bb6
docs: add comprehensive prisma migration tracking document and migrat…
devin-ai-integration[bot] May 20, 2025
6670fd6
feat: implement getTenantAwarePrisma function for easier access witho…
devin-ai-integration[bot] May 20, 2025
4f6d3c0
feat: add error handling to withPrismaRoute for missing database URLs
devin-ai-integration[bot] May 20, 2025
cfc5be8
feat: add error handling to withPrismaSsr and withPrismaApiHandler
devin-ai-integration[bot] May 20, 2025
ca4cce0
feat: update prismaMiddleware to use tenant parameter in runWithTenants
devin-ai-integration[bot] May 20, 2025
0b4de20
refactor: migrate tRPC handlers to use tenant-aware Prisma client
devin-ai-integration[bot] May 20, 2025
1e6a310
refactor: migrate API routes to use tenant-aware Prisma client
devin-ai-integration[bot] May 20, 2025
089827b
fix: correct syntax errors in API utility files
devin-ai-integration[bot] May 20, 2025
a4f7c49
refactor: migrate tRPC handlers to use ctx.prisma instead of direct i…
devin-ai-integration[bot] May 20, 2025
e6b5563
refactor: make createContext.ts tenant-aware to eliminate prismaMiddl…
devin-ai-integration[bot] May 20, 2025
06bf7ca
refactor: make createContext.ts tenant-aware to eliminate prismaMiddl…
devin-ai-integration[bot] May 20, 2025
c3d58d4
refactor: remove prismaMiddleware from procedures since context is no…
devin-ai-integration[bot] May 20, 2025
c3986a1
docs: update migration tracking to reflect tenant-aware context
devin-ai-integration[bot] May 20, 2025
91caf39
refactor: update prisma index to use currentTenant as default
devin-ai-integration[bot] May 21, 2025
aad4953
Discard changes to apps/api/v1/pages/api/api-keys/[id]/_auth-middlewa…
zomars May 21, 2025
2246eca
Discard changes to apps/api/v1/pages/api/api-keys/[id]/_delete.ts
zomars May 21, 2025
2a9e64b
Discard changes to packages/trpc/server/procedures/authedProcedure.ts
zomars May 21, 2025
2479620
Discard changes to packages/trpc/server/procedures/publicProcedure.ts
zomars May 21, 2025
fb5e84f
refactor: prisma proxy
zomars May 21, 2025
05765fb
WIP
zomars May 21, 2025
97be3a9
WIP
zomars May 21, 2025
3c36d55
WIP
zomars May 21, 2025
857ba7c
WIP
zomars May 21, 2025
0e269cd
WIP
zomars May 21, 2025
2c0b225
Revert "refactor: migrate API routes to use tenant-aware Prisma client"
zomars May 21, 2025
1039991
Revert "fix: correct syntax errors in API utility files"
zomars May 21, 2025
6c5c634
Discard changes to packages/trpc/server/routers/viewer/workflows/list…
zomars May 21, 2025
e280e91
Discard changes to packages/trpc/server/routers/viewer/workflows/crea…
zomars May 21, 2025
3b4c7ad
revert
zomars May 21, 2025
cc53f78
Discard changes to packages/trpc/server/routers/viewer/webhook/delete…
zomars May 21, 2025
05613c4
Discard changes to packages/trpc/server/routers/viewer/teams/legacyLi…
zomars May 21, 2025
39db512
Discard changes to packages/trpc/server/routers/viewer/teams/update.h…
zomars May 21, 2025
4268733
Discard changes to packages/trpc/server/routers/viewer/organizations/…
zomars May 21, 2025
bf9b758
Discard changes to packages/trpc/server/routers/viewer/organizations/…
zomars May 21, 2025
7449134
Discard changes to packages/trpc/server/routers/viewer/organizations/…
zomars May 21, 2025
e4cd320
Discard changes to packages/trpc/server/routers/viewer/eventTypes/get…
zomars May 21, 2025
c7f00b0
Discard changes to packages/trpc/server/routers/viewer/organizations/…
zomars May 21, 2025
7a44c43
Discard changes to packages/trpc/server/routers/viewer/eventTypes/cre…
zomars May 21, 2025
9659e55
Discard changes to packages/trpc/server/routers/viewer/availability/s…
zomars May 21, 2025
e421c27
Update createContext.ts
zomars May 21, 2025
eeb70fc
Discard changes to packages/lib/server/repository/eventType.ts
zomars May 21, 2025
35a8c83
Delete packages/trpc/server/routers/viewer/apiKeys/queryForDependenci…
zomars May 21, 2025
a519499
Delete migrate-prisma-usage.ts
zomars May 21, 2025
d10e2af
Update prismaStore.ts
zomars May 21, 2025
a89bb2e
WIP
zomars May 21, 2025
15ccdcb
Fix type errors in multi-tenancy Prisma implementation
devin-ai-integration[bot] May 21, 2025
c63c429
Revert "Fix type errors in multi-tenancy Prisma implementation"
devin-ai-integration[bot] May 22, 2025
e4370ca
Delete route.ts
zomars May 22, 2025
99cb078
Add multi-tenant helper for crons
zomars May 22, 2025
083f341
Fix tests by skipping tenant logic in test environments
devin-ai-integration[bot] May 22, 2025
b580e90
refactor: migrate calendar-cache cron to app dir
zomars May 22, 2025
6b5db9f
Merge branch 'main' into feat/db-multitenancy
zomars May 22, 2025
f30e002
Discard changes to packages/lib/bookings/filterHostsByLeadThreshold.t…
zomars May 22, 2025
7e1157c
Discard changes to packages/lib/bookings/filterHostsBySameRoundRobinH…
zomars May 22, 2025
4d50582
Discard changes to packages/lib/bookings/filterHostsBySameRoundRobinH…
zomars May 22, 2025
8bec6ea
Discard changes to packages/trpc/server/routers/viewer/__tests__/outO…
zomars May 22, 2025
33ebff9
Discard changes to packages/trpc/server/routers/viewer/organizations/…
zomars May 22, 2025
c99e961
Discard changes to tests/libs/__mocks__/prisma.ts
zomars May 22, 2025
ecf6e28
Discard changes to tests/libs/__mocks__/prismaMock.ts
zomars May 22, 2025
582eb57
cleanup
zomars May 22, 2025
277c54d
Discard changes to apps/web/modules/auth/forgot-password/forgot-passw…
zomars May 22, 2025
f5a3f94
Delete route.ts
zomars May 22, 2025
57f48a3
Delete route.ts
zomars May 22, 2025
17b8617
Delete middleware_prisma-test.ts
zomars May 22, 2025
cd3ac7f
Delete route.ts
zomars May 22, 2025
6936208
Renamed file to withMultiTenantPrisma
zomars May 22, 2025
3fd62c5
Delete withPrismaApiHandler.ts
zomars May 22, 2025
12c52b8
Delete withPrismaDataForPage.ts
zomars May 22, 2025
2c9d12f
Merge branch 'main' into feat/db-multitenancy
zomars May 22, 2025
440e41e
WIP
zomars May 22, 2025
bdfacd0
Merge branch 'main' into feat/db-multitenancy
zomars May 22, 2025
75ec19c
Update tenants.ts
zomars May 23, 2025
14b168d
Update prismaStore.ts
zomars May 23, 2025
e6ff029
Update is-prisma-available-check.ts
zomars May 23, 2025
9c7cd50
Update delete-app.ts
zomars May 23, 2025
5eae7d6
refactor: prevents mixed server/clients imports
zomars May 23, 2025
7a20dc4
refactor: prevent mixed imports
zomars May 23, 2025
19cd8c3
Delete tenant-aware-prisma.service.ts
zomars May 23, 2025
1d70c2a
Merge branch 'main' into feat/db-multitenancy
emrysal May 27, 2025
cde530d
Merge branch 'main' into feat/db-multitenancy
emrysal May 28, 2025
d23e970
Allow EU data residency config through TENANT_DOMAINS_EU
emrysal May 29, 2025
722c64b
Merge branch 'main' into feat/db-multitenancy
emrysal May 29, 2025
8b36fb6
Required changes to API responders, appDir and pages
emrysal May 31, 2025
902af2f
Prevent insights db config from crashing tenant init
emrysal May 31, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions apps/api/v2/src/modules/prisma/tenant-aware-prisma.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { Injectable, Scope } from "@nestjs/common";
import { Inject } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { REQUEST } from "@nestjs/core";
import { PrismaClient } from "@prisma/client";

import { getTenantFromHost } from "@calcom/prisma/store/tenants";

@Injectable({ scope: Scope.REQUEST })
export class TenantAwarePrismaService {
public prisma: PrismaClient;

constructor(
@Inject(REQUEST) private readonly request: Request,
private readonly configService: ConfigService
) {
const host = this.request.headers["host"] || "";
const tenant = getTenantFromHost(host);

let dbUrl = this.configService.get("db.url", { infer: true });
if (tenant === "eu") {
dbUrl = this.configService.get("db.euUrl", { infer: true });
}

this.prisma = new PrismaClient({
datasources: {
db: {
url: dbUrl,
},
},
});
}
}
6 changes: 6 additions & 0 deletions apps/web/app/api/calendar-cache/cron/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { handler } from "@calcom/features/calendar-cache/api/cron";
import { withMultiTenantPrisma } from "@calcom/prisma/store/withMultiTenantPrisma";

import { defaultResponderForAppDir } from "../../defaultResponderForAppDir";

export const GET = withMultiTenantPrisma(defaultResponderForAppDir(handler));
3 changes: 2 additions & 1 deletion apps/web/app/api/cron/calendar-cache-cleanup/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

import prisma from "@calcom/prisma";
import { withMultiTenantPrisma } from "@calcom/prisma/store/withMultiTenantPrisma";

async function postHandler(request: NextRequest) {
const apiKey = request.headers.get("authorization") || request.nextUrl.searchParams.get("apiKey");
Expand All @@ -23,4 +24,4 @@ async function postHandler(request: NextRequest) {
return NextResponse.json({ ok: true, count: deleted.count });
}

export const POST = defaultResponderForAppDir(postHandler);
export const POST = withMultiTenantPrisma(defaultResponderForAppDir(postHandler));
3 changes: 2 additions & 1 deletion apps/web/app/api/cron/credentials/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import { CredentialRepository } from "@calcom/lib/server/repository/credential";
import { DelegationCredentialRepository } from "@calcom/lib/server/repository/delegationCredential";
import { withMultiTenantPrisma } from "@calcom/prisma/store/withMultiTenantPrisma";

import { defaultResponderForAppDir } from "../../defaultResponderForAppDir";

Expand Down Expand Up @@ -167,4 +168,4 @@ const handler = async (request: NextRequest) => {
return NextResponse.json(response);
};

export const GET = defaultResponderForAppDir(handler);
export const GET = withMultiTenantPrisma(defaultResponderForAppDir(handler));
3 changes: 2 additions & 1 deletion apps/web/app/api/cron/selected-calendars/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import { CredentialRepository } from "@calcom/lib/server/repository/credential";
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
import { withMultiTenantPrisma } from "@calcom/prisma/store/withMultiTenantPrisma";
import type { CredentialForCalendarServiceWithEmail } from "@calcom/types/Credential";
import type { Ensure } from "@calcom/types/utils";

Expand Down Expand Up @@ -273,4 +274,4 @@ const handler = async (request: NextRequest) => {
return NextResponse.json(await handleCreateSelectedCalendars());
};

export const GET = defaultResponderForAppDir(handler);
export const GET = withMultiTenantPrisma(defaultResponderForAppDir(handler));
3 changes: 2 additions & 1 deletion apps/web/app/api/tasks/cleanup/route.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";

import { GET as handler } from "@calcom/features/tasker/api/cleanup";
import { withMultiTenantPrisma } from "@calcom/prisma/store/withMultiTenantPrisma";

export const GET = defaultResponderForAppDir(handler);
export const GET = withMultiTenantPrisma(defaultResponderForAppDir(handler));
3 changes: 2 additions & 1 deletion apps/web/app/api/tasks/cron/route.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { defaultResponderForAppDir } from "app/api/defaultResponderForAppDir";

import { GET as handler } from "@calcom/features/tasker/api/cron";
import { withMultiTenantPrisma } from "@calcom/prisma/store/withMultiTenantPrisma";

export const GET = defaultResponderForAppDir(handler);
export const GET = withMultiTenantPrisma(defaultResponderForAppDir(handler));

/**
* This runs each minute and we need fresh data each time
Expand Down
18 changes: 18 additions & 0 deletions apps/web/app/api/tenant-aware-example/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextResponse } from "next/server";

import { prisma } from "@calcom/prisma";
import { withPrismaRoute } from "@calcom/prisma/store/withPrismaRoute";

async function handler(req: Request) {
const users = await prisma.user.findMany({
select: { id: true, name: true, email: true },
take: 5,
});

return NextResponse.json({
tenant: req.headers.get("host") || "unknown",
users,
});
}

export const GET = withPrismaRoute(handler);
9 changes: 9 additions & 0 deletions apps/web/app/prisma-test/api/route.ts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to cover the main entrypoints with re-usable wrappers.

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { NextResponse } from "next/server";

import { prisma } from "@calcom/prisma";
import { withPrismaRoute } from "@calcom/prisma/store/withPrismaRoute";

export const GET = withPrismaRoute(async (req) => {
const user = await prisma.user.findFirst({ where: { id: 1 }, select: { id: true, name: true } });
return NextResponse.json({ user });
});
29 changes: 29 additions & 0 deletions apps/web/app/prisma-test/page/page.tsx
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same for pages

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { PrismaClient } from "@prisma/client";

import { withPrismaPage } from "@calcom/prisma/store/withPrismaPage";

interface HomePageProps {
prisma: PrismaClient;
host: string; // host can be used if needed, e.g. for display
}

// This is the actual page component logic, now cleaner.
async function HomePageContent({ prisma, host }: HomePageProps) {
const users = await prisma.user.findMany({ where: { id: 1 }, select: { id: true, name: true } });

return (
<div>
<h1>Users for tenant ({host})</h1>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}

// Wrap the page content component with the HOC
const Home = withPrismaPage(HomePageContent);

export default Home;
1 change: 0 additions & 1 deletion apps/web/pages/api/calendar-cache/cron.ts

This file was deleted.

11 changes: 10 additions & 1 deletion packages/features/auth/lib/getServerSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import { UserRepository } from "@calcom/lib/server/repository/user";
import prisma from "@calcom/prisma";
import { runWithTenants } from "@calcom/prisma/store/prismaStore";
import { getTenantFromHost } from "@calcom/prisma/store/tenants";

const log = logger.getSubLogger({ prefix: ["getServerSession"] });
/**
Expand All @@ -28,7 +30,7 @@ const CACHE = new LRUCache<string, Session>({ max: 1000 });
* token has expired (30 days). This should be fine as we call `/auth/session`
* frequently enough on the client-side to keep the session alive.
*/
export async function getServerSession(options: {
async function _getServerSession(options: {
req: NextApiRequest | GetServerSidePropsContext["req"];
authOptions?: AuthOptions;
}) {
Expand Down Expand Up @@ -130,3 +132,10 @@ export async function getServerSession(options: {
log.debug("Returned session", safeStringify(session));
return session;
}

export async function getServerSession(options: {
req: NextApiRequest | GetServerSidePropsContext["req"];
authOptions?: AuthOptions;
}) {
return runWithTenants(getTenantFromHost(options.req.headers.host || ""), () => _getServerSession(options));
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useState } from "react";
import { z } from "zod";
import type { z } from "zod";

import { useBookerStore } from "@calcom/features/bookings/Booker/store";
import type getBookingResponsesSchema from "@calcom/features/bookings/lib/getBookingResponsesSchema";
Expand Down
22 changes: 9 additions & 13 deletions packages/features/calendar-cache/api/cron.ts
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This got migrated from pages to app dir. It was the only cron remaining there. And I didn't want to make a specific helper for pages.

Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import type { NextApiRequest } from "next";
import type { NextRequest } from "next/server";
import { NextResponse } from "next/server";

import { HttpError } from "@calcom/lib/http-error";
import logger from "@calcom/lib/logger";
import { safeStringify } from "@calcom/lib/safeStringify";
import { defaultHandler } from "@calcom/lib/server/defaultHandler";
import { defaultResponder } from "@calcom/lib/server/defaultResponder";
import { SelectedCalendarRepository } from "@calcom/lib/server/repository/selectedCalendar";
import type { SelectedCalendarEventTypeIds } from "@calcom/types/Calendar";

import { CalendarCache } from "../calendar-cache";

const log = logger.getSubLogger({ prefix: ["CalendarCacheCron"] });

const validateRequest = (req: NextApiRequest) => {
const apiKey = req.headers.authorization || req.query.apiKey;
const validateRequest = (req: NextRequest) => {
const url = new URL(req.url);
const apiKey = req.headers.get("authorization") || url.searchParams.get("apiKey");
if (![process.env.CRON_API_KEY, `Bearer ${process.env.CRON_SECRET}`].includes(`${apiKey}`)) {
throw new HttpError({ statusCode: 401, message: "Unauthorized" });
}
Expand Down Expand Up @@ -144,16 +144,12 @@ const handleCalendarsToWatch = async () => {
};

// This cron is used to activate and renew calendar subscriptions
const handler = defaultResponder(async (request: NextApiRequest) => {
export const handler = async (request: NextRequest) => {
validateRequest(request);
await Promise.allSettled([handleCalendarsToWatch(), handleCalendarsToUnwatch()]);

// TODO: Credentials can be installed on a whole team, check for selected calendars on the team
return {
return NextResponse.json({
executedAt: new Date().toISOString(),
};
});

export default defaultHandler({
GET: Promise.resolve({ default: defaultResponder(handler) }),
});
});
};
68 changes: 21 additions & 47 deletions packages/prisma/index.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
import type { Prisma } from "@prisma/client";
import { PrismaClient as PrismaClientWithoutExtension } from "@prisma/client";
import { withAccelerate } from "@prisma/extension-accelerate";

import { bookingIdempotencyKeyExtension } from "./extensions/booking-idempotency-key";
import { disallowUndefinedDeleteUpdateManyExtension } from "./extensions/disallow-undefined-delete-update-many";
import { excludeLockedUsersExtension } from "./extensions/exclude-locked-users";
import { excludePendingPaymentsExtension } from "./extensions/exclude-pending-payment-teams";
import { usageTrackingExtention } from "./extensions/usage-tracking";
import { bookingReferenceMiddleware } from "./middleware";
import type { PrismaClientWithExtensions } from "./store/prismaStore";
import { getPrisma, getTenantAwarePrisma } from "./store/prismaStore";
import { Tenant } from "./store/tenants";

const prismaOptions: Prisma.PrismaClientOptions = {};

const globalForPrisma = global as unknown as {
prismaWithoutClientExtensions: PrismaClientWithoutExtension;
prismaWithClientExtensions: PrismaClientWithExtensions;
};

const loggerLevel = parseInt(process.env.NEXT_PUBLIC_LOGGER_LEVEL ?? "", 10);

if (!isNaN(loggerLevel)) {
Expand All @@ -37,49 +27,33 @@ if (!isNaN(loggerLevel)) {
}
}

// Prevents flooding with idle connections
const prismaWithoutClientExtensions =
globalForPrisma.prismaWithoutClientExtensions || new PrismaClientWithoutExtension(prismaOptions);

export const customPrisma = (options?: Prisma.PrismaClientOptions) =>
new PrismaClientWithoutExtension({ ...prismaOptions, ...options })
.$extends(usageTrackingExtention())
.$extends(excludeLockedUsersExtension())
.$extends(excludePendingPaymentsExtension())
.$extends(bookingIdempotencyKeyExtension())
.$extends(disallowUndefinedDeleteUpdateManyExtension())
.$extends(withAccelerate());

// 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(usageTrackingExtention())
.$extends(excludeLockedUsersExtension())
.$extends(excludePendingPaymentsExtension())
.$extends(bookingIdempotencyKeyExtension())
.$extends(disallowUndefinedDeleteUpdateManyExtension())
.$extends(withAccelerate());

export const prisma = globalForPrisma.prismaWithClientExtensions || prismaWithClientExtensions;
export const prisma = new Proxy({} as PrismaClientWithExtensions, {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've opted for the proxy approach so we can keep using the regular import { prisma } from "@calcom/prisma"; everywhere. Otherwise this PR would get very very messy.

get(target, prop) {
if (process.env.NODE_ENV === "test") {
const defaultPrisma = getPrisma(Tenant.US, prismaOptions);
return Reflect.get(defaultPrisma, prop);
}
Comment on lines +32 to +35
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this doesn't break unit tests. E2E test should run normally tho.


try {
const tenantPrisma = getTenantAwarePrisma(prismaOptions);
return Reflect.get(tenantPrisma, prop);
} catch (error) {
throw new Error(
"Prisma was called outside of runWithTenants. Please wrap your code with runWithTenants or use a tenant-aware approach."
);
}
},
});

// This prisma instance is meant to be used only for READ operations.
// If self hosting, feel free to leave INSIGHTS_DATABASE_URL as empty and `readonlyPrisma` will default to `prisma`.
export const readonlyPrisma = process.env.INSIGHTS_DATABASE_URL
? customPrisma({
datasources: { db: { url: process.env.INSIGHTS_DATABASE_URL } },
})
? getPrisma(Tenant.INSIGHTS, prismaOptions)
: prisma;

if (process.env.NODE_ENV !== "production") {
globalForPrisma.prismaWithoutClientExtensions = prismaWithoutClientExtensions;
globalForPrisma.prismaWithClientExtensions = prisma;
}

type PrismaClientWithExtensions = typeof prismaWithClientExtensions;
export type PrismaClient = PrismaClientWithExtensions;

type OmitPrismaClient = Omit<
Expand Down
Loading
Loading