Skip to content

Commit 82303a4

Browse files
committed
Merge branch 'main' of https://github.com/calcom/cal.com into hariom/pri-305-bookingcreateservice-rename-handlers-to-services
# Conflicts: # packages/features/bookings/lib/service/RegularBookingService.ts
2 parents f005448 + bb9c4bb commit 82303a4

594 files changed

Lines changed: 16408 additions & 2418 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/knowledge-base.md

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,224 @@ import { Button } from "@calcom/ui/components/button";
306306
- **Tests**: Same as source file + `.test.ts` or `.spec.ts`
307307
- **Avoid**: Dot-suffixes like `.service.ts`, `.repository.ts` (except for tests, types, specs)
308308

309+
## Repository Method Conventions
310+
311+
Repositories should follow consistent naming and design patterns to promote reusability and maintainability.
312+
313+
### Method Naming Rules
314+
315+
**1. Don't include the repository's entity name in method names**
316+
317+
Method names should be concise and avoid redundancy since the repository class name already indicates the entity type.
318+
319+
```typescript
320+
// ✅ Good - Concise method names
321+
class BookingRepository {
322+
findById(id: string) { ... }
323+
findByUserId(userId: string) { ... }
324+
create(data: BookingCreateInput) { ... }
325+
delete(id: string) { ... }
326+
}
327+
328+
// ❌ Bad - Redundant entity name in methods
329+
class BookingRepository {
330+
findBookingById(id: string) { ... }
331+
findBookingByUserId(userId: string) { ... }
332+
createBooking(data: BookingCreateInput) { ... }
333+
deleteBooking(id: string) { ... }
334+
}
335+
```
336+
337+
**2. Use `include` or similar keywords for methods that fetch relational data**
338+
339+
When a method retrieves additional related entities, make this explicit in the method name using keywords like `include`, `with`, or `andRelations`.
340+
341+
```typescript
342+
// ✅ Good - Clear indication of included relations
343+
class EventTypeRepository {
344+
findById(id: string) {
345+
return prisma.eventType.findUnique({
346+
where: { id },
347+
});
348+
}
349+
350+
findByIdIncludeHosts(id: string) {
351+
return prisma.eventType.findUnique({
352+
where: { id },
353+
include: {
354+
hosts: true,
355+
},
356+
});
357+
}
358+
359+
findByIdIncludeHostsAndSchedule(id: string) {
360+
return prisma.eventType.findUnique({
361+
where: { id },
362+
include: {
363+
hosts: true,
364+
schedule: true,
365+
},
366+
});
367+
}
368+
}
369+
370+
// ❌ Bad - Unclear what data is included
371+
class EventTypeRepository {
372+
findById(id: string) {
373+
return prisma.eventType.findUnique({
374+
where: { id },
375+
include: {
376+
hosts: true,
377+
schedule: true,
378+
},
379+
});
380+
}
381+
382+
findByIdForReporting(id: string) {
383+
return prisma.eventType.findUnique({
384+
where: { id },
385+
include: {
386+
hosts: true,
387+
},
388+
});
389+
}
390+
}
391+
```
392+
393+
**3. Keep methods generic and reusable - avoid use-case-specific names**
394+
395+
Repository methods should be general-purpose and describe what data they return, not how or where it's used. This promotes code reuse across different features.
396+
397+
```typescript
398+
// ✅ Good - Generic, reusable methods
399+
class BookingRepository {
400+
findByUserIdIncludeAttendees(userId: string) {
401+
return prisma.booking.findMany({
402+
where: { userId },
403+
include: {
404+
attendees: true,
405+
},
406+
});
407+
}
408+
409+
findByDateRangeIncludeEventType(startDate: Date, endDate: Date) {
410+
return prisma.booking.findMany({
411+
where: {
412+
startTime: { gte: startDate },
413+
endTime: { lte: endDate },
414+
},
415+
include: {
416+
eventType: true,
417+
},
418+
});
419+
}
420+
}
421+
422+
// ❌ Bad - Use-case-specific method names
423+
class BookingRepository {
424+
findBookingsForReporting(userId: string) {
425+
return prisma.booking.findMany({
426+
where: { userId },
427+
include: {
428+
attendees: true,
429+
},
430+
});
431+
}
432+
433+
findBookingsForDashboard(startDate: Date, endDate: Date) {
434+
return prisma.booking.findMany({
435+
where: {
436+
startTime: { gte: startDate },
437+
endTime: { lte: endDate },
438+
},
439+
include: {
440+
eventType: true,
441+
},
442+
});
443+
}
444+
}
445+
```
446+
447+
**4. No business logic in repositories**
448+
449+
Repositories should only handle data access. Business logic, validations, and complex transformations belong in the Service layer.
450+
451+
```typescript
452+
// ✅ Good - Repository only handles data access
453+
class BookingRepository {
454+
findByIdIncludeAttendees(id: string) {
455+
return prisma.booking.findUnique({
456+
where: { id },
457+
include: {
458+
attendees: true,
459+
},
460+
});
461+
}
462+
463+
updateStatus(id: string, status: BookingStatus) {
464+
return prisma.booking.update({
465+
where: { id },
466+
data: { status },
467+
});
468+
}
469+
}
470+
471+
class BookingService {
472+
async confirmBooking(bookingId: string) {
473+
const booking = await this.bookingRepository.findByIdIncludeAttendees(bookingId);
474+
475+
if (!booking) {
476+
throw new Error("Booking not found");
477+
}
478+
479+
if (booking.status !== "PENDING") {
480+
throw new Error("Only pending bookings can be confirmed");
481+
}
482+
483+
// Business logic: send confirmation emails
484+
await this.emailService.sendConfirmationToAttendees(booking.attendees);
485+
486+
// Update status through repository
487+
return this.bookingRepository.updateStatus(bookingId, "CONFIRMED");
488+
}
489+
}
490+
491+
// ❌ Bad - Business logic in repository
492+
class BookingRepository {
493+
async confirmBooking(bookingId: string) {
494+
const booking = await prisma.booking.findUnique({
495+
where: { id: bookingId },
496+
include: {
497+
attendees: true,
498+
},
499+
});
500+
501+
if (!booking) {
502+
throw new Error("Booking not found");
503+
}
504+
505+
if (booking.status !== "PENDING") {
506+
throw new Error("Only pending bookings can be confirmed");
507+
}
508+
509+
// ❌ Business logic shouldn't be here
510+
await sendEmailToAttendees(booking.attendees);
511+
512+
return prisma.booking.update({
513+
where: { id: bookingId },
514+
data: { status: "CONFIRMED" },
515+
});
516+
}
517+
}
518+
```
519+
520+
### Summary
521+
522+
- Method names should be concise: `findById` not `findBookingById`
523+
- Use `include`/`with` keywords when fetching relations: `findByIdIncludeHosts`
524+
- Keep methods generic and reusable: `findByUserIdIncludeAttendees` not `findBookingsForReporting`
525+
- No business logic in repositories - that belongs in Services
526+
309527
## When using Day.js
310528

311529
```typescript

.changeset/eighty-walls-send.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@calcom/atoms": minor
3+
---
4+
5+
This PR adds ability to display bookings of a user event for calendar view atom

.changeset/lemon-rice-smile.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@calcom/atoms": minor
3+
---
4+
5+
This PR adds an atom to list a user's schedule. Furthermore, there was also another atom introduced which can be used to create a new schedule for a user.

.github/CODEOWNERS

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
/apps/web/lib/handleOrgRedirect.ts @calcom/Foundation
1111
/apps/web/middleware.ts @calcom/Foundation
1212
/deploy/**/* @calcom/Foundation
13-
/infra/**/* @calcom/Foundation
1413
/packages/app-store/applecalendar/**/* @calcom/Foundation
1514
/packages/app-store/caldavcalendar/**/* @calcom/Foundation
1615
/packages/app-store/exchange2013calendar/**/* @calcom/Foundation

.yarn/versions/3a60c02f.yml

Whitespace-only changes.

.yarn/versions/492e4e82.yml

Whitespace-only changes.

apps/api/v1/lib/helpers/rateLimitApiKey.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type { NextApiResponse, NextApiRequest } from "next";
44
import { createMocks } from "node-mocks-http";
55
import { describe, it, expect, vi } from "vitest";
66

7-
import { handleAutoLock } from "@calcom/lib/autoLock";
7+
import { handleAutoLock } from "@calcom/features/ee/api-keys/lib/autoLock";
88
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
99
import { HttpError } from "@calcom/lib/http-error";
1010

@@ -19,7 +19,7 @@ vi.mock("@calcom/lib/checkRateLimitAndThrowError", () => ({
1919
checkRateLimitAndThrowError: vi.fn(),
2020
}));
2121

22-
vi.mock("@calcom/lib/autoLock", () => ({
22+
vi.mock("@calcom/features/ee/api-keys/lib/autoLock", () => ({
2323
handleAutoLock: vi.fn(),
2424
}));
2525

apps/api/v1/lib/helpers/rateLimitApiKey.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { NextMiddleware } from "next-api-middleware";
22

3-
import { handleAutoLock } from "@calcom/lib/autoLock";
3+
import { handleAutoLock } from "@calcom/features/ee/api-keys/lib/autoLock";
44
import { checkRateLimitAndThrowError } from "@calcom/lib/checkRateLimitAndThrowError";
55
import { HttpError } from "@calcom/lib/http-error";
66

0 commit comments

Comments
 (0)