chore: Insights readonly DB client (#12373)

This commit is contained in:
Erik 2023-11-15 18:50:20 -03:00 committed by GitHub
parent eb97e1660b
commit 6a8726f5f8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 48 additions and 36 deletions

View File

@ -25,6 +25,7 @@ CALCOM_LICENSE_KEY=
DATABASE_URL="postgresql://postgres:@localhost:5450/calendso"
UPSTASH_REDIS_REST_URL=
UPSTASH_REDIS_REST_TOKEN=
INSIGHTS_DATABASE_URL=
# Uncomment to enable a dedicated connection pool for Prisma using Prisma Data Proxy
# Cold boots will be faster and you'll be able to scale your DB independently of your app.

View File

@ -3,7 +3,7 @@ import { serverSideTranslations } from "next-i18next/serverSideTranslations";
import superjson from "superjson";
import { CALCOM_VERSION } from "@calcom/lib/constants";
import prisma from "@calcom/prisma";
import prisma, { readonlyPrisma } from "@calcom/prisma";
import { createProxySSGHelpers } from "@calcom/trpc/react/ssg";
import { appRouter } from "@calcom/trpc/server/routers/_app";
@ -31,6 +31,7 @@ export async function ssgInit<TParams extends { locale?: string }>(opts: GetStat
transformer: superjson,
ctx: {
prisma,
insightsDb: readonlyPrisma,
session: null,
locale,
i18n: _i18n,

View File

@ -1,6 +1,6 @@
import type { Dayjs } from "@calcom/dayjs";
import dayjs from "@calcom/dayjs";
import { prisma } from "@calcom/prisma";
import { readonlyPrisma as prisma } from "@calcom/prisma";
import type { Prisma } from "@calcom/prisma/client";
import type { RawDataInput } from "./raw-data.schema";

View File

@ -35,7 +35,7 @@ const userBelongsToTeamProcedure = authedProcedure.use(async ({ ctx, next, rawIn
membershipWhereConditional["teamId"] = parse.data.teamId;
}
const membership = await ctx.prisma.membership.findFirst({
const membership = await ctx.insightsDb.membership.findFirst({
where: membershipWhereConditional,
});
@ -43,7 +43,7 @@ const userBelongsToTeamProcedure = authedProcedure.use(async ({ ctx, next, rawIn
// So that would mean ctx.user.organization is present
if ((parse.data.isAll && ctx.user.organizationId) || (!membership && ctx.user.organizationId)) {
//Look for membership type in organizationId
const membershipOrg = await ctx.prisma.membership.findFirst({
const membershipOrg = await ctx.insightsDb.membership.findFirst({
where: {
userId: ctx.user.id,
teamId: ctx.user.organizationId,
@ -152,7 +152,7 @@ export const insightsRouter = router({
}
if (isAll && ctx.user.isOwnerAdminOfParentTeam && ctx.user.organizationId) {
const teamsFromOrg = await ctx.prisma.team.findMany({
const teamsFromOrg = await ctx.insightsDb.team.findMany({
where: {
parentId: ctx.user.organizationId,
},
@ -168,7 +168,7 @@ export const insightsRouter = router({
in: [ctx.user.organizationId, ...teamsFromOrg.map((t) => t.id)],
},
};
const usersFromOrg = await ctx.prisma.membership.findMany({
const usersFromOrg = await ctx.insightsDb.membership.findMany({
where: {
team: teamConditional,
accepted: true,
@ -197,7 +197,7 @@ export const insightsRouter = router({
}
if (teamId && !isAll) {
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId: teamId,
accepted: true,
@ -348,7 +348,7 @@ export const insightsRouter = router({
let whereConditional: Prisma.BookingTimeStatusWhereInput = {};
if (isAll && ctx.user.isOwnerAdminOfParentTeam && ctx.user.organizationId) {
const teamsFromOrg = await ctx.prisma.team.findMany({
const teamsFromOrg = await ctx.insightsDb.team.findMany({
where: {
parentId: user.organizationId,
},
@ -357,7 +357,7 @@ export const insightsRouter = router({
},
});
const usersFromOrg = await ctx.prisma.membership.findMany({
const usersFromOrg = await ctx.insightsDb.membership.findMany({
where: {
teamId: {
in: [ctx.user.organizationId, ...teamsFromOrg.map((t) => t.id)],
@ -388,7 +388,7 @@ export const insightsRouter = router({
}
if (teamId && !isAll) {
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId,
accepted: true,
@ -537,7 +537,7 @@ export const insightsRouter = router({
};
if (isAll && ctx.user.isOwnerAdminOfParentTeam && ctx.user.organizationId) {
const teamsFromOrg = await ctx.prisma.team.findMany({
const teamsFromOrg = await ctx.insightsDb.team.findMany({
where: {
parentId: user.organizationId,
},
@ -546,7 +546,7 @@ export const insightsRouter = router({
},
});
const usersFromOrg = await ctx.prisma.membership.findMany({
const usersFromOrg = await ctx.insightsDb.membership.findMany({
where: {
teamId: {
in: [ctx.user.organizationId, ...teamsFromOrg.map((t) => t.id)],
@ -578,7 +578,7 @@ export const insightsRouter = router({
}
if (teamId && !isAll) {
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId,
accepted: true,
@ -615,7 +615,7 @@ export const insightsRouter = router({
bookingWhere.userId = memberUserId;
}
const bookingsFromSelected = await ctx.prisma.bookingTimeStatus.groupBy({
const bookingsFromSelected = await ctx.insightsDb.bookingTimeStatus.groupBy({
by: ["eventTypeId"],
where: bookingWhere,
_count: {
@ -639,7 +639,7 @@ export const insightsRouter = router({
},
};
const eventTypesFrom = await ctx.prisma.eventType.findMany({
const eventTypesFrom = await ctx.insightsDb.eventType.findMany({
select: {
id: true,
title: true,
@ -752,7 +752,7 @@ export const insightsRouter = router({
}
if (isAll && ctx.user.isOwnerAdminOfParentTeam && ctx.user.organizationId) {
const teamsFromOrg = await ctx.prisma.team.findMany({
const teamsFromOrg = await ctx.insightsDb.team.findMany({
where: {
parentId: ctx.user?.organizationId,
},
@ -777,7 +777,7 @@ export const insightsRouter = router({
}
if (teamId && !isAll) {
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId,
accepted: true,
@ -832,7 +832,7 @@ export const insightsRouter = router({
const startDate = dayjs(date).startOf(startOfEndOf);
const endDate = dayjs(date).endOf(startOfEndOf);
const bookingsInTimeRange = await ctx.prisma.bookingTimeStatus.findMany({
const bookingsInTimeRange = await ctx.insightsDb.bookingTimeStatus.findMany({
select: {
eventLength: true,
},
@ -896,7 +896,7 @@ export const insightsRouter = router({
if (isAll && user.isOwnerAdminOfParentTeam && user.organizationId) {
delete bookingWhere.teamId;
const teamsFromOrg = await ctx.prisma.team.findMany({
const teamsFromOrg = await ctx.insightsDb.team.findMany({
where: {
parentId: user?.organizationId,
},
@ -904,7 +904,7 @@ export const insightsRouter = router({
id: true,
},
});
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId: {
in: [user?.organizationId, ...teamsFromOrg.map((t) => t.id)],
@ -931,7 +931,7 @@ export const insightsRouter = router({
}
if (teamId && !isAll) {
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId,
accepted: true,
@ -956,7 +956,7 @@ export const insightsRouter = router({
];
}
const bookingsFromTeam = await ctx.prisma.bookingTimeStatus.groupBy({
const bookingsFromTeam = await ctx.insightsDb.bookingTimeStatus.groupBy({
by: ["userId"],
where: bookingWhere,
_count: {
@ -977,7 +977,7 @@ export const insightsRouter = router({
return [];
}
const usersFromTeam = await ctx.prisma.user.findMany({
const usersFromTeam = await ctx.insightsDb.user.findMany({
where: {
id: {
in: userIds as number[],
@ -1030,7 +1030,7 @@ export const insightsRouter = router({
if (isAll && user.isOwnerAdminOfParentTeam) {
delete bookingWhere.teamId;
const teamsFromOrg = await ctx.prisma.team.findMany({
const teamsFromOrg = await ctx.insightsDb.team.findMany({
where: {
parentId: user?.organizationId,
},
@ -1038,7 +1038,7 @@ export const insightsRouter = router({
id: true,
},
});
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId: {
in: teamsFromOrg.map((t) => t.id),
@ -1066,7 +1066,7 @@ export const insightsRouter = router({
}
if (teamId && !isAll) {
const usersFromTeam = await ctx.prisma.membership.findMany({
const usersFromTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId,
accepted: true,
@ -1089,7 +1089,7 @@ export const insightsRouter = router({
];
}
const bookingsFromTeam = await ctx.prisma.bookingTimeStatus.groupBy({
const bookingsFromTeam = await ctx.insightsDb.bookingTimeStatus.groupBy({
by: ["userId"],
where: bookingWhere,
_count: {
@ -1109,7 +1109,7 @@ export const insightsRouter = router({
if (userIds.length === 0) {
return [];
}
const usersFromTeam = await ctx.prisma.user.findMany({
const usersFromTeam = await ctx.insightsDb.user.findMany({
where: {
id: {
in: userIds as number[],
@ -1138,7 +1138,7 @@ export const insightsRouter = router({
const user = ctx.user;
// Fetch user data
const userData = await ctx.prisma.user.findUnique({
const userData = await ctx.insightsDb.user.findUnique({
where: {
id: user.id,
},
@ -1167,7 +1167,7 @@ export const insightsRouter = router({
// Validate if user belongs to org as admin/owner
if (user.organizationId) {
const teamsFromOrg = await ctx.prisma.team.findMany({
const teamsFromOrg = await ctx.insightsDb.team.findMany({
where: {
parentId: user.organizationId,
},
@ -1178,7 +1178,7 @@ export const insightsRouter = router({
logo: true,
},
});
const orgTeam = await ctx.prisma.team.findUnique({
const orgTeam = await ctx.insightsDb.team.findUnique({
where: {
id: user.organizationId,
},
@ -1214,7 +1214,7 @@ export const insightsRouter = router({
}
// Look if user it's admin/owner in multiple teams
const belongsToTeams = await ctx.prisma.membership.findMany({
const belongsToTeams = await ctx.insightsDb.membership.findMany({
where: membershipConditional,
include: {
team: {
@ -1255,7 +1255,7 @@ export const insightsRouter = router({
}
if (isAll && user.organizationId && user.isOwnerAdminOfParentTeam) {
const usersInTeam = await ctx.prisma.membership.findMany({
const usersInTeam = await ctx.insightsDb.membership.findMany({
where: {
team: {
parentId: user.organizationId,
@ -1271,7 +1271,7 @@ export const insightsRouter = router({
return usersInTeam.map((membership) => membership.user);
}
const membership = await ctx.prisma.membership.findFirst({
const membership = await ctx.insightsDb.membership.findFirst({
where: {
userId: user.id,
teamId,
@ -1292,7 +1292,7 @@ export const insightsRouter = router({
return [membership.user];
}
const usersInTeam = await ctx.prisma.membership.findMany({
const usersInTeam = await ctx.insightsDb.membership.findMany({
where: {
teamId,
accepted: true,

View File

@ -59,6 +59,14 @@ const prismaWithClientExtensions = prismaWithoutClientExtensions
export const prisma = globalForPrisma.prismaWithClientExtensions || prismaWithClientExtensions;
// 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 } },
})
: prisma;
if (process.env.NODE_ENV !== "production") {
globalForPrisma.prismaWithoutClientExtensions = prismaWithoutClientExtensions;
globalForPrisma.prismaWithClientExtensions = prisma;

View File

@ -4,7 +4,7 @@ import type { Session } from "next-auth";
import type { serverSideTranslations } from "next-i18next/serverSideTranslations";
import { getLocale } from "@calcom/features/auth/lib/getLocale";
import prisma from "@calcom/prisma";
import prisma, { readonlyPrisma } from "@calcom/prisma";
import type { SelectedCalendar, User as PrismaUser } from "@calcom/prisma/client";
import type { CreateNextContextOptions } from "@trpc/server/adapters/next";
@ -53,6 +53,7 @@ export type GetSessionFn =
export async function createContextInner(opts: CreateInnerContextOptions) {
return {
prisma,
insightsDb: readonlyPrisma,
...opts,
};
}

View File

@ -247,6 +247,7 @@
"INTEGRATION_TEST_MODE",
"INTERCOM_SECRET",
"INTERCOM_SECRET",
"INSIGHTS_DATABASE_URL",
"IP_BANLIST",
"LARK_OPEN_APP_ID",
"LARK_OPEN_APP_SECRET",