mirror of
https://github.com/brendan-ch/project-inter-server.git
synced 2026-04-19 08:50:29 +00:00
Make addTravelTimeDataPoint public, add tests, and fix the query interval
This commit is contained in:
@@ -117,7 +117,7 @@ export class RedisShuttleRepository extends EventEmitter implements ShuttleGette
|
|||||||
private createEtaKey = (shuttleId: string, stopId: string) => `shuttle:eta:${shuttleId}:${stopId}`;
|
private createEtaKey = (shuttleId: string, stopId: string) => `shuttle:eta:${shuttleId}:${stopId}`;
|
||||||
private createOrderedStopKey = (routeId: string, stopId: string) => `shuttle:orderedstop:${routeId}:${stopId}`;
|
private createOrderedStopKey = (routeId: string, stopId: string) => `shuttle:orderedstop:${routeId}:${stopId}`;
|
||||||
private createShuttleLastStopKey = (shuttleId: string) => `shuttle:laststop:${shuttleId}`;
|
private createShuttleLastStopKey = (shuttleId: string) => `shuttle:laststop:${shuttleId}`;
|
||||||
private createHistoricalEtaTimeSeriesKey =(routeId: string, fromStopId: string, toStopId: string) => {
|
private createHistoricalEtaTimeSeriesKey = (routeId: string, fromStopId: string, toStopId: string) => {
|
||||||
return `shuttle:eta:historical:${routeId}:${fromStopId}:${toStopId}`;
|
return `shuttle:eta:historical:${routeId}:${fromStopId}:${toStopId}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,7 +500,7 @@ export class RedisShuttleRepository extends EventEmitter implements ShuttleGette
|
|||||||
const timeSeriesKey = this.createHistoricalEtaTimeSeriesKey(routeId, fromStopId, toStopId);
|
const timeSeriesKey = this.createHistoricalEtaTimeSeriesKey(routeId, fromStopId, toStopId);
|
||||||
const fromTimestamp = from.getTime();
|
const fromTimestamp = from.getTime();
|
||||||
const toTimestamp = to.getTime();
|
const toTimestamp = to.getTime();
|
||||||
const intervalMs = toTimestamp - fromTimestamp;
|
const intervalMs = toTimestamp - fromTimestamp + 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const aggregationResult = await this.redisClient.sendCommand([
|
const aggregationResult = await this.redisClient.sendCommand([
|
||||||
@@ -518,14 +518,14 @@ export class RedisShuttleRepository extends EventEmitter implements ShuttleGette
|
|||||||
return parseFloat(averageValue);
|
return parseFloat(averageValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`No historical data found for route ${routeId} from stop ${fromStopId} to stop ${toStopId}`);
|
return;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn(`Failed to get average travel time: ${error instanceof Error ? error.message : String(error)}`);
|
console.warn(`Failed to get average travel time: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async addTravelTimeDataPoint(
|
public async addTravelTimeDataPoint(
|
||||||
{ routeId, fromStopId, toStopId }: ShuttleTravelTimeDataIdentifier,
|
{ routeId, fromStopId, toStopId }: ShuttleTravelTimeDataIdentifier,
|
||||||
travelTimeSeconds: number,
|
travelTimeSeconds: number,
|
||||||
timestamp = Date.now(),
|
timestamp = Date.now(),
|
||||||
|
|||||||
@@ -253,4 +253,113 @@ describe("RedisShuttleRepository", () => {
|
|||||||
expect(result?.timestamp.getTime()).toBe(secondArrival.timestamp.getTime());
|
expect(result?.timestamp.getTime()).toBe(secondArrival.timestamp.getTime());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("getAverageTravelTimeSeconds", () => {
|
||||||
|
it("returns the average travel time when historical data exists", async () => {
|
||||||
|
const { route, stop2, stop1 } = 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 travelTime = await repository.getAverageTravelTimeSeconds({
|
||||||
|
routeId: route.id,
|
||||||
|
fromStopId: stop1.id,
|
||||||
|
toStopId: stop2.id,
|
||||||
|
}, {
|
||||||
|
from: new Date(2025, 0, 1, 11, 0, 0),
|
||||||
|
to: new Date(2025, 0, 1, 13, 0, 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(travelTime).toEqual(15 * 60);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns average of multiple data points", async () => {
|
||||||
|
const { route, stop2, stop1 } = await setupRouteAndOrderedStops();
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
);
|
||||||
|
|
||||||
|
const averageTravelTime = await repository.getAverageTravelTimeSeconds({
|
||||||
|
routeId: route.id,
|
||||||
|
fromStopId: stop1.id,
|
||||||
|
toStopId: stop2.id,
|
||||||
|
}, {
|
||||||
|
from: new Date(2025, 0, 1, 11, 0, 0),
|
||||||
|
to: new Date(2025, 0, 1, 14, 0, 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Average of 10 minutes and 20 minutes = 15 minutes = 900 seconds
|
||||||
|
expect(averageTravelTime).toEqual(15 * 60);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns undefined when no data exists", async () => {
|
||||||
|
const { route, stop1, stop2 } = await setupRouteAndOrderedStops();
|
||||||
|
|
||||||
|
// Don't add any data points, just query for data that doesn't exist
|
||||||
|
const averageTravelTime = await repository.getAverageTravelTimeSeconds({
|
||||||
|
routeId: route.id,
|
||||||
|
fromStopId: stop1.id,
|
||||||
|
toStopId: stop2.id,
|
||||||
|
}, {
|
||||||
|
from: new Date(2025, 0, 1, 11, 0, 0),
|
||||||
|
to: new Date(2025, 0, 1, 14, 0, 0),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(averageTravelTime).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns undefined when querying outside the time range of data", async () => {
|
||||||
|
const { route, stop2, stop1 } = await setupRouteAndOrderedStops();
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
);
|
||||||
|
|
||||||
|
// Query for Jan 2 (no data should exist in this range)
|
||||||
|
const averageTravelTime = await repository.getAverageTravelTimeSeconds({
|
||||||
|
routeId: route.id,
|
||||||
|
fromStopId: stop1.id,
|
||||||
|
toStopId: stop2.id,
|
||||||
|
}, {
|
||||||
|
from: new Date(2025, 0, 2, 11, 0, 0),
|
||||||
|
to: new Date(2025, 0, 2, 13, 0, 0),
|
||||||
|
});
|
||||||
|
expect(averageTravelTime).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user