Skip to content

Commit cd576f5

Browse files
refactor: use dependency injection for InsightsBookingService (calcom#22790)
* refactor: use dependency injection for InsightsBookingService - Add DI tokens for InsightsBookingService and module - Rename InsightsBookingService to InsightsBookingBaseService - Create InsightsBookingService DI interface with create method - Add DI module and container for InsightsBookingService - Update tRPC router to use getInsightsBookingService DI container - Update test file to use InsightsBookingBaseService - Update documentation to reflect new DI pattern Follows the same dependency injection pattern established for InsightsRoutingService in PR calcom#22677 Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: restore createInsightsBookingService helper using DI internally - Keep createInsightsBookingService helper function for cleaner API - Use getInsightsBookingService DI container internally - Maintain same function signature and behavior - All existing calls continue to work unchanged Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * refactor: rename service files with proper capitalization - Rename insightsBookingBase.ts to InsightsBookingBaseService.ts - Rename insightsBookingDI.ts to InsightsBookingDIService.ts - Update all import statements to use new file names - Maintain existing handler functionality using createInsightsBookingService(ctx, input) Co-Authored-By: eunjae@cal.com <hey@eunjae.dev> * revert some changes * rename * update doc --------- Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 2965450 commit cd576f5

9 files changed

Lines changed: 81 additions & 12 deletions

File tree

packages/features/insights/HOW_TO_ADD_BOOKING_CHARTS.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export default function InsightsPage() {
103103

104104
## Step 4: Create tRPC Handler
105105

106-
Add the tRPC endpoint in the insights router using the `createInsightsBookingService()` helper:
106+
Add the tRPC endpoint in the insights router using the `getInsightsBookingService()` DI container function:
107107

108108
```typescript
109109
// packages/features/insights/server/trpc-router.ts
@@ -118,6 +118,7 @@ export const insightsRouter = router({
118118
myNewChartData: userBelongsToTeamProcedure
119119
.input(bookingRepositoryBaseInputSchema)
120120
.query(async ({ ctx, input }) => {
121+
// `createInsightsBookingService` is defined at the root level in this file
121122
const insightsBookingService = createInsightsBookingService(ctx, input);
122123

123124
try {
@@ -129,13 +130,13 @@ export const insightsRouter = router({
129130
});
130131
```
131132

132-
## Step 5: Add Service Method to InsightsBookingService
133+
## Step 5: Add Service Method to InsightsBookingBaseService
133134

134-
Add your new method to the `InsightsBookingService` class:
135+
Add your new method to the `InsightsBookingBaseService` class:
135136

136137
```typescript
137-
// packages/lib/server/service/insightsBooking.ts
138-
export class InsightsBookingService {
138+
// packages/lib/server/service/InsightsBookingBaseService.ts
139+
export class InsightsBookingBaseService {
139140
// ... existing methods
140141

141142
async getMyNewChartData() {
@@ -168,7 +169,7 @@ export class InsightsBookingService {
168169

169170
## Best Practices
170171

171-
1. **Use `createInsightsBookingService()`**: Always use the helper function for consistent service creation
172+
1. **Use `getInsightsBookingService()`**: Always use the DI container function for consistent service creation
172173
2. **Raw SQL for Performance**: Use `$queryRaw` for complex aggregations and better performance
173174
3. **Base Conditions**: Always use `await this.getBaseConditions()` for proper filtering and permissions
174175
4. **Error Handling**: Wrap service calls in try-catch blocks with `TRPCError`

packages/features/insights/server/trpc-router.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {
99
routingRepositoryBaseInputSchema,
1010
bookingRepositoryBaseInputSchema,
1111
} from "@calcom/features/insights/server/raw-data.schema";
12+
import { getInsightsBookingService } from "@calcom/lib/di/containers/insights-booking";
1213
import { getInsightsRoutingService } from "@calcom/lib/di/containers/insights-routing";
13-
import { InsightsBookingService } from "@calcom/lib/server/service/insightsBooking";
1414
import type { readonlyPrisma } from "@calcom/prisma";
1515
import { BookingStatus } from "@calcom/prisma/enums";
1616
import authedProcedure from "@calcom/trpc/server/procedures/authedProcedure";
@@ -316,14 +316,13 @@ const BATCH_SIZE = 1000; // Adjust based on your needs
316316
* Helper function to create InsightsBookingService with standardized parameters
317317
*/
318318
function createInsightsBookingService(
319-
ctx: { insightsDb: typeof readonlyPrisma; user: { id: number; organizationId: number | null } },
319+
ctx: { user: { id: number; organizationId: number | null } },
320320
input: z.infer<typeof bookingRepositoryBaseInputSchema>,
321321
dateTarget: "createdAt" | "startTime" = "createdAt"
322322
) {
323323
const { scope, selectedTeamId, startDate, endDate, columnFilters } = input;
324324

325-
return new InsightsBookingService({
326-
prisma: ctx.insightsDb,
325+
return getInsightsBookingService({
327326
options: {
328327
scope,
329328
userId: ctx.user.id,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { createContainer } from "@evyweb/ioctopus";
2+
3+
import { DI_TOKENS } from "@calcom/lib/di/tokens";
4+
import type {
5+
InsightsBookingServicePublicOptions,
6+
InsightsBookingServiceFilterOptions,
7+
InsightsBookingBaseService,
8+
} from "@calcom/lib/server/service/InsightsBookingBaseService";
9+
import type { InsightsBookingService } from "@calcom/lib/server/service/InsightsBookingDIService";
10+
import { prismaModule } from "@calcom/prisma/prisma.module";
11+
12+
import { insightsBookingModule } from "../modules/insights-booking";
13+
14+
export function getInsightsBookingService({
15+
options,
16+
filters,
17+
}: {
18+
options: InsightsBookingServicePublicOptions;
19+
filters?: InsightsBookingServiceFilterOptions;
20+
}): InsightsBookingBaseService {
21+
const container = createContainer();
22+
container.load(DI_TOKENS.READ_ONLY_PRISMA_CLIENT, prismaModule);
23+
container.load(DI_TOKENS.INSIGHTS_BOOKING_SERVICE_MODULE, insightsBookingModule);
24+
25+
const diService = container.get<InsightsBookingService>(DI_TOKENS.INSIGHTS_BOOKING_SERVICE);
26+
return diService.create({ options, filters });
27+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { createModule } from "@evyweb/ioctopus";
2+
3+
import type { IInsightsBookingService } from "@calcom/lib/server/service/InsightsBookingDIService";
4+
import { InsightsBookingService } from "@calcom/lib/server/service/InsightsBookingDIService";
5+
6+
import { DI_TOKENS } from "../tokens";
7+
8+
export const insightsBookingModule = createModule();
9+
insightsBookingModule.bind(DI_TOKENS.INSIGHTS_BOOKING_SERVICE).toClass(InsightsBookingService, {
10+
prisma: DI_TOKENS.READ_ONLY_PRISMA_CLIENT,
11+
} satisfies Record<keyof IInsightsBookingService, symbol>);

packages/lib/di/tokens.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export const DI_TOKENS = {
2222
AVAILABLE_SLOTS_SERVICE_MODULE: Symbol("AvailableSlotsModule"),
2323
INSIGHTS_ROUTING_SERVICE: Symbol("InsightsRoutingService"),
2424
INSIGHTS_ROUTING_SERVICE_MODULE: Symbol("InsightsRoutingServiceModule"),
25+
INSIGHTS_BOOKING_SERVICE: Symbol("InsightsBookingService"),
26+
INSIGHTS_BOOKING_SERVICE_MODULE: Symbol("InsightsBookingServiceModule"),
2527
FEATURES_REPOSITORY: Symbol("FeaturesRepository"),
2628
FEATURES_REPOSITORY_MODULE: Symbol("FeaturesRepositoryModule"),
2729
CACHE_SERVICE: Symbol("CacheService"),

packages/lib/server/service/insightsBooking.ts renamed to packages/lib/server/service/InsightsBookingBaseService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ const NOTHING_CONDITION = Prisma.sql`1=0`;
135135

136136
const bookingDataKeys = new Set(Object.keys(bookingDataSchema.shape));
137137

138-
export class InsightsBookingService {
138+
export class InsightsBookingBaseService {
139139
private prisma: typeof readonlyPrisma;
140140
private options: InsightsBookingServiceOptions | null;
141141
private filters: InsightsBookingServiceFilterOptions | null;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import type { readonlyPrisma } from "@calcom/prisma";
2+
3+
import {
4+
InsightsBookingBaseService,
5+
type InsightsBookingServicePublicOptions,
6+
type InsightsBookingServiceFilterOptions,
7+
} from "./InsightsBookingBaseService";
8+
9+
export interface IInsightsBookingService {
10+
prisma: typeof readonlyPrisma;
11+
}
12+
13+
export class InsightsBookingService {
14+
constructor(private readonly dependencies: IInsightsBookingService) {}
15+
16+
create({
17+
options,
18+
filters,
19+
}: {
20+
options: InsightsBookingServicePublicOptions;
21+
filters?: InsightsBookingServiceFilterOptions;
22+
}): InsightsBookingBaseService {
23+
return new InsightsBookingBaseService({
24+
prisma: this.dependencies.prisma,
25+
options,
26+
filters,
27+
});
28+
}
29+
}

packages/lib/server/service/__tests__/insightsBooking.integration-test.ts renamed to packages/lib/server/service/__tests__/InsightsBookingService.integration-test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { ColumnFilterType } from "@calcom/features/data-table/lib/types";
66
import prisma from "@calcom/prisma";
77
import { BookingStatus, MembershipRole } from "@calcom/prisma/enums";
88

9-
import { InsightsBookingService } from "../../service/insightsBooking";
9+
import { InsightsBookingBaseService as InsightsBookingService } from "../InsightsBookingBaseService";
1010

1111
const NOTHING_CONDITION = Prisma.sql`1=0`;
1212

packages/lib/server/service/__tests__/insightsRouting.integration-test.ts renamed to packages/lib/server/service/__tests__/InsightsRoutingService.integration-test.ts

File renamed without changes.

0 commit comments

Comments
 (0)