refactor: convert EventTypeRepository to use dependency injection pattern (#22397)
- Add constructor with PrismaClient dependency injection - Convert all 14 static methods to instance methods using this.prismaClient - Update all usage sites to use two-step instantiation pattern: const eventTypeRepo = new EventTypeRepository(prisma); eventTypeRepo.method(...) - Keep getSelectedCalendarsFromUser as static utility method - Follow same pattern as UserRepository, TeamRepository, SelectedSlotsRepository, and BookingRepository - Maintain all existing method signatures and functionality Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: morgan@cal.com <morgan@cal.com>
This commit is contained in:
co-authored by
morgan@cal.com
parent
b5911a9a2d
commit
758143ef70
@@ -94,7 +94,8 @@ const checkIfUserIsHost = async ({
|
||||
return booking.user?.id === sessionUserId;
|
||||
}
|
||||
|
||||
const eventType = await EventTypeRepository.findByIdWithUserAccess({
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const eventType = await eventTypeRepo.findByIdWithUserAccess({
|
||||
id: booking.eventTypeId,
|
||||
userId: sessionUserId,
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { getCRMContactOwnerForRRLeadSkip } from "@calcom/app-store/_utils/CRMRoundRobinSkip";
|
||||
import { EventTypeRepository } from "@calcom/lib/server/repository/eventType";
|
||||
import { prisma } from "@calcom/prisma";
|
||||
import { SchedulingType } from "@calcom/prisma/enums";
|
||||
|
||||
import type { LocalRoute } from "../../types/types";
|
||||
@@ -32,7 +33,8 @@ export default async function routerGetCrmContactOwnerEmail({
|
||||
// Determine if the action is an event type redirect
|
||||
if (action.type !== "eventTypeRedirectUrl" || !action.eventTypeId) return null;
|
||||
|
||||
const eventType = await EventTypeRepository.findByIdIncludeHostsAndTeam({ id: action.eventTypeId });
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const eventType = await eventTypeRepo.findByIdIncludeHostsAndTeam({ id: action.eventTypeId });
|
||||
if (!eventType || eventType.schedulingType !== SchedulingType.ROUND_ROBIN) return null;
|
||||
|
||||
const eventTypeMetadata = eventType.metadata;
|
||||
|
||||
@@ -61,7 +61,8 @@ describe("deleteCredential", () => {
|
||||
await setupCredential({ userId: user.id, type: "zoom_video", appId: "zoom" });
|
||||
|
||||
await handleDeleteCredential({ userId: user.id, userMetadata: user.metadata, credentialId: 123 });
|
||||
const eventTypeQuery = await EventTypeRepository.findAllByUserId({ userId: user.id });
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const eventTypeQuery = await eventTypeRepo.findAllByUserId({ userId: user.id });
|
||||
|
||||
// Ensure that the event type with the deleted app was converted back to daily
|
||||
const changedEventType = eventTypeQuery.find((eventType) => eventType.id === 1)?.locations;
|
||||
|
||||
@@ -52,7 +52,8 @@ export const getEventTypeById = async ({
|
||||
isPlatformManaged: true,
|
||||
} satisfies Prisma.UserSelect;
|
||||
|
||||
const rawEventType = await EventTypeRepository.findById({ id: eventTypeId, userId });
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const rawEventType = await eventTypeRepo.findById({ id: eventTypeId, userId });
|
||||
|
||||
if (!rawEventType) {
|
||||
if (isTrpcCall) {
|
||||
|
||||
@@ -51,6 +51,7 @@ export const getEventTypesByViewer = async (user: User, filters?: Filters, forRo
|
||||
if (isFilterSet && filters?.upIds && !isUpIdInFilter) {
|
||||
shouldListUserEvents = true;
|
||||
}
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const [profileMemberships, profileEventTypes] = await Promise.all([
|
||||
MembershipRepository.findAllByUpIdIncludeTeamWithMembersAndEventTypes(
|
||||
{
|
||||
@@ -63,7 +64,7 @@ export const getEventTypesByViewer = async (user: User, filters?: Filters, forRo
|
||||
}
|
||||
),
|
||||
shouldListUserEvents
|
||||
? EventTypeRepository.findAllByUpId(
|
||||
? eventTypeRepo.findAllByUpId(
|
||||
{
|
||||
upId: userProfile.upId,
|
||||
userId: user.id,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import type { EventType as PrismaEventType } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
|
||||
import logger from "@calcom/lib/logger";
|
||||
import type { PrismaClient } from "@calcom/prisma";
|
||||
import { prisma, availabilityUserSelect } from "@calcom/prisma";
|
||||
import type { Prisma } from "@calcom/prisma/client";
|
||||
import { MembershipRole } from "@calcom/prisma/enums";
|
||||
import { credentialForCalendarServiceSelect } from "@calcom/prisma/selects/credential";
|
||||
import { EventTypeMetaDataSchema, rrSegmentQueryValueSchema } from "@calcom/prisma/zod-utils";
|
||||
@@ -68,7 +69,9 @@ function usersWithSelectedCalendars<
|
||||
}
|
||||
|
||||
export class EventTypeRepository {
|
||||
private static generateCreateEventTypeData = (eventTypeCreateData: IEventType) => {
|
||||
constructor(private prismaClient: PrismaClient) {}
|
||||
|
||||
private generateCreateEventTypeData = (eventTypeCreateData: IEventType) => {
|
||||
const {
|
||||
userId,
|
||||
profileId,
|
||||
@@ -122,8 +125,8 @@ export class EventTypeRepository {
|
||||
};
|
||||
};
|
||||
|
||||
static async create(data: IEventType) {
|
||||
return await prisma.eventType.create({
|
||||
async create(data: IEventType) {
|
||||
return await this.prismaClient.eventType.create({
|
||||
data: this.generateCreateEventTypeData(data),
|
||||
include: {
|
||||
calVideoSettings: true,
|
||||
@@ -131,13 +134,13 @@ export class EventTypeRepository {
|
||||
});
|
||||
}
|
||||
|
||||
static async createMany(data: IEventType[]) {
|
||||
return await prisma.eventType.createMany({
|
||||
async createMany(data: IEventType[]) {
|
||||
return await this.prismaClient.eventType.createMany({
|
||||
data: data.map((d) => this.generateCreateEventTypeData(d)),
|
||||
});
|
||||
}
|
||||
|
||||
static async findAllByUpId(
|
||||
async findAllByUpId(
|
||||
{ upId, userId }: { upId: string; userId: number },
|
||||
{
|
||||
orderBy,
|
||||
@@ -184,7 +187,7 @@ export class EventTypeRepository {
|
||||
|
||||
if (!profileId) {
|
||||
// Lookup is by userId
|
||||
return await prisma.eventType.findMany({
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
userId: lookupTarget.id,
|
||||
...where,
|
||||
@@ -200,7 +203,7 @@ export class EventTypeRepository {
|
||||
if (profile?.movedFromUser) {
|
||||
// Because the user has been moved to this profile, we need to get all user events except those that belong to some other profile
|
||||
// This is because those event-types that are created after moving to profile would have profileId but existing event-types would have profileId set to null
|
||||
return await prisma.eventType.findMany({
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
// Existing events
|
||||
@@ -228,7 +231,7 @@ export class EventTypeRepository {
|
||||
orderBy,
|
||||
});
|
||||
} else {
|
||||
return await prisma.eventType.findMany({
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
@@ -252,7 +255,7 @@ export class EventTypeRepository {
|
||||
}
|
||||
}
|
||||
|
||||
static async findAllByUpIdWithMinimalData(
|
||||
async findAllByUpIdWithMinimalData(
|
||||
{ upId, userId }: { upId: string; userId: number },
|
||||
{
|
||||
orderBy,
|
||||
@@ -288,7 +291,7 @@ export class EventTypeRepository {
|
||||
|
||||
if (!profileId) {
|
||||
// Lookup is by userId
|
||||
return await prisma.eventType.findMany({
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
userId: lookupTarget.id,
|
||||
...where,
|
||||
@@ -304,7 +307,7 @@ export class EventTypeRepository {
|
||||
if (profile?.movedFromUser) {
|
||||
// Because the user has been moved to this profile, we need to get all user events except those that belong to some other profile
|
||||
// This is because those event-types that are created after moving to profile would have profileId but existing event-types would have profileId set to null
|
||||
return await prisma.eventType.findMany({
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
// Existing events
|
||||
@@ -332,7 +335,7 @@ export class EventTypeRepository {
|
||||
orderBy,
|
||||
});
|
||||
} else {
|
||||
return await prisma.eventType.findMany({
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
@@ -356,7 +359,7 @@ export class EventTypeRepository {
|
||||
}
|
||||
}
|
||||
|
||||
static async findTeamEventTypes({
|
||||
async findTeamEventTypes({
|
||||
teamId,
|
||||
parentId,
|
||||
userId,
|
||||
@@ -397,7 +400,7 @@ export class EventTypeRepository {
|
||||
},
|
||||
};
|
||||
|
||||
const teamMembership = await prisma.membership.findFirst({
|
||||
const teamMembership = await this.prismaClient.membership.findFirst({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
@@ -437,16 +440,16 @@ export class EventTypeRepository {
|
||||
});
|
||||
}
|
||||
|
||||
static async findAllByUserId({ userId }: { userId: number }) {
|
||||
return await prisma.eventType.findMany({
|
||||
async findAllByUserId({ userId }: { userId: number }) {
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
userId,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static async findTitleById({ id }: { id: number }) {
|
||||
return await prisma.eventType.findUnique({
|
||||
async findTitleById({ id }: { id: number }) {
|
||||
return await this.prismaClient.eventType.findUnique({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
@@ -456,8 +459,8 @@ export class EventTypeRepository {
|
||||
});
|
||||
}
|
||||
|
||||
static async findByIdWithUserAccess({ id, userId }: { id: number; userId: number }) {
|
||||
return await prisma.eventType.findUnique({
|
||||
async findByIdWithUserAccess({ id, userId }: { id: number; userId: number }) {
|
||||
return await this.prismaClient.eventType.findUnique({
|
||||
where: {
|
||||
id,
|
||||
OR: [{ userId }, { hosts: { some: { userId } } }, { users: { some: { id: userId } } }],
|
||||
@@ -465,7 +468,7 @@ export class EventTypeRepository {
|
||||
});
|
||||
}
|
||||
|
||||
static async findById({ id, userId }: { id: number; userId: number }) {
|
||||
async findById({ id, userId }: { id: number; userId: number }) {
|
||||
const userSelect = {
|
||||
name: true,
|
||||
avatarUrl: true,
|
||||
@@ -716,7 +719,7 @@ export class EventTypeRepository {
|
||||
// This is more efficient than using a complex join with team.members in the query
|
||||
const userTeamIds = await MembershipRepository.findUserTeamIds({ userId });
|
||||
|
||||
return await prisma.eventType.findFirst({
|
||||
return await this.prismaClient.eventType.findFirst({
|
||||
where: {
|
||||
AND: [
|
||||
{
|
||||
@@ -745,24 +748,16 @@ export class EventTypeRepository {
|
||||
});
|
||||
}
|
||||
|
||||
static async findByIdMinimal({ id }: { id: number }) {
|
||||
return await prisma.eventType.findUnique({
|
||||
async findByIdMinimal({ id }: { id: number }) {
|
||||
return await this.prismaClient.eventType.findUnique({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
static async findFirstEventTypeId({
|
||||
slug,
|
||||
teamId,
|
||||
userId,
|
||||
}: {
|
||||
slug: string;
|
||||
teamId?: number;
|
||||
userId?: number;
|
||||
}) {
|
||||
return prisma.eventType.findFirst({
|
||||
async findFirstEventTypeId({ slug, teamId, userId }: { slug: string; teamId?: number; userId?: number }) {
|
||||
return this.prismaClient.eventType.findFirst({
|
||||
where: {
|
||||
slug,
|
||||
...(teamId ? { teamId } : {}),
|
||||
@@ -774,8 +769,8 @@ export class EventTypeRepository {
|
||||
});
|
||||
}
|
||||
|
||||
static async findByIdIncludeHostsAndTeam({ id }: { id: number }) {
|
||||
const eventType = await prisma.eventType.findUnique({
|
||||
async findByIdIncludeHostsAndTeam({ id }: { id: number }) {
|
||||
const eventType = await this.prismaClient.eventType.findUnique({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
@@ -818,8 +813,8 @@ export class EventTypeRepository {
|
||||
};
|
||||
}
|
||||
|
||||
static async findAllByTeamIdIncludeManagedEventTypes({ teamId }: { teamId?: number }) {
|
||||
return await prisma.eventType.findMany({
|
||||
async findAllByTeamIdIncludeManagedEventTypes({ teamId }: { teamId?: number }) {
|
||||
return await this.prismaClient.eventType.findMany({
|
||||
where: {
|
||||
OR: [
|
||||
{
|
||||
@@ -835,8 +830,8 @@ export class EventTypeRepository {
|
||||
});
|
||||
}
|
||||
|
||||
static async findForSlots({ id }: { id: number }) {
|
||||
const eventType = await prisma.eventType.findUnique({
|
||||
async findForSlots({ id }: { id: number }) {
|
||||
const eventType = await this.prismaClient.eventType.findUnique({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
|
||||
@@ -126,7 +126,8 @@ export const createHandler = async ({ ctx, input }: CreateOptions) => {
|
||||
|
||||
const profile = ctx.user.profile;
|
||||
try {
|
||||
const eventType = await EventTypeRepository.create({
|
||||
const eventTypeRepo = new EventTypeRepository(ctx.prisma);
|
||||
const eventType = await eventTypeRepo.create({
|
||||
...data,
|
||||
profileId: profile.id,
|
||||
});
|
||||
|
||||
@@ -151,7 +151,8 @@ export const duplicateHandler = async ({ ctx, input }: DuplicateOptions) => {
|
||||
}
|
||||
}
|
||||
|
||||
const newEventType = await EventTypeRepository.create(data);
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const newEventType = await eventTypeRepo.create(data);
|
||||
|
||||
// Create custom inputs
|
||||
if (customInputs) {
|
||||
|
||||
@@ -21,7 +21,7 @@ type GetByViewerOptions = {
|
||||
input: TGetEventTypesFromGroupSchema;
|
||||
};
|
||||
|
||||
type EventType = Awaited<ReturnType<typeof EventTypeRepository.findAllByUpId>>[number];
|
||||
type EventType = Awaited<ReturnType<EventTypeRepository["findAllByUpId"]>>[number];
|
||||
type MappedEventType = Awaited<ReturnType<typeof mapEventType>>;
|
||||
|
||||
export const getEventTypesFromGroup = async ({
|
||||
@@ -47,6 +47,7 @@ export const getEventTypesFromGroup = async ({
|
||||
!isFilterSet || isUpIdInFilter || (isFilterSet && filters?.upIds && !isUpIdInFilter);
|
||||
|
||||
const eventTypes: EventType[] = [];
|
||||
const eventTypeRepo = new EventTypeRepository(ctx.prisma);
|
||||
|
||||
if (shouldListUserEvents || !teamId) {
|
||||
const baseQueryConditions = {
|
||||
@@ -56,7 +57,7 @@ export const getEventTypesFromGroup = async ({
|
||||
};
|
||||
|
||||
const [nonChildEventTypes, childEventTypes] = await Promise.all([
|
||||
EventTypeRepository.findAllByUpId(
|
||||
eventTypeRepo.findAllByUpId(
|
||||
{
|
||||
upId: userProfile.upId,
|
||||
userId: ctx.user.id,
|
||||
@@ -78,7 +79,7 @@ export const getEventTypesFromGroup = async ({
|
||||
cursor,
|
||||
}
|
||||
),
|
||||
EventTypeRepository.findAllByUpId(
|
||||
eventTypeRepo.findAllByUpId(
|
||||
{
|
||||
upId: userProfile.upId,
|
||||
userId: ctx.user.id,
|
||||
@@ -117,7 +118,7 @@ export const getEventTypesFromGroup = async ({
|
||||
|
||||
if (teamId) {
|
||||
const teamEventTypes =
|
||||
(await EventTypeRepository.findTeamEventTypes({
|
||||
(await eventTypeRepo.findTeamEventTypes({
|
||||
teamId,
|
||||
parentId,
|
||||
userId: ctx.user.id,
|
||||
|
||||
+2
-1
@@ -53,6 +53,7 @@ export const getTeamAndEventTypeOptions = async ({ ctx, input }: GetTeamAndEvent
|
||||
const parentOrgHasLockedEventTypes =
|
||||
profile?.organization?.organizationSettings?.lockEventTypeCreationForUsers;
|
||||
|
||||
const eventTypeRepo = new EventTypeRepository(ctx.prisma);
|
||||
const [profileMemberships, profileEventTypes] = await Promise.all([
|
||||
MembershipRepository.findAllByUpIdIncludeMinimalEventTypes(
|
||||
{
|
||||
@@ -67,7 +68,7 @@ export const getTeamAndEventTypeOptions = async ({ ctx, input }: GetTeamAndEvent
|
||||
),
|
||||
teamId
|
||||
? []
|
||||
: EventTypeRepository.findAllByUpIdWithMinimalData(
|
||||
: eventTypeRepo.findAllByUpIdWithMinimalData(
|
||||
{
|
||||
upId: userProfile.upId,
|
||||
userId: user.id,
|
||||
|
||||
@@ -14,7 +14,7 @@ import { TRPCError } from "@trpc/server";
|
||||
import authedProcedure from "../../../procedures/authedProcedure";
|
||||
import type { TUpdateInputSchema } from "./types";
|
||||
|
||||
type EventType = Awaited<ReturnType<typeof EventTypeRepository.findAllByUpId>>[number];
|
||||
type EventType = Awaited<ReturnType<EventTypeRepository["findAllByUpId"]>>[number];
|
||||
|
||||
export const eventOwnerProcedure = authedProcedure
|
||||
.input(
|
||||
|
||||
+2
-1
@@ -177,7 +177,8 @@ export const findTeamMembersMatchingAttributeLogicOfRouteHandler = async ({
|
||||
});
|
||||
}
|
||||
|
||||
const eventType = await EventTypeRepository.findByIdIncludeHostsAndTeam({ id: eventTypeId });
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const eventType = await eventTypeRepo.findByIdIncludeHostsAndTeam({ id: eventTypeId });
|
||||
|
||||
if (!eventType) {
|
||||
throw new TRPCError({
|
||||
|
||||
@@ -32,7 +32,8 @@ export const isAvailableHandler = async ({
|
||||
const { slots, eventTypeId } = input;
|
||||
|
||||
// Get event type details for time bounds validation
|
||||
const eventType = await EventTypeRepository.findByIdMinimal({ id: eventTypeId });
|
||||
const eventTypeRepo = new EventTypeRepository(ctx.prisma);
|
||||
const eventType = await eventTypeRepo.findByIdMinimal({ id: eventTypeId });
|
||||
|
||||
if (!eventType) {
|
||||
throw new HttpError({ statusCode: 404, message: "Event type not found" });
|
||||
|
||||
@@ -211,7 +211,8 @@ export class AvailableSlotsService {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await EventTypeRepository.findForSlots({ id: eventTypeId });
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
return await eventTypeRepo.findForSlots({ id: eventTypeId });
|
||||
}
|
||||
|
||||
private getEventType = withReporting(this._getEventType.bind(this), "getEventType");
|
||||
@@ -281,7 +282,8 @@ export class AvailableSlotsService {
|
||||
organizationDetails ?? { currentOrgDomain: null, isValidOrgDomain: false }
|
||||
);
|
||||
}
|
||||
const eventType = await EventTypeRepository.findFirstEventTypeId({ slug: eventTypeSlug, teamId, userId });
|
||||
const eventTypeRepo = new EventTypeRepository(prisma);
|
||||
const eventType = await eventTypeRepo.findFirstEventTypeId({ slug: eventTypeSlug, teamId, userId });
|
||||
if (!eventType) {
|
||||
throw new TRPCError({ code: "NOT_FOUND" });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user