Files
calendar/packages/features/calendar-subscription/lib/cache/CalendarCacheEventService.ts
T
Volnei MunhozGitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1eb6ff3e65 chore: calendar cache optmize (#24533)
* wip

* fix: regenerate Prisma types and fix GoogleCalendarSubscriptionAdapter tests

- Run yarn prisma generate to regenerate Prisma client with missing types (WorkflowType enum)
- Fix addMonthsFromNow helper to properly return the calculated date
- Update GoogleCalendarSubscriptionAdapter to use startOf/endOf day for time ranges
- Update test expectations to use Date objects instead of dayjs objects
- Fix all-day event test to use future date instead of today
- All tests now passing (3599 passed)

Co-Authored-By: Volnei Munhoz <volnei.munhoz@gmail.com>

* fix tests

* parametrize months ahead

* improve names

* Improve based on reviews

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2025-10-17 17:20:08 +00:00

101 lines
3.3 KiB
TypeScript

import type { CalendarSubscriptionEventItem } from "@calcom/features/calendar-subscription/lib/CalendarSubscriptionPort.interface";
import type { ICalendarCacheEventRepository } from "@calcom/features/calendar-subscription/lib/cache/CalendarCacheEventRepository.interface";
import logger from "@calcom/lib/logger";
import type { CalendarCacheEvent, SelectedCalendar } from "@calcom/prisma/client";
const log = logger.getSubLogger({ prefix: ["CalendarCacheEventService"] });
/**
* Service to handle calendar cache
*/
export class CalendarCacheEventService {
static MONTHS_AHEAD: number = 3;
constructor(
private deps: {
calendarCacheEventRepository: ICalendarCacheEventRepository;
}
) {}
/**
* Handle calendar events from provider and update the cache
*
* @param selectedCalendar
* @param calendarSubscriptionEvents
*/
async handleEvents(
selectedCalendar: SelectedCalendar,
calendarSubscriptionEvents: CalendarSubscriptionEventItem[]
): Promise<void> {
log.debug("handleEvents", { count: calendarSubscriptionEvents.length });
const toUpsert: Partial<CalendarCacheEvent>[] = [];
const toDelete: Pick<CalendarCacheEvent, "externalId" | "selectedCalendarId">[] = [];
for (const event of calendarSubscriptionEvents) {
// not storing free or cancelled events
if (event.busy && event.status !== "cancelled") {
toUpsert.push({
externalId: event.id,
selectedCalendarId: selectedCalendar.id,
start: event.start,
end: event.end,
summary: event.summary,
description: event.description,
location: event.location,
isAllDay: event.isAllDay,
timeZone: event.timeZone,
originalStartTime: event.originalStartDate,
recurringEventId: event.recurringEventId,
externalEtag: event.etag || "",
externalCreatedAt: event.createdAt,
externalUpdatedAt: event.updatedAt,
});
} else {
toDelete.push({
selectedCalendarId: selectedCalendar.id,
externalId: event.id,
});
}
}
log.info("handleEvents: applying changes to the database", {
received: calendarSubscriptionEvents.length,
toUpsert: toUpsert.length,
toDelete: toDelete.length,
});
await Promise.all([
this.deps.calendarCacheEventRepository.deleteMany(toDelete),
this.deps.calendarCacheEventRepository.upsertMany(toUpsert),
]);
}
/**
* Removes all events from the cache
*
* @param selectedCalendar calendar to cleanup
*/
async cleanupCache(selectedCalendar: SelectedCalendar): Promise<void> {
log.debug("cleanupCache", { selectedCalendarId: selectedCalendar.id });
await this.deps.calendarCacheEventRepository.deleteAllBySelectedCalendarId(selectedCalendar.id);
}
/**
* Removes stale events from the cache
*/
async cleanupStaleCache(): Promise<void> {
log.debug("cleanupStaleCache");
await this.deps.calendarCacheEventRepository.deleteStale();
}
/**
* Checks if the app is supported
*
* @param type
* @returns
*/
static isCalendarTypeSupported(type: string | null): boolean {
if (!type) return false;
// return ["google_calendar", "office365_calendar"].includes(type);
return ["google_calendar"].includes(type);
}
}