diff --git a/src/repositories/shuttle/RedisShuttleRepository.ts b/src/repositories/shuttle/RedisShuttleRepository.ts index 59b9eff..6e8ea18 100644 --- a/src/repositories/shuttle/RedisShuttleRepository.ts +++ b/src/repositories/shuttle/RedisShuttleRepository.ts @@ -525,7 +525,7 @@ export class RedisShuttleRepository extends EventEmitter implements ShuttleGette } } - public async addTravelTimeDataPoint( + private async addTravelTimeDataPoint( { routeId, fromStopId, toStopId }: ShuttleTravelTimeDataIdentifier, travelTimeSeconds: number, timestamp = Date.now(), @@ -626,7 +626,7 @@ export class RedisShuttleRepository extends EventEmitter implements ShuttleGette }; } - public async updateShuttleLastStopArrival(shuttleId: string, lastStopArrival: ShuttleStopArrival) { + private async updateShuttleLastStopArrival(shuttleId: string, lastStopArrival: ShuttleStopArrival) { const key = this.createShuttleLastStopKey(shuttleId); await this.redisClient.hSet(key, { stopId: lastStopArrival.stopId, diff --git a/src/repositories/shuttle/__tests__/RedisShuttleRepository.test.ts b/src/repositories/shuttle/__tests__/RedisShuttleRepository.test.ts index 975d360..2e143e0 100644 --- a/src/repositories/shuttle/__tests__/RedisShuttleRepository.test.ts +++ b/src/repositories/shuttle/__tests__/RedisShuttleRepository.test.ts @@ -205,19 +205,26 @@ describe("RedisShuttleRepository", () => { describe("getShuttleLastStopArrival", () => { it("gets the shuttle's last stop if existing in the data", async () => { - const mockShuttles = generateMockShuttles(); - const shuttle = mockShuttles[0]; - const stopArrival = { - stopId: "st1", - timestamp: new Date("2024-01-15T10:30:00Z"), + const { route, systemId, stop1 } = await setupRouteAndOrderedStops(); + + const shuttle = { + id: "sh1", + name: "Shuttle 1", + routeId: route.id, + systemId: systemId, + coordinates: stop1.coordinates, + orientationInDegrees: 0, + updatedTime: new Date(), }; - await repository.updateShuttleLastStopArrival(shuttle.id, stopArrival); + const stopArrivalTime = new Date("2024-01-15T10:30:00Z"); + await repository.addOrUpdateShuttle(shuttle, stopArrivalTime.getTime()); + const result = await repository.getShuttleLastStopArrival(shuttle.id); expect(result).toBeDefined(); - expect(result?.stopId).toBe(stopArrival.stopId); - expect(result?.timestamp.getTime()).toBe(stopArrival.timestamp.getTime()); + expect(result?.stopId).toBe(stop1.id); + expect(result?.timestamp.getTime()).toBe(stopArrivalTime.getTime()); }); it("returns undefined if the data has never been initialized", async () => { @@ -230,45 +237,55 @@ describe("RedisShuttleRepository", () => { }); it("returns the most recent stop arrival when updated multiple times", async () => { - const mockShuttles = generateMockShuttles(); - const shuttle = mockShuttles[0]; + const { route, systemId, stop1, stop2 } = await setupRouteAndOrderedStops(); - const firstArrival = { - stopId: "st1", - timestamp: new Date("2024-01-15T10:30:00Z"), + const shuttle = { + id: "sh1", + name: "Shuttle 1", + routeId: route.id, + systemId: systemId, + coordinates: stop1.coordinates, + orientationInDegrees: 0, + updatedTime: new Date(), }; - const secondArrival = { - stopId: "st2", - timestamp: new Date("2024-01-15T10:35:00Z"), - }; + const firstArrivalTime = new Date("2024-01-15T10:30:00Z"); + await repository.addOrUpdateShuttle(shuttle, firstArrivalTime.getTime()); - await repository.updateShuttleLastStopArrival(shuttle.id, firstArrival); - await repository.updateShuttleLastStopArrival(shuttle.id, secondArrival); + shuttle.coordinates = stop2.coordinates; + const secondArrivalTime = new Date("2024-01-15T10:35:00Z"); + await repository.addOrUpdateShuttle(shuttle, secondArrivalTime.getTime()); const result = await repository.getShuttleLastStopArrival(shuttle.id); expect(result).toBeDefined(); - expect(result?.stopId).toBe(secondArrival.stopId); - expect(result?.timestamp.getTime()).toBe(secondArrival.timestamp.getTime()); + expect(result?.stopId).toBe(stop2.id); + expect(result?.timestamp.getTime()).toBe(secondArrivalTime.getTime()); }); }); describe("getAverageTravelTimeSeconds", () => { it("returns the average travel time when historical data exists", async () => { - const { route, stop2, stop1 } = await setupRouteAndOrderedStops(); + const { route, systemId, stop1, stop2 } = await setupRouteAndOrderedStops(); - // Add a single data point: 15 minutes travel time - const timestamp = new Date(2025, 0, 1, 12, 15, 0); - await repository.addTravelTimeDataPoint( - { - routeId: route.id, - fromStopId: stop1.id, - toStopId: stop2.id, - }, - 15 * 60, // 15 minutes in seconds - timestamp.getTime() - ); + const shuttle = { + id: "sh1", + name: "Shuttle 1", + routeId: route.id, + systemId: systemId, + coordinates: stop1.coordinates, + orientationInDegrees: 0, + updatedTime: new Date(), + }; + + // Shuttle arrives at stop1 + const firstStopTime = new Date(2025, 0, 1, 12, 0, 0); + await repository.addOrUpdateShuttle(shuttle, firstStopTime.getTime()); + + // Shuttle moves to stop2 (15 minutes later) + shuttle.coordinates = stop2.coordinates; + const secondStopTime = new Date(2025, 0, 1, 12, 15, 0); + await repository.addOrUpdateShuttle(shuttle, secondStopTime.getTime()); const travelTime = await repository.getAverageTravelTimeSeconds({ routeId: route.id, @@ -283,29 +300,28 @@ describe("RedisShuttleRepository", () => { }); it("returns average of multiple data points", async () => { - const { route, stop2, stop1 } = await setupRouteAndOrderedStops(); + const { route, systemId, stop1, stop2 } = await setupRouteAndOrderedStops(); + + const shuttle = { + id: "sh1", + name: "Shuttle 1", + routeId: route.id, + systemId: systemId, + coordinates: stop1.coordinates, + orientationInDegrees: 0, + updatedTime: new Date(), + }; // First trip: 10 minutes travel time - await repository.addTravelTimeDataPoint( - { - routeId: route.id, - fromStopId: stop1.id, - toStopId: stop2.id, - }, - 10 * 60, // 10 minutes - new Date(2025, 0, 1, 12, 0, 0).getTime() - ); + await repository.addOrUpdateShuttle(shuttle, new Date(2025, 0, 1, 12, 0, 0).getTime()); + shuttle.coordinates = stop2.coordinates; + await repository.addOrUpdateShuttle(shuttle, new Date(2025, 0, 1, 12, 10, 0).getTime()); // Second trip: 20 minutes travel time - await repository.addTravelTimeDataPoint( - { - routeId: route.id, - fromStopId: stop1.id, - toStopId: stop2.id, - }, - 20 * 60, // 20 minutes - new Date(2025, 0, 1, 13, 0, 0).getTime() - ); + shuttle.coordinates = stop1.coordinates; + await repository.addOrUpdateShuttle(shuttle, new Date(2025, 0, 1, 12, 30, 0).getTime()); + shuttle.coordinates = stop2.coordinates; + await repository.addOrUpdateShuttle(shuttle, new Date(2025, 0, 1, 12, 50, 0).getTime()); const averageTravelTime = await repository.getAverageTravelTimeSeconds({ routeId: route.id, @@ -337,18 +353,22 @@ describe("RedisShuttleRepository", () => { }); it("returns undefined when querying outside the time range of data", async () => { - const { route, stop2, stop1 } = await setupRouteAndOrderedStops(); + const { route, systemId, stop1, stop2 } = await setupRouteAndOrderedStops(); + + const shuttle = { + id: "sh1", + name: "Shuttle 1", + routeId: route.id, + systemId: systemId, + coordinates: stop1.coordinates, + orientationInDegrees: 0, + updatedTime: new Date(), + }; // Add data on Jan 1 - await repository.addTravelTimeDataPoint( - { - routeId: route.id, - fromStopId: stop1.id, - toStopId: stop2.id, - }, - 15 * 60, // 15 minutes - new Date(2025, 0, 1, 12, 15, 0).getTime() - ); + await repository.addOrUpdateShuttle(shuttle, new Date(2025, 0, 1, 12, 0, 0).getTime()); + shuttle.coordinates = stop2.coordinates; + await repository.addOrUpdateShuttle(shuttle, new Date(2025, 0, 1, 12, 15, 0).getTime()); // Query for Jan 2 (no data should exist in this range) const averageTravelTime = await repository.getAverageTravelTimeSeconds({