mirror of
https://github.com/kennethnym/aris.git
synced 2026-03-20 17:11:17 +00:00
perf: cache fetched events within a refresh cycle
FeedEngine calls fetchContext then fetchItems with the same context. Cache events by context.time reference to avoid duplicate CalDAV round-trips. Co-authored-by: Ona <no-reply@ona.com>
This commit is contained in:
@@ -48,6 +48,7 @@ class MockCredentialProvider implements CalendarCredentialProvider {
|
|||||||
|
|
||||||
class MockDAVClient implements CalendarDAVClient {
|
class MockDAVClient implements CalendarDAVClient {
|
||||||
credentials: Record<string, unknown> = {}
|
credentials: Record<string, unknown> = {}
|
||||||
|
fetchCalendarsCallCount = 0
|
||||||
private calendars: CalendarDAVCalendar[]
|
private calendars: CalendarDAVCalendar[]
|
||||||
private objectsByCalendarUrl: Record<string, CalendarDAVObject[]>
|
private objectsByCalendarUrl: Record<string, CalendarDAVObject[]>
|
||||||
|
|
||||||
@@ -62,6 +63,7 @@ class MockDAVClient implements CalendarDAVClient {
|
|||||||
async login(): Promise<void> {}
|
async login(): Promise<void> {}
|
||||||
|
|
||||||
async fetchCalendars(): Promise<CalendarDAVCalendar[]> {
|
async fetchCalendars(): Promise<CalendarDAVCalendar[]> {
|
||||||
|
this.fetchCalendarsCallCount++
|
||||||
return this.calendars
|
return this.calendars
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,6 +243,40 @@ describe("CalendarSource", () => {
|
|||||||
expect(exception!.data.recurrenceId).not.toBeNull()
|
expect(exception!.data.recurrenceId).not.toBeNull()
|
||||||
expect(exception!.id).toContain("-")
|
expect(exception!.id).toContain("-")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("caches events within the same refresh cycle", async () => {
|
||||||
|
const objects: Record<string, CalendarDAVObject[]> = {
|
||||||
|
"/cal/work": [{ url: "/cal/work/event1.ics", data: loadFixture("single-event.ics") }],
|
||||||
|
}
|
||||||
|
const client = new MockDAVClient([{ url: "/cal/work", displayName: "Work" }], objects)
|
||||||
|
const source = new CalendarSource(new MockCredentialProvider(), "user-1", {
|
||||||
|
davClient: client,
|
||||||
|
})
|
||||||
|
|
||||||
|
const context = createContext(new Date("2026-01-15T12:00:00Z"))
|
||||||
|
|
||||||
|
await source.fetchContext(context)
|
||||||
|
await source.fetchItems(context)
|
||||||
|
|
||||||
|
// Same context.time reference — fetchEvents should only hit the client once
|
||||||
|
expect(client.fetchCalendarsCallCount).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
test("refetches events for a different context time", async () => {
|
||||||
|
const objects: Record<string, CalendarDAVObject[]> = {
|
||||||
|
"/cal/work": [{ url: "/cal/work/event1.ics", data: loadFixture("single-event.ics") }],
|
||||||
|
}
|
||||||
|
const client = new MockDAVClient([{ url: "/cal/work", displayName: "Work" }], objects)
|
||||||
|
const source = new CalendarSource(new MockCredentialProvider(), "user-1", {
|
||||||
|
davClient: client,
|
||||||
|
})
|
||||||
|
|
||||||
|
await source.fetchItems(createContext(new Date("2026-01-15T12:00:00Z")))
|
||||||
|
await source.fetchItems(createContext(new Date("2026-01-15T13:00:00Z")))
|
||||||
|
|
||||||
|
// Different context.time references — should fetch twice
|
||||||
|
expect(client.fetchCalendarsCallCount).toBe(2)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("CalendarSource.fetchContext", () => {
|
describe("CalendarSource.fetchContext", () => {
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ export class CalendarSource implements FeedSource<CalendarFeedItem> {
|
|||||||
private readonly injectedClient: CalendarDAVClient | null
|
private readonly injectedClient: CalendarDAVClient | null
|
||||||
private davClient: CalendarDAVClient | null = null
|
private davClient: CalendarDAVClient | null = null
|
||||||
private lastAccessToken: string | null = null
|
private lastAccessToken: string | null = null
|
||||||
|
private cachedEvents: { time: Date; events: CalendarEventData[] } | null = null
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
credentialProvider: CalendarCredentialProvider,
|
credentialProvider: CalendarCredentialProvider,
|
||||||
@@ -94,6 +95,10 @@ export class CalendarSource implements FeedSource<CalendarFeedItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async fetchEvents(context: Context): Promise<CalendarEventData[]> {
|
private async fetchEvents(context: Context): Promise<CalendarEventData[]> {
|
||||||
|
if (this.cachedEvents && this.cachedEvents.time === context.time) {
|
||||||
|
return this.cachedEvents.events
|
||||||
|
}
|
||||||
|
|
||||||
const credentials = await this.credentialProvider.fetchCredentials(this.userId)
|
const credentials = await this.credentialProvider.fetchCredentials(this.userId)
|
||||||
if (!credentials) {
|
if (!credentials) {
|
||||||
return []
|
return []
|
||||||
@@ -134,6 +139,7 @@ export class CalendarSource implements FeedSource<CalendarFeedItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.cachedEvents = { time: context.time, events: allEvents }
|
||||||
return allEvents
|
return allEvents
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user