Refactor shuttle update method into clear sub-procedures

This commit is contained in:
2025-09-26 14:45:11 -07:00
parent 9a2b2f65b9
commit 74a55b3f57
2 changed files with 61 additions and 41 deletions

View File

@@ -132,11 +132,37 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
} }
public async updateShuttleDataForSystem() { public async updateShuttleDataForSystem() {
const systemId = this.passioSystemId; try {
const json = await this.fetchShuttleDataJson();
const shuttles = this.constructShuttlesFromJson(json);
if (shuttles !== null) {
await this.updateShuttleDataInRepository(shuttles);
} else {
console.warn(`Shuttle update failed for the following JSON: ${JSON.stringify(json)}`)
}
} catch(e: any) {
throw new ApiResponseError(e.message);
}
}
private async updateShuttleDataInRepository(shuttles: IShuttle[]) {
const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => { const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => {
return await this.repository.getShuttles(); return await this.repository.getShuttles();
}); });
await Promise.all(shuttles.map(async (shuttle) => {
await this.repository.addOrUpdateShuttle(shuttle);
shuttleIdsToPrune.delete(shuttle.id);
}));
await Promise.all(Array.from(shuttleIdsToPrune).map(async (shuttleId) => {
await this.repository.removeShuttleIfExists(shuttleId);
}));
}
private async fetchShuttleDataJson() {
const systemId = this.passioSystemId;
const params = { const params = {
getBuses: "2" getBuses: "2"
}; };
@@ -151,19 +177,20 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
const query = new URLSearchParams(params).toString(); const query = new URLSearchParams(params).toString();
try {
const response = await fetch(`${this.baseUrl}?${query}`, { const response = await fetch(`${this.baseUrl}?${query}`, {
method: "POST", method: "POST",
body: formData, body: formData,
}); });
const json = await response.json(); return await response.json();
}
private constructShuttlesFromJson(json: any): IShuttle[] | null {
if (json.buses && json.buses["-1"] === undefined) { if (json.buses && json.buses["-1"] === undefined) {
const jsonBuses = Object.values(json.buses).map((busesArr: any) => { const jsonBuses = Object.values(json.buses).map((busesArr: any) => {
return busesArr[0]; return busesArr[0];
}); });
await Promise.all(jsonBuses.map(async (jsonBus: any) => { return jsonBuses.map((jsonBus: any) => {
const constructedShuttle: IShuttle = { const constructedShuttle: IShuttle = {
name: jsonBus.bus, name: jsonBus.bus,
coordinates: { coordinates: {
@@ -176,19 +203,11 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
orientationInDegrees: parseFloat(jsonBus.calculatedCourse), orientationInDegrees: parseFloat(jsonBus.calculatedCourse),
updatedTime: new Date(), updatedTime: new Date(),
} }
return constructedShuttle;
await this.repository.addOrUpdateShuttle(constructedShuttle); });
shuttleIdsToPrune.delete(constructedShuttle.id);
}));
} }
await Promise.all(Array.from(shuttleIdsToPrune).map(async (shuttleId) => { return null;
await this.repository.removeShuttleIfExists(shuttleId);
}));
} catch(e: any) {
throw new ApiResponseError(e.message);
}
} }
public async updateEtaDataForExistingStopsForSystem() { public async updateEtaDataForExistingStopsForSystem() {
@@ -331,4 +350,5 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader
})) }))
} }
} }
} }

View File

@@ -34,10 +34,10 @@ describe("ApiBasedShuttleRepositoryLoader", () => {
describe("fetchAndUpdateAll", () => { describe("fetchAndUpdateAll", () => {
it("calls all the correct methods", async () => { it("calls all the correct methods", async () => {
const spies = { const spies = {
fetchAndUpdateRouteDataForSystem: jest.spyOn(loader, "fetchAndUpdateRouteDataForSystem"), updateRouteDataForSystem: jest.spyOn(loader, "updateRouteDataForSystem"),
fetchAndUpdateStopAndPolylineDataForRoutesInSystem: jest.spyOn(loader, "fetchAndUpdateStopAndPolylineDataForRoutesInSystem"), updateStopAndPolylineDataForRoutesInSystem: jest.spyOn(loader, "updateStopAndPolylineDataForRoutesInSystem"),
fetchAndUpdateShuttleDataForSystem: jest.spyOn(loader, "fetchAndUpdateShuttleDataForSystem"), updateShuttleDataForSystem: jest.spyOn(loader, "updateShuttleDataForSystem"),
fetchAndUpdateEtaDataForExistingStopsForSystem: jest.spyOn(loader, "fetchAndUpdateEtaDataForExistingStopsForSystem"), updateEtaDataForExistingStopsForSystem: jest.spyOn(loader, "updateEtaDataForExistingStopsForSystem"),
}; };
Object.values(spies).forEach((spy: any) => { Object.values(spies).forEach((spy: any) => {
@@ -153,7 +153,7 @@ describe("ApiBasedShuttleRepositoryLoader", () => {
describe("fetchAndUpdateEtaDataForExistingStopsForSystem", () => { describe("fetchAndUpdateEtaDataForExistingStopsForSystem", () => {
it("calls fetchAndUpdateEtaDataForStopId for every stop in repository", async () => { it("calls fetchAndUpdateEtaDataForStopId for every stop in repository", async () => {
const spy = jest.spyOn(loader, "fetchAndUpdateEtaDataForStopId"); const spy = jest.spyOn(loader, "updateEtaDataForStopId");
const stops = generateMockStops(); const stops = generateMockStops();
stops.forEach((stop) => { stops.forEach((stop) => {