From 7e0c1f3539271fc535df5176553f6e505f34e0b6 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 09:48:55 -0700 Subject: [PATCH 01/71] rename get system method on shuttle repository, update tests --- .../ApiBasedShuttleRepositoryLoader.ts | 10 +++---- src/repositories/ShuttleGetterRepository.ts | 2 +- .../UnoptimizedInMemoryShuttleRepository.ts | 2 +- src/resolvers/QueryResolvers.ts | 2 +- ...iBasedShuttleRepositoryLoaderTests.test.ts | 2 +- ...izedInMemoryShuttleRepositoryTests.test.ts | 28 +++++++++---------- 6 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index b8a6285..30f033e 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -39,7 +39,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader const query = new URLSearchParams(params).toString(); const systemIds = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getSystems(); + return await this.repository.getSystemIfExists(); }) try { @@ -76,7 +76,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateRouteDataForExistingSystemsInRepository() { - const systems = await this.repository.getSystems(); + const systems = await this.repository.getSystemIfExists(); await Promise.all(systems.map(async (system) => { await this.fetchAndUpdateRouteDataForSystemId(system.id); })); @@ -132,7 +132,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository() { - const systems = await this.repository.getSystems(); + const systems = await this.repository.getSystemIfExists(); await Promise.all(systems.map(async (system: ISystem) => { await this.fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(system.id); })); @@ -178,7 +178,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateShuttleDataForExistingSystemsInRepository() { - const systems = await this.repository.getSystems(); + const systems = await this.repository.getSystemIfExists(); await Promise.all(systems.map(async (system: ISystem) => { const systemId = system.id; await this.fetchAndUpdateShuttleDataForSystemId(systemId); @@ -244,7 +244,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository() { - const systems = await this.repository.getSystems() + const systems = await this.repository.getSystemIfExists() await Promise.all(systems.map(async (system: ISystem) => { const systemId = system.id; await this.fetchAndUpdateEtaDataForExistingStopsForSystemId(systemId); diff --git a/src/repositories/ShuttleGetterRepository.ts b/src/repositories/ShuttleGetterRepository.ts index 664328f..28a9de2 100644 --- a/src/repositories/ShuttleGetterRepository.ts +++ b/src/repositories/ShuttleGetterRepository.ts @@ -1,7 +1,7 @@ import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; export interface ShuttleGetterRepository { - getSystems(): Promise; + getSystemIfExists(): Promise; getSystemById(systemId: string): Promise; getStopsBySystemId(systemId: string): Promise; diff --git a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts index 59afac9..d807556 100644 --- a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts @@ -16,7 +16,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter private subscribers: ((eta: IEta) => void)[] = []; - public async getSystems() { + public async getSystemIfExists() { return this.systems; } diff --git a/src/resolvers/QueryResolvers.ts b/src/resolvers/QueryResolvers.ts index 06df1a9..1b316c8 100644 --- a/src/resolvers/QueryResolvers.ts +++ b/src/resolvers/QueryResolvers.ts @@ -4,7 +4,7 @@ import { Resolvers } from "../generated/graphql"; export const QueryResolvers: Resolvers = { Query: { systems: async (_parent, args, contextValue, _info) => { - return await contextValue.shuttleRepository.getSystems(); + return await contextValue.shuttleRepository.getSystemIfExists(); }, system: async (_parent, args, contextValue, _info) => { if (!args.id) return null; diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index cead5ec..5cf30f1 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -45,7 +45,7 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateSystemData(); // Assert - const systems = await loader.repository.getSystems(); + const systems = await loader.repository.getSystemIfExists(); if (loader.supportedSystemIds.length < numberOfSystemsInResponse) { expect(systems).toHaveLength(loader.supportedSystemIds.length); } else { diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index 003f71f..9801037 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -22,21 +22,19 @@ describe("UnoptimizedInMemoryRepository", () => { }); describe("getSystems", () => { - test("gets the systems stored in the repository", async () => { + test("gets the system stored in the repository", async () => { const mockSystems = generateMockSystems(); - for (const system of mockSystems) { - await repository.addOrUpdateSystem(system); - } + await repository.addOrUpdateSystem(mockSystems[0]); - const result = await repository.getSystems(); + const result = await repository.getSystemIfExists(); - expect(result).toEqual(mockSystems); + expect(result).toEqual(mockSystems[0]); }); - test("gets an empty list if there are no systems stored", async () => { - const result = await repository.getSystems(); + test("gets null if there is no data associated with the system", async () => { + const result = await repository.getSystemIfExists(); - expect(result).toEqual([]); + expect(result).toEqual(null); }); }); @@ -331,7 +329,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateSystem(newSystem); - const result = await repository.getSystems(); + const result = await repository.getSystemIfExists(); expect(result).toEqual([newSystem]); }); @@ -344,7 +342,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateSystem(existingSystem); await repository.addOrUpdateSystem(updatedSystem); - const result = await repository.getSystems(); + const result = await repository.getSystemIfExists(); expect(result).toEqual([updatedSystem]); }); }); @@ -484,7 +482,7 @@ describe("UnoptimizedInMemoryRepository", () => { const systemToRemove = mockSystems[0]; await repository.removeSystemIfExists(systemToRemove.id); - const remainingSystems = await repository.getSystems(); + const remainingSystems = await repository.getSystemIfExists(); expect(remainingSystems).toHaveLength(mockSystems.length - 1); }); @@ -496,7 +494,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.removeSystemIfExists("nonexistent-id"); - const remainingSystems = await repository.getSystems(); + const remainingSystems = await repository.getSystemIfExists(); expect(remainingSystems).toHaveLength(mockSystems.length); }); }); @@ -671,7 +669,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearSystemData(); - const result = await repository.getSystems(); + const result = await repository.getSystemIfExists(); expect(result).toEqual([]); }); @@ -682,7 +680,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearSystemData(); - const result = await repository.getSystems(); + const result = await repository.getSystemIfExists(); expect(result).toEqual([]); }); }); From 695fec1fcec3db6690431c065a5d4f77a957c332 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 09:51:13 -0700 Subject: [PATCH 02/71] rename update method and update return types --- src/loaders/ApiBasedShuttleRepositoryLoader.ts | 2 +- src/loaders/loadShuttleTestData.ts | 2 +- src/repositories/ShuttleGetterRepository.ts | 3 +-- .../ShuttleGetterSetterRepository.ts | 3 +-- .../UnoptimizedInMemoryShuttleRepository.ts | 6 +++--- ...piBasedShuttleRepositoryLoaderTests.test.ts | 10 +++++----- ...mizedInMemoryShuttleRepositoryTests.test.ts | 18 +++++++++--------- test/resolvers/QueryResolverTests.test.ts | 2 +- test/resolvers/SystemResolverTests.test.ts | 6 +++--- test/testHelpers/repositorySetupHelpers.ts | 2 +- 10 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index 30f033e..a7fd0f8 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -59,7 +59,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader name: system.fullname, }; - await this.repository.addOrUpdateSystem(constructedSystem); + await this.repository.updateSystem(constructedSystem); systemIds.delete(constructedSystem.id); })); } else { diff --git a/src/loaders/loadShuttleTestData.ts b/src/loaders/loadShuttleTestData.ts index 76cce74..9b1f8f3 100644 --- a/src/loaders/loadShuttleTestData.ts +++ b/src/loaders/loadShuttleTestData.ts @@ -4456,7 +4456,7 @@ const etas: IEta[] = [ export async function loadShuttleTestData(repository: ShuttleGetterSetterRepository) { await Promise.all(systems.map(async (system) => { - await repository.addOrUpdateSystem(system); + await repository.updateSystem(system); })); await Promise.all(routes.map(async (route) => { await repository.addOrUpdateRoute(route); diff --git a/src/repositories/ShuttleGetterRepository.ts b/src/repositories/ShuttleGetterRepository.ts index 28a9de2..063f6e2 100644 --- a/src/repositories/ShuttleGetterRepository.ts +++ b/src/repositories/ShuttleGetterRepository.ts @@ -1,8 +1,7 @@ import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; export interface ShuttleGetterRepository { - getSystemIfExists(): Promise; - getSystemById(systemId: string): Promise; + getSystemIfExists(): Promise; getStopsBySystemId(systemId: string): Promise; getStopById(stopId: string): Promise; diff --git a/src/repositories/ShuttleGetterSetterRepository.ts b/src/repositories/ShuttleGetterSetterRepository.ts index 0c0bf90..5153609 100644 --- a/src/repositories/ShuttleGetterSetterRepository.ts +++ b/src/repositories/ShuttleGetterSetterRepository.ts @@ -12,14 +12,13 @@ import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entitie */ export interface ShuttleGetterSetterRepository extends ShuttleGetterRepository { // Setter methods - addOrUpdateSystem(system: ISystem): Promise; + updateSystem(system: ISystem): Promise; addOrUpdateRoute(route: IRoute): Promise; addOrUpdateShuttle(shuttle: IShuttle): Promise; addOrUpdateStop(stop: IStop): Promise; addOrUpdateOrderedStop(orderedStop: IOrderedStop): Promise; addOrUpdateEta(eta: IEta): Promise; - removeSystemIfExists(systemId: string): Promise; removeRouteIfExists(routeId: string): Promise; removeShuttleIfExists(shuttleId: string): Promise; removeStopIfExists(stopId: string): Promise; diff --git a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts index d807556..90e088a 100644 --- a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts @@ -7,7 +7,7 @@ import { IEntityWithId, IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } f * switching to another data store later anyways) */ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetterRepository { - private systems: ISystem[] = []; + private system: ISystem | null = null; private stops: IStop[] = []; private routes: IRoute[] = []; private shuttles: IShuttle[] = []; @@ -17,7 +17,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter private subscribers: ((eta: IEta) => void)[] = []; public async getSystemIfExists() { - return this.systems; + return this.system; } public async getSystemById(systemId: string) { @@ -99,7 +99,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return entity; } - public async addOrUpdateSystem(system: ISystem): Promise { + public async updateSystem(system: ISystem): Promise { const index = this.systems.findIndex((s) => s.id === system.id); if (index !== -1) { this.systems[index] = system; // Update existing diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index 5cf30f1..93489dc 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -35,7 +35,7 @@ describe("ApiBasedRepositoryLoader", () => { // Arrange const systemsToPrune = generateMockSystems(); await Promise.all(systemsToPrune.map(async (system) => { - await loader.repository.addOrUpdateSystem(system); + await loader.repository.updateSystem(system); })); const numberOfSystemsInResponse = fetchSystemDataSuccessfulResponse.all.length; @@ -78,7 +78,7 @@ describe("ApiBasedRepositoryLoader", () => { const systems = generateMockSystems(); await Promise.all(systems.map(async (system) => { - await loader.repository.addOrUpdateSystem(system); + await loader.repository.updateSystem(system); })); await loader.fetchAndUpdateRouteDataForExistingSystemsInRepository(); @@ -128,7 +128,7 @@ describe("ApiBasedRepositoryLoader", () => { const systems = generateMockSystems(); await Promise.all(systems.map(async (system) => { - await loader.repository.addOrUpdateSystem(system); + await loader.repository.updateSystem(system); })); await loader.fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository(); @@ -183,7 +183,7 @@ describe("ApiBasedRepositoryLoader", () => { const systems = generateMockSystems(); await Promise.all(systems.map(async (system) => { - await loader.repository.addOrUpdateSystem(system); + await loader.repository.updateSystem(system); })) await loader.fetchAndUpdateShuttleDataForExistingSystemsInRepository(); @@ -226,7 +226,7 @@ describe("ApiBasedRepositoryLoader", () => { const systems = generateMockSystems(); await Promise.all(systems.map(async (system) => { - await loader.repository.addOrUpdateSystem(system); + await loader.repository.updateSystem(system); })); await loader.fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository(); diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index 9801037..a634373 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -24,7 +24,7 @@ describe("UnoptimizedInMemoryRepository", () => { describe("getSystems", () => { test("gets the system stored in the repository", async () => { const mockSystems = generateMockSystems(); - await repository.addOrUpdateSystem(mockSystems[0]); + await repository.updateSystem(mockSystems[0]); const result = await repository.getSystemIfExists(); @@ -42,7 +42,7 @@ describe("UnoptimizedInMemoryRepository", () => { test("gets a system by the ID if it exists", async () => { const mockSystems = generateMockSystems(); for (const system of mockSystems) { - await repository.addOrUpdateSystem(system); + await repository.updateSystem(system); } const result = await repository.getSystemById("2"); @@ -327,7 +327,7 @@ describe("UnoptimizedInMemoryRepository", () => { const mockSystems = generateMockSystems(); const newSystem = mockSystems[0]; - await repository.addOrUpdateSystem(newSystem); + await repository.updateSystem(newSystem); const result = await repository.getSystemIfExists(); expect(result).toEqual([newSystem]); @@ -339,8 +339,8 @@ describe("UnoptimizedInMemoryRepository", () => { const updatedSystem = structuredClone(existingSystem); updatedSystem.name = "Updated System"; - await repository.addOrUpdateSystem(existingSystem); - await repository.addOrUpdateSystem(updatedSystem); + await repository.updateSystem(existingSystem); + await repository.updateSystem(updatedSystem); const result = await repository.getSystemIfExists(); expect(result).toEqual([updatedSystem]); @@ -476,7 +476,7 @@ describe("UnoptimizedInMemoryRepository", () => { test("removes system given ID", async () => { const mockSystems = generateMockSystems(); await Promise.all(mockSystems.map(async (system) => { - await repository.addOrUpdateSystem(system); + await repository.updateSystem(system); })); const systemToRemove = mockSystems[0]; @@ -489,7 +489,7 @@ describe("UnoptimizedInMemoryRepository", () => { test("does nothing if system doesn't exist", async () => { const mockSystems = generateMockSystems(); await Promise.all(mockSystems.map(async (system) => { - await repository.addOrUpdateSystem(system); + await repository.updateSystem(system); })); await repository.removeSystemIfExists("nonexistent-id"); @@ -664,7 +664,7 @@ describe("UnoptimizedInMemoryRepository", () => { test("clears all systems from the repository", async () => { const mockSystems = generateMockSystems(); for (const system of mockSystems) { - await repository.addOrUpdateSystem(system); + await repository.updateSystem(system); } await repository.clearSystemData(); @@ -676,7 +676,7 @@ describe("UnoptimizedInMemoryRepository", () => { test("clears system data when the repository has data", async () => { const mockSystems = generateMockSystems(); const system = mockSystems[0]; - await repository.addOrUpdateSystem(system); + await repository.updateSystem(system); await repository.clearSystemData(); diff --git a/test/resolvers/QueryResolverTests.test.ts b/test/resolvers/QueryResolverTests.test.ts index 52d6605..5d90c57 100644 --- a/test/resolvers/QueryResolverTests.test.ts +++ b/test/resolvers/QueryResolverTests.test.ts @@ -15,7 +15,7 @@ describe("QueryResolvers", () => { async function addMockSystems() { const systems = generateMockSystems(); await Promise.all(systems.map(async (system) => { - await context.shuttleRepository.addOrUpdateSystem(system); + await context.shuttleRepository.updateSystem(system); })); return systems; } diff --git a/test/resolvers/SystemResolverTests.test.ts b/test/resolvers/SystemResolverTests.test.ts index 1eb817c..c9de4a1 100644 --- a/test/resolvers/SystemResolverTests.test.ts +++ b/test/resolvers/SystemResolverTests.test.ts @@ -133,7 +133,7 @@ describe("SystemResolvers", () => { ...mockSystem, id: "2", } - await context.shuttleRepository.addOrUpdateSystem(updatedSystem); + await context.shuttleRepository.updateSystem(updatedSystem); const mockStop = await addMockStopToRepository(context.shuttleRepository, updatedSystem.id); @@ -199,7 +199,7 @@ describe("SystemResolvers", () => { ...mockSystem, id: "2", } - await context.shuttleRepository.addOrUpdateSystem(updatedSystem); + await context.shuttleRepository.updateSystem(updatedSystem); const mockRoute = await addMockRouteToRepository(context.shuttleRepository, updatedSystem.id); @@ -265,7 +265,7 @@ describe("SystemResolvers", () => { ...mockSystem, id: "2", } - await context.shuttleRepository.addOrUpdateSystem(updatedSystem); + await context.shuttleRepository.updateSystem(updatedSystem); const mockShuttle = await addMockShuttleToRepository(context.shuttleRepository, updatedSystem.id); diff --git a/test/testHelpers/repositorySetupHelpers.ts b/test/testHelpers/repositorySetupHelpers.ts index 58caea3..357d652 100644 --- a/test/testHelpers/repositorySetupHelpers.ts +++ b/test/testHelpers/repositorySetupHelpers.ts @@ -11,7 +11,7 @@ export async function addMockSystemToRepository(repository: ShuttleGetterSetterR const mockSystems = generateMockSystems(); const mockSystem = mockSystems[0]; mockSystem.id = "1"; - await repository.addOrUpdateSystem(mockSystem); + await repository.updateSystem(mockSystem); return mockSystem; } From a144657fa800ee338e63918d3dbf158c714427b3 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 09:55:23 -0700 Subject: [PATCH 03/71] update remove implementation and tests --- .../UnoptimizedInMemoryShuttleRepository.ts | 23 +++++----- ...izedInMemoryShuttleRepositoryTests.test.ts | 43 ++++--------------- 2 files changed, 18 insertions(+), 48 deletions(-) diff --git a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts index 90e088a..9060662 100644 --- a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts @@ -20,10 +20,6 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return this.system; } - public async getSystemById(systemId: string) { - return this.findEntityById(systemId, this.systems); - } - public async getStopsBySystemId(systemId: string) { return this.stops.filter(stop => stop.systemId === systemId); } @@ -100,12 +96,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter } public async updateSystem(system: ISystem): Promise { - const index = this.systems.findIndex((s) => s.id === system.id); - if (index !== -1) { - this.systems[index] = system; // Update existing - } else { - this.systems.push(system); // Add new - } + this.system = system; } public async addOrUpdateRoute(route: IRoute): Promise { @@ -175,8 +166,14 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return await this.removeEntityByMatcherIfExists((value) => value.id === entityId, arrayToSearchIn); } - public async removeSystemIfExists(systemId: string): Promise { - return await this.removeEntityByIdIfExists(systemId, this.systems); + public async removeSystemIfExists(): Promise { + if (this.system !== null) { + const system = this.system; + this.system = null; + return system; + } + + return null; } public async removeRouteIfExists(routeId: string): Promise { @@ -206,7 +203,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter } public async clearSystemData() { - this.systems = []; + this.system = null; } public async clearShuttleData(): Promise { diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index a634373..d7c0544 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -21,7 +21,7 @@ describe("UnoptimizedInMemoryRepository", () => { repository = new UnoptimizedInMemoryShuttleRepository(); }); - describe("getSystems", () => { + describe("getSystem", () => { test("gets the system stored in the repository", async () => { const mockSystems = generateMockSystems(); await repository.updateSystem(mockSystems[0]); @@ -38,25 +38,6 @@ describe("UnoptimizedInMemoryRepository", () => { }); }); - describe("getSystemById", () => { - test("gets a system by the ID if it exists", async () => { - const mockSystems = generateMockSystems(); - for (const system of mockSystems) { - await repository.updateSystem(system); - } - - const result = await repository.getSystemById("2"); - - expect(result).toEqual(mockSystems[1]); // Ensure it retrieves the correct system - }); - - test("returns null if the system doesn't exist", async () => { - const result = await repository.getSystemById("nonexistent-id"); - - expect(result).toBeNull(); - }); - }); - describe("getStopsBySystemId", () => { test("gets stops by system ID", async () => { const mockStops = generateMockStops(); @@ -475,27 +456,19 @@ describe("UnoptimizedInMemoryRepository", () => { describe("removeSystemIfExists", () => { test("removes system given ID", async () => { const mockSystems = generateMockSystems(); - await Promise.all(mockSystems.map(async (system) => { - await repository.updateSystem(system); - })); + await repository.updateSystem(mockSystems[0]); - const systemToRemove = mockSystems[0]; - await repository.removeSystemIfExists(systemToRemove.id); + await repository.removeSystemIfExists(); - const remainingSystems = await repository.getSystemIfExists(); - expect(remainingSystems).toHaveLength(mockSystems.length - 1); + const expectedSystem = await repository.getSystemIfExists(); + expect(expectedSystem).toBeNull(); }); test("does nothing if system doesn't exist", async () => { - const mockSystems = generateMockSystems(); - await Promise.all(mockSystems.map(async (system) => { - await repository.updateSystem(system); - })); + await repository.removeSystemIfExists(); - await repository.removeSystemIfExists("nonexistent-id"); - - const remainingSystems = await repository.getSystemIfExists(); - expect(remainingSystems).toHaveLength(mockSystems.length); + const expectedSystem = await repository.getSystemIfExists(); + expect(expectedSystem).toBeNull(); }); }); From 5936c2b743b450caa5d2990242023f0a059fe747 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 09:57:03 -0700 Subject: [PATCH 04/71] update tests to match new repository behavior --- ...izedInMemoryShuttleRepositoryTests.test.ts | 33 +++---------------- 1 file changed, 4 insertions(+), 29 deletions(-) diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index d7c0544..030e423 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -303,28 +303,15 @@ describe("UnoptimizedInMemoryRepository", () => { }); }); - describe("addOrUpdateSystem", () => { - test("adds a new system if nonexistent", async () => { + describe("updateSystem", () => { + test("adds a new system", async () => { const mockSystems = generateMockSystems(); const newSystem = mockSystems[0]; await repository.updateSystem(newSystem); const result = await repository.getSystemIfExists(); - expect(result).toEqual([newSystem]); - }); - - test("updates an existing system if it exists", async () => { - const mockSystems = generateMockSystems(); - const existingSystem = mockSystems[0]; - const updatedSystem = structuredClone(existingSystem); - updatedSystem.name = "Updated System"; - - await repository.updateSystem(existingSystem); - await repository.updateSystem(updatedSystem); - - const result = await repository.getSystemIfExists(); - expect(result).toEqual([updatedSystem]); + expect(result).toEqual(newSystem); }); }); @@ -634,18 +621,6 @@ describe("UnoptimizedInMemoryRepository", () => { }); describe("clearSystemData", () => { - test("clears all systems from the repository", async () => { - const mockSystems = generateMockSystems(); - for (const system of mockSystems) { - await repository.updateSystem(system); - } - - await repository.clearSystemData(); - - const result = await repository.getSystemIfExists(); - expect(result).toEqual([]); - }); - test("clears system data when the repository has data", async () => { const mockSystems = generateMockSystems(); const system = mockSystems[0]; @@ -654,7 +629,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearSystemData(); const result = await repository.getSystemIfExists(); - expect(result).toEqual([]); + expect(result).toEqual(null); }); }); From d584d1f58b3c32d3310eb94deeb41fd16b00223a Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:14:24 -0700 Subject: [PATCH 05/71] update repository loader and tests to support only one system --- .../ApiBasedShuttleRepositoryLoader.ts | 55 ++++++++----------- src/loaders/ShuttleRepositoryLoader.ts | 8 +-- .../TimedApiBasedShuttleRepositoryLoader.ts | 8 +-- ...iBasedShuttleRepositoryLoaderTests.test.ts | 48 +++++++--------- 4 files changed, 52 insertions(+), 67 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index a7fd0f8..cf31c25 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -15,7 +15,7 @@ export class ApiResponseError extends Error { * which inherit from `IEntityWithId`. */ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader { - supportedSystemIds = ["263"]; + systemId = "263"; baseUrl = "https://passiogo.com/mapGetData.php"; constructor( @@ -38,9 +38,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader }; const query = new URLSearchParams(params).toString(); - const systemIds = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getSystemIfExists(); - }) + const system = await this.repository.getSystemIfExists(); try { const response = await fetch(`${this.baseUrl}?${query}`); @@ -52,34 +50,28 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader if (typeof json.all === "object") { // filter down to supported systems - const filteredSystems = json.all.filter((jsonSystem: any) => this.supportedSystemIds.includes(jsonSystem.id)); - await Promise.all(filteredSystems.map(async (system: any) => { + const filteredSystem = json.all.find((jsonSystem: any) => jsonSystem.id === this.systemId); + if (filteredSystem !== undefined) { const constructedSystem: ISystem = { - id: system.id, - name: system.fullname, + id: filteredSystem.id, + name: filteredSystem.fullname, }; await this.repository.updateSystem(constructedSystem); - systemIds.delete(constructedSystem.id); - })); + } } else { throw new Error("Received JSON object does not contain `all` field") } - - // Prune systems - await Promise.all(Array.from(systemIds).map(async (systemId) => { - await this.repository.removeSystemIfExists(systemId); - })); } catch(e: any) { throw new ApiResponseError(e.message); } } - public async fetchAndUpdateRouteDataForExistingSystemsInRepository() { - const systems = await this.repository.getSystemIfExists(); - await Promise.all(systems.map(async (system) => { + public async fetchAndUpdateRouteDataForExistingSystemInRepository() { + const system = await this.repository.getSystemIfExists(); + if (system !== null) { await this.fetchAndUpdateRouteDataForSystemId(system.id); - })); + } } public async fetchAndUpdateRouteDataForSystemId(systemId: string) { @@ -131,11 +123,11 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } } - public async fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository() { - const systems = await this.repository.getSystemIfExists(); - await Promise.all(systems.map(async (system: ISystem) => { + public async fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository() { + const system = await this.repository.getSystemIfExists(); + if (system !== null) { await this.fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(system.id); - })); + } } public async fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(systemId: string) { @@ -177,12 +169,13 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } } - public async fetchAndUpdateShuttleDataForExistingSystemsInRepository() { - const systems = await this.repository.getSystemIfExists(); - await Promise.all(systems.map(async (system: ISystem) => { + public async fetchAndUpdateShuttleDataForExistingSystemInRepository() { + const system = await this.repository.getSystemIfExists(); + + if (system !== null) { const systemId = system.id; await this.fetchAndUpdateShuttleDataForSystemId(systemId); - })); + } } public async fetchAndUpdateShuttleDataForSystemId(systemId: string) { @@ -243,12 +236,12 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } } - public async fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository() { - const systems = await this.repository.getSystemIfExists() - await Promise.all(systems.map(async (system: ISystem) => { + public async fetchAndUpdateEtaDataForExistingStopsForSystemInRepository() { + const system = await this.repository.getSystemIfExists() + if (system !== null) { const systemId = system.id; await this.fetchAndUpdateEtaDataForExistingStopsForSystemId(systemId); - })) + } } public async fetchAndUpdateEtaDataForExistingStopsForSystemId(systemId: string) { diff --git a/src/loaders/ShuttleRepositoryLoader.ts b/src/loaders/ShuttleRepositoryLoader.ts index 9ffa137..3d4a6b4 100644 --- a/src/loaders/ShuttleRepositoryLoader.ts +++ b/src/loaders/ShuttleRepositoryLoader.ts @@ -1,12 +1,12 @@ export interface ShuttleRepositoryLoader { fetchAndUpdateSystemData(): Promise; - fetchAndUpdateRouteDataForExistingSystemsInRepository(): Promise; + fetchAndUpdateRouteDataForExistingSystemInRepository(): Promise; fetchAndUpdateRouteDataForSystemId(systemId: string): Promise; - fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository(): Promise; + fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository(): Promise; fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(systemId: string): Promise; - fetchAndUpdateShuttleDataForExistingSystemsInRepository(): Promise; + fetchAndUpdateShuttleDataForExistingSystemInRepository(): Promise; fetchAndUpdateShuttleDataForSystemId(systemId: string): Promise; - fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository(): Promise; + fetchAndUpdateEtaDataForExistingStopsForSystemInRepository(): Promise; fetchAndUpdateEtaDataForExistingStopsForSystemId(systemId: string): Promise; fetchAndUpdateEtaDataForStopId(stopId: string): Promise; } diff --git a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts index 1d15273..e036373 100644 --- a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts @@ -47,14 +47,14 @@ export class TimedApiBasedShuttleRepositoryLoader extends ApiBasedShuttleReposit try { await this.fetchAndUpdateSystemData(); - await this.fetchAndUpdateRouteDataForExistingSystemsInRepository(); - await this.fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository(); - await this.fetchAndUpdateShuttleDataForExistingSystemsInRepository(); + await this.fetchAndUpdateRouteDataForExistingSystemInRepository(); + await this.fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository(); + await this.fetchAndUpdateShuttleDataForExistingSystemInRepository(); // Because ETA method doesn't support pruning yet, // add a call to the clear method here await this.repository.clearEtaData(); - await this.fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository(); + await this.fetchAndUpdateEtaDataForExistingStopsForSystemInRepository(); } catch (e) { console.error(e); } diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index 93489dc..ba40f6f 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -45,12 +45,8 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateSystemData(); // Assert - const systems = await loader.repository.getSystemIfExists(); - if (loader.supportedSystemIds.length < numberOfSystemsInResponse) { - expect(systems).toHaveLength(loader.supportedSystemIds.length); - } else { - expect(systems).toHaveLength(numberOfSystemsInResponse); - } + const system = await loader.repository.getSystemIfExists(); + expect(system).not.toBeNull(); }); it("throws the correct error if the API response contains no data", async () => { @@ -72,18 +68,17 @@ describe("ApiBasedRepositoryLoader", () => { describe("fetchAndUpdateRouteDataForExistingSystemsInRepository", () => { - test("calls fetchAndUpdateRouteDataForSystemId for all systems in repository", async () => { + test("calls fetchAndUpdateRouteDataForSystemId for system in repository", async () => { const spy = jest.spyOn(loader, "fetchAndUpdateRouteDataForSystemId"); const systems = generateMockSystems(); - await Promise.all(systems.map(async (system) => { - await loader.repository.updateSystem(system); - })); + await loader.repository.updateSystem(systems[0]); - await loader.fetchAndUpdateRouteDataForExistingSystemsInRepository(); + await loader.fetchAndUpdateRouteDataForExistingSystemInRepository(); - expect(spy.mock.calls.length).toBe(systems.length); + expect(spy.mock.calls.length).toBe(1); + expect(spy).toHaveBeenCalledWith(systems[0].id) }); }); @@ -122,18 +117,17 @@ describe("ApiBasedRepositoryLoader", () => { }); describe("fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository", () => { - it("calls fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId for every system", async () => { + it("calls fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId for system", async () => { const spy = jest.spyOn(loader, "fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId"); const systems = generateMockSystems(); - await Promise.all(systems.map(async (system) => { - await loader.repository.updateSystem(system); - })); + await loader.repository.updateSystem(systems[0]); - await loader.fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository(); + await loader.fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository(); - expect(spy.mock.calls.length).toBe(systems.length); + expect(spy.mock.calls.length).toBe(1); + expect(spy).toHaveBeenCalledWith(systems[0].id) }); }) @@ -182,13 +176,12 @@ describe("ApiBasedRepositoryLoader", () => { const spy = jest.spyOn(loader, "fetchAndUpdateShuttleDataForSystemId"); const systems = generateMockSystems(); - await Promise.all(systems.map(async (system) => { - await loader.repository.updateSystem(system); - })) + await loader.repository.updateSystem(systems[0]); - await loader.fetchAndUpdateShuttleDataForExistingSystemsInRepository(); + await loader.fetchAndUpdateShuttleDataForExistingSystemInRepository(); - expect(spy.mock.calls.length).toBe(systems.length); + expect(spy.mock.calls.length).toBe(1); + expect(spy).toHaveBeenCalledWith(systems[0].id) }); }); @@ -225,13 +218,12 @@ describe("ApiBasedRepositoryLoader", () => { const spy = jest.spyOn(loader, "fetchAndUpdateEtaDataForExistingStopsForSystemId"); const systems = generateMockSystems(); - await Promise.all(systems.map(async (system) => { - await loader.repository.updateSystem(system); - })); + await loader.repository.updateSystem(systems[0]); - await loader.fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository(); + await loader.fetchAndUpdateEtaDataForExistingStopsForSystemInRepository(); - expect(spy.mock.calls.length).toBe(systems.length); + expect(spy.mock.calls.length).toBe(1); + expect(spy).toHaveBeenCalledWith(systems[0].id) }); }); From 503bb0fec769bb77ed906fc7c63ebcbeee2f2895 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:16:58 -0700 Subject: [PATCH 06/71] fix timed api loader tests --- .../TimedApiBasedShuttleRepositoryLoaderTests.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts index 3c81887..f8548a3 100644 --- a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts @@ -19,10 +19,10 @@ describe("TimedApiBasedRepositoryLoader", () => { spies = { fetchAndUpdateSystemData: jest.spyOn(loader, 'fetchAndUpdateSystemData'), - fetchAndUpdateRouteDataForExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateRouteDataForExistingSystemsInRepository'), - fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository'), - fetchAndUpdateShuttleDataForExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateShuttleDataForExistingSystemsInRepository'), - fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository') + fetchAndUpdateRouteDataForExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateRouteDataForExistingSystemInRepository'), + fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository'), + fetchAndUpdateShuttleDataForExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateShuttleDataForExistingSystemInRepository'), + fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateEtaDataForExistingStopsForSystemInRepository') }; Object.values(spies).forEach((spy: any) => { From 4ea43ff21fea4d5f1256506738d89955a4c772ed Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:19:33 -0700 Subject: [PATCH 07/71] add system entity as class (holder for shuttle repo and loader) --- src/entities/System.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/entities/System.ts diff --git a/src/entities/System.ts b/src/entities/System.ts new file mode 100644 index 0000000..ecd5bc6 --- /dev/null +++ b/src/entities/System.ts @@ -0,0 +1,11 @@ +import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; +import { ShuttleRepositoryLoader } from "../loaders/ShuttleRepositoryLoader"; + +class System { + constructor( + public systemId: string, + public shuttleRepository: ShuttleGetterSetterRepository, + public shuttleDataLoader: ShuttleRepositoryLoader, + ) { + } +} From d607a3742ccff4650b615d69652716c9554a0e89 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:24:55 -0700 Subject: [PATCH 08/71] update constructor of loaders to take a system id --- src/loaders/ApiBasedShuttleRepositoryLoader.ts | 2 +- src/loaders/TimedApiBasedShuttleRepositoryLoader.ts | 3 ++- test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts | 2 +- test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index cf31c25..dc2ba1f 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -15,10 +15,10 @@ export class ApiResponseError extends Error { * which inherit from `IEntityWithId`. */ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader { - systemId = "263"; baseUrl = "https://passiogo.com/mapGetData.php"; constructor( + public systemId: string, public repository: ShuttleGetterSetterRepository, ) { } diff --git a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts index e036373..91847a5 100644 --- a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts @@ -22,9 +22,10 @@ export class TimedApiBasedShuttleRepositoryLoader extends ApiBasedShuttleReposit readonly timeout = 10000; constructor( + public systemId: string, repository: ShuttleGetterSetterRepository, ) { - super(repository); + super(systemId, repository); this.startFetchDataAndUpdate = this.startFetchDataAndUpdate.bind(this); } diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index ba40f6f..706387f 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -26,7 +26,7 @@ describe("ApiBasedRepositoryLoader", () => { let loader: ApiBasedShuttleRepositoryLoader; beforeEach(() => { - loader = new ApiBasedShuttleRepositoryLoader(new UnoptimizedInMemoryShuttleRepository()); + loader = new ApiBasedShuttleRepositoryLoader("1", new UnoptimizedInMemoryShuttleRepository()); resetGlobalFetchMockJson(); }); diff --git a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts index f8548a3..f6c27f5 100644 --- a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts @@ -15,7 +15,7 @@ describe("TimedApiBasedRepositoryLoader", () => { beforeEach(() => { resetGlobalFetchMockJson(); - loader = new TimedApiBasedShuttleRepositoryLoader(new UnoptimizedInMemoryShuttleRepository()); + loader = new TimedApiBasedShuttleRepositoryLoader("1", new UnoptimizedInMemoryShuttleRepository()); spies = { fetchAndUpdateSystemData: jest.spyOn(loader, 'fetchAndUpdateSystemData'), From 187800cf405408842c646dbe0e021046d534430b Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:28:19 -0700 Subject: [PATCH 09/71] add a build method and export statement --- src/entities/System.ts | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/entities/System.ts b/src/entities/System.ts index ecd5bc6..78857e1 100644 --- a/src/entities/System.ts +++ b/src/entities/System.ts @@ -1,11 +1,34 @@ -import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; import { ShuttleRepositoryLoader } from "../loaders/ShuttleRepositoryLoader"; +import { ETANotificationScheduler } from "../notifications/schedulers/ETANotificationScheduler"; +import { TimedApiBasedShuttleRepositoryLoader } from "../loaders/TimedApiBasedShuttleRepositoryLoader"; +import { UnoptimizedInMemoryShuttleRepository } from "../repositories/UnoptimizedInMemoryShuttleRepository"; +import { RedisNotificationRepository } from "../repositories/RedisNotificationRepository"; -class System { +export class System { constructor( public systemId: string, - public shuttleRepository: ShuttleGetterSetterRepository, public shuttleDataLoader: ShuttleRepositoryLoader, + public notificationScheduler: ETANotificationScheduler, ) { } + + /** + * Construct an instance of the class where all composited + * classes are correctly linked. + * @param systemId + */ + static build(systemId: string) { + const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); + const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(systemId, shuttleRepository); + + const notificationRepository = new RedisNotificationRepository(); + const notificationScheduler = new ETANotificationScheduler(shuttleRepository, notificationRepository); + + const system = new System( + systemId, + shuttleDataLoader, + notificationScheduler, + ); + return system; + } } From 5b695c7250fdd6f7558fc7a7a8e37b0434343b19 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:29:41 -0700 Subject: [PATCH 10/71] add notification repository argument --- src/entities/System.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/entities/System.ts b/src/entities/System.ts index 78857e1..d4737c5 100644 --- a/src/entities/System.ts +++ b/src/entities/System.ts @@ -3,6 +3,7 @@ import { ETANotificationScheduler } from "../notifications/schedulers/ETANotific import { TimedApiBasedShuttleRepositoryLoader } from "../loaders/TimedApiBasedShuttleRepositoryLoader"; import { UnoptimizedInMemoryShuttleRepository } from "../repositories/UnoptimizedInMemoryShuttleRepository"; import { RedisNotificationRepository } from "../repositories/RedisNotificationRepository"; +import { NotificationRepository } from "../repositories/NotificationRepository"; export class System { constructor( @@ -16,12 +17,15 @@ export class System { * Construct an instance of the class where all composited * classes are correctly linked. * @param systemId + * @param notificationRepository */ - static build(systemId: string) { + static build( + systemId: string, + notificationRepository: NotificationRepository = new RedisNotificationRepository() + ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(systemId, shuttleRepository); - const notificationRepository = new RedisNotificationRepository(); const notificationScheduler = new ETANotificationScheduler(shuttleRepository, notificationRepository); const system = new System( From 95410470f6b33d7b73563ac935cd0ce1cddc0f13 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:34:03 -0700 Subject: [PATCH 11/71] make shuttleRepository and notificationRepository accessible through system --- src/ServerContext.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/ServerContext.ts b/src/ServerContext.ts index 732f7d8..93cd9ca 100644 --- a/src/ServerContext.ts +++ b/src/ServerContext.ts @@ -1,8 +1,5 @@ -import { ETANotificationScheduler } from "./notifications/schedulers/ETANotificationScheduler"; -import { ShuttleGetterSetterRepository } from "./repositories/ShuttleGetterSetterRepository"; -import { NotificationRepository } from "./repositories/NotificationRepository"; +import { System } from "./entities/System"; export interface ServerContext { - shuttleRepository: ShuttleGetterSetterRepository; - notificationRepository: NotificationRepository; + systems: System[]; } From 2bc12aa794ba79437ce68900111b4c46fd1c4038 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:34:30 -0700 Subject: [PATCH 12/71] update the system class --- src/entities/System.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/entities/System.ts b/src/entities/System.ts index d4737c5..456fd7a 100644 --- a/src/entities/System.ts +++ b/src/entities/System.ts @@ -4,12 +4,15 @@ import { TimedApiBasedShuttleRepositoryLoader } from "../loaders/TimedApiBasedSh import { UnoptimizedInMemoryShuttleRepository } from "../repositories/UnoptimizedInMemoryShuttleRepository"; import { RedisNotificationRepository } from "../repositories/RedisNotificationRepository"; import { NotificationRepository } from "../repositories/NotificationRepository"; +import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; export class System { constructor( public systemId: string, public shuttleDataLoader: ShuttleRepositoryLoader, + public shuttleRepository: ShuttleGetterSetterRepository, public notificationScheduler: ETANotificationScheduler, + public notificationRepository: NotificationRepository, ) { } @@ -31,7 +34,9 @@ export class System { const system = new System( systemId, shuttleDataLoader, + shuttleRepository, notificationScheduler, + notificationRepository, ); return system; } From db097b00dcacff4c3702b8bc25acde3160c66e66 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:43:34 -0700 Subject: [PATCH 13/71] rename class to InterchangeSystem.ts and add builder arguments --- src/ServerContext.ts | 4 ++-- .../{System.ts => InterchangeSystem.ts} | 18 +++++++++++------- 2 files changed, 13 insertions(+), 9 deletions(-) rename src/entities/{System.ts => InterchangeSystem.ts} (84%) diff --git a/src/ServerContext.ts b/src/ServerContext.ts index 93cd9ca..bccfcf2 100644 --- a/src/ServerContext.ts +++ b/src/ServerContext.ts @@ -1,5 +1,5 @@ -import { System } from "./entities/System"; +import { InterchangeSystem } from "./entities/InterchangeSystem"; export interface ServerContext { - systems: System[]; + systems: InterchangeSystem[]; } diff --git a/src/entities/System.ts b/src/entities/InterchangeSystem.ts similarity index 84% rename from src/entities/System.ts rename to src/entities/InterchangeSystem.ts index 456fd7a..a2af349 100644 --- a/src/entities/System.ts +++ b/src/entities/InterchangeSystem.ts @@ -6,7 +6,12 @@ import { RedisNotificationRepository } from "../repositories/RedisNotificationRe import { NotificationRepository } from "../repositories/NotificationRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; -export class System { +export interface InterchangeSystemBuilderArguments { + name: string; + passioSystemId: string; +} + +export class InterchangeSystem { constructor( public systemId: string, public shuttleDataLoader: ShuttleRepositoryLoader, @@ -19,25 +24,24 @@ export class System { /** * Construct an instance of the class where all composited * classes are correctly linked. - * @param systemId + * @param args * @param notificationRepository */ static build( - systemId: string, + args: InterchangeSystemBuilderArguments, notificationRepository: NotificationRepository = new RedisNotificationRepository() ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); - const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(systemId, shuttleRepository); + const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); const notificationScheduler = new ETANotificationScheduler(shuttleRepository, notificationRepository); - const system = new System( - systemId, + return new InterchangeSystem( + args.name, shuttleDataLoader, shuttleRepository, notificationScheduler, notificationRepository, ); - return system; } } From 6d762ce62081e2166fc4b219998f2ce890b55890 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:49:47 -0700 Subject: [PATCH 14/71] remove all system related data from shuttle repository --- .../UnoptimizedInMemoryShuttleRepository.ts | 25 +------- ...izedInMemoryShuttleRepositoryTests.test.ts | 62 ------------------- 2 files changed, 1 insertion(+), 86 deletions(-) diff --git a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts index 9060662..6d613f2 100644 --- a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts @@ -1,5 +1,5 @@ import { ShuttleGetterSetterRepository } from "./ShuttleGetterSetterRepository"; -import { IEntityWithId, IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; +import { IEntityWithId, IEta, IOrderedStop, IRoute, IShuttle, IStop } from "../entities/entities"; /** * An unoptimized in memory repository. @@ -7,7 +7,6 @@ import { IEntityWithId, IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } f * switching to another data store later anyways) */ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetterRepository { - private system: ISystem | null = null; private stops: IStop[] = []; private routes: IRoute[] = []; private shuttles: IShuttle[] = []; @@ -16,10 +15,6 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter private subscribers: ((eta: IEta) => void)[] = []; - public async getSystemIfExists() { - return this.system; - } - public async getStopsBySystemId(systemId: string) { return this.stops.filter(stop => stop.systemId === systemId); } @@ -95,10 +90,6 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return entity; } - public async updateSystem(system: ISystem): Promise { - this.system = system; - } - public async addOrUpdateRoute(route: IRoute): Promise { const index = this.routes.findIndex((r) => r.id === route.id); if (index !== -1) { @@ -166,16 +157,6 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return await this.removeEntityByMatcherIfExists((value) => value.id === entityId, arrayToSearchIn); } - public async removeSystemIfExists(): Promise { - if (this.system !== null) { - const system = this.system; - this.system = null; - return system; - } - - return null; - } - public async removeRouteIfExists(routeId: string): Promise { return await this.removeEntityByIdIfExists(routeId, this.routes); } @@ -202,10 +183,6 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter }, this.etas); } - public async clearSystemData() { - this.system = null; - } - public async clearShuttleData(): Promise { this.shuttles = []; } diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index 030e423..4cb2419 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -6,7 +6,6 @@ import { generateMockRoutes, generateMockShuttles, generateMockStops, - generateMockSystems } from "../testHelpers/mockDataGenerators"; // For repositories created in the future, reuse core testing @@ -21,23 +20,6 @@ describe("UnoptimizedInMemoryRepository", () => { repository = new UnoptimizedInMemoryShuttleRepository(); }); - describe("getSystem", () => { - test("gets the system stored in the repository", async () => { - const mockSystems = generateMockSystems(); - await repository.updateSystem(mockSystems[0]); - - const result = await repository.getSystemIfExists(); - - expect(result).toEqual(mockSystems[0]); - }); - - test("gets null if there is no data associated with the system", async () => { - const result = await repository.getSystemIfExists(); - - expect(result).toEqual(null); - }); - }); - describe("getStopsBySystemId", () => { test("gets stops by system ID", async () => { const mockStops = generateMockStops(); @@ -303,18 +285,6 @@ describe("UnoptimizedInMemoryRepository", () => { }); }); - describe("updateSystem", () => { - test("adds a new system", async () => { - const mockSystems = generateMockSystems(); - const newSystem = mockSystems[0]; - - await repository.updateSystem(newSystem); - - const result = await repository.getSystemIfExists(); - expect(result).toEqual(newSystem); - }); - }); - describe("addOrUpdateRoute", () => { test("adds a new route if nonexistent", async () => { const mockRoutes = generateMockRoutes(); @@ -440,25 +410,6 @@ describe("UnoptimizedInMemoryRepository", () => { }); }); - describe("removeSystemIfExists", () => { - test("removes system given ID", async () => { - const mockSystems = generateMockSystems(); - await repository.updateSystem(mockSystems[0]); - - await repository.removeSystemIfExists(); - - const expectedSystem = await repository.getSystemIfExists(); - expect(expectedSystem).toBeNull(); - }); - - test("does nothing if system doesn't exist", async () => { - await repository.removeSystemIfExists(); - - const expectedSystem = await repository.getSystemIfExists(); - expect(expectedSystem).toBeNull(); - }); - }); - describe("removeRouteIfExists", () => { test("removes route given ID", async () => { const systemId = "1"; @@ -620,19 +571,6 @@ describe("UnoptimizedInMemoryRepository", () => { }); }); - describe("clearSystemData", () => { - test("clears system data when the repository has data", async () => { - const mockSystems = generateMockSystems(); - const system = mockSystems[0]; - await repository.updateSystem(system); - - await repository.clearSystemData(); - - const result = await repository.getSystemIfExists(); - expect(result).toEqual(null); - }); - }); - describe("clearShuttleData", () => { test("clears all shuttles from the repository", async () => { const mockShuttles = generateMockShuttles(); From 940d172e87669403e036e39ec6b54fa4f84cef36 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:50:51 -0700 Subject: [PATCH 15/71] rename ISystem to IPassioSystem --- src/entities/entities.ts | 2 +- src/loaders/ApiBasedShuttleRepositoryLoader.ts | 4 ++-- src/loaders/loadShuttleTestData.ts | 7 ++----- src/repositories/ShuttleGetterRepository.ts | 4 +--- src/repositories/ShuttleGetterSetterRepository.ts | 4 +--- .../ApiBasedShuttleRepositoryLoaderTests.test.ts | 12 ++++++------ test/resolvers/EtaResolverTests.test.ts | 4 ++-- test/resolvers/OrderedStopResolverTests.test.ts | 4 ++-- test/resolvers/QueryResolverTests.test.ts | 4 ++-- test/resolvers/RouteResolverTests.test.ts | 4 ++-- test/resolvers/ShuttleResolverTests.test.ts | 4 ++-- test/resolvers/StopResolverTests.test.ts | 4 ++-- test/resolvers/SystemResolverTests.test.ts | 4 ++-- test/testHelpers/mockDataGenerators.ts | 4 ++-- test/testHelpers/repositorySetupHelpers.ts | 4 ++-- 15 files changed, 31 insertions(+), 38 deletions(-) diff --git a/src/entities/entities.ts b/src/entities/entities.ts index 2766595..8d1f0ad 100644 --- a/src/entities/entities.ts +++ b/src/entities/entities.ts @@ -6,7 +6,7 @@ export interface IEntityWithId { id: string; } -export interface ISystem extends IEntityWithId, IEntityWithOptionalTimestamp { +export interface IPassioSystem extends IEntityWithId, IEntityWithOptionalTimestamp { name: string; } diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index dc2ba1f..1e9cf2a 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -1,5 +1,5 @@ import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; -import { IEntityWithId, IEta, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; +import { IEntityWithId, IEta, IRoute, IShuttle, IStop, IPassioSystem } from "../entities/entities"; import { ShuttleRepositoryLoader } from "./ShuttleRepositoryLoader"; export class ApiResponseError extends Error { @@ -52,7 +52,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader // filter down to supported systems const filteredSystem = json.all.find((jsonSystem: any) => jsonSystem.id === this.systemId); if (filteredSystem !== undefined) { - const constructedSystem: ISystem = { + const constructedSystem: IPassioSystem = { id: filteredSystem.id, name: filteredSystem.fullname, }; diff --git a/src/loaders/loadShuttleTestData.ts b/src/loaders/loadShuttleTestData.ts index 9b1f8f3..ef0c13c 100644 --- a/src/loaders/loadShuttleTestData.ts +++ b/src/loaders/loadShuttleTestData.ts @@ -1,8 +1,8 @@ // Mock data -import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; +import { IEta, IOrderedStop, IRoute, IShuttle, IStop, IPassioSystem } from "../entities/entities"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; -const systems: ISystem[] = [ +const systems: IPassioSystem[] = [ { id: "1", name: "Chapman University", @@ -4455,9 +4455,6 @@ const etas: IEta[] = [ ]; export async function loadShuttleTestData(repository: ShuttleGetterSetterRepository) { - await Promise.all(systems.map(async (system) => { - await repository.updateSystem(system); - })); await Promise.all(routes.map(async (route) => { await repository.addOrUpdateRoute(route); })); diff --git a/src/repositories/ShuttleGetterRepository.ts b/src/repositories/ShuttleGetterRepository.ts index 063f6e2..0006f5f 100644 --- a/src/repositories/ShuttleGetterRepository.ts +++ b/src/repositories/ShuttleGetterRepository.ts @@ -1,8 +1,6 @@ -import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; +import { IEta, IOrderedStop, IRoute, IShuttle, IStop } from "../entities/entities"; export interface ShuttleGetterRepository { - getSystemIfExists(): Promise; - getStopsBySystemId(systemId: string): Promise; getStopById(stopId: string): Promise; diff --git a/src/repositories/ShuttleGetterSetterRepository.ts b/src/repositories/ShuttleGetterSetterRepository.ts index 5153609..5e5a925 100644 --- a/src/repositories/ShuttleGetterSetterRepository.ts +++ b/src/repositories/ShuttleGetterSetterRepository.ts @@ -2,7 +2,7 @@ // to convert from data repo to GraphQL schema import { ShuttleGetterRepository } from "./ShuttleGetterRepository"; -import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; +import { IEta, IOrderedStop, IRoute, IShuttle, IStop } from "../entities/entities"; /** * ShuttleGetterRepository interface for data derived from Passio API. @@ -12,7 +12,6 @@ import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entitie */ export interface ShuttleGetterSetterRepository extends ShuttleGetterRepository { // Setter methods - updateSystem(system: ISystem): Promise; addOrUpdateRoute(route: IRoute): Promise; addOrUpdateShuttle(shuttle: IShuttle): Promise; addOrUpdateStop(stop: IStop): Promise; @@ -25,7 +24,6 @@ export interface ShuttleGetterSetterRepository extends ShuttleGetterRepository { removeOrderedStopIfExists(stopId: string, routeId: string): Promise; removeEtaIfExists(shuttleId: string, stopId: string): Promise; - clearSystemData(): Promise; clearRouteData(): Promise; clearShuttleData(): Promise; clearStopData(): Promise; diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index 706387f..f4f8e68 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -7,7 +7,7 @@ import { fetchRouteDataSuccessfulResponse } from "../jsonSnapshots/fetchRouteDat import { fetchStopAndPolylineDataSuccessfulResponse } from "../jsonSnapshots/fetchStopAndPolylineData/fetchStopAndPolylineDataSuccessfulResponse"; -import { generateMockRoutes, generateMockShuttles, generateMockStops, generateMockSystems } from "../testHelpers/mockDataGenerators"; +import { generateMockRoutes, generateMockShuttles, generateMockStops, generateMockPassioSystems } from "../testHelpers/mockDataGenerators"; import { fetchShuttleDataSuccessfulResponse } from "../jsonSnapshots/fetchShuttleData/fetchShuttleDataSuccessfulResponse"; @@ -33,7 +33,7 @@ describe("ApiBasedRepositoryLoader", () => { describe("fetchAndUpdateSystemData", () => { it("updates system data in repository if response received", async () => { // Arrange - const systemsToPrune = generateMockSystems(); + const systemsToPrune = generateMockPassioSystems(); await Promise.all(systemsToPrune.map(async (system) => { await loader.repository.updateSystem(system); })); @@ -71,7 +71,7 @@ describe("ApiBasedRepositoryLoader", () => { test("calls fetchAndUpdateRouteDataForSystemId for system in repository", async () => { const spy = jest.spyOn(loader, "fetchAndUpdateRouteDataForSystemId"); - const systems = generateMockSystems(); + const systems = generateMockPassioSystems(); await loader.repository.updateSystem(systems[0]); @@ -120,7 +120,7 @@ describe("ApiBasedRepositoryLoader", () => { it("calls fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId for system", async () => { const spy = jest.spyOn(loader, "fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId"); - const systems = generateMockSystems(); + const systems = generateMockPassioSystems(); await loader.repository.updateSystem(systems[0]); @@ -175,7 +175,7 @@ describe("ApiBasedRepositoryLoader", () => { it("calls fetchAndUpdateShuttleDataForSystemId for every system", async () => { const spy = jest.spyOn(loader, "fetchAndUpdateShuttleDataForSystemId"); - const systems = generateMockSystems(); + const systems = generateMockPassioSystems(); await loader.repository.updateSystem(systems[0]); await loader.fetchAndUpdateShuttleDataForExistingSystemInRepository(); @@ -217,7 +217,7 @@ describe("ApiBasedRepositoryLoader", () => { it("calls fetchAndUpdateEtaDataFoExistingStopsForSystemId for every system in repository", async () => { const spy = jest.spyOn(loader, "fetchAndUpdateEtaDataForExistingStopsForSystemId"); - const systems = generateMockSystems(); + const systems = generateMockPassioSystems(); await loader.repository.updateSystem(systems[0]); await loader.fetchAndUpdateEtaDataForExistingStopsForSystemInRepository(); diff --git a/test/resolvers/EtaResolverTests.test.ts b/test/resolvers/EtaResolverTests.test.ts index 92a5600..89fe12b 100644 --- a/test/resolvers/EtaResolverTests.test.ts +++ b/test/resolvers/EtaResolverTests.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; -import { IEta, IShuttle, IStop, ISystem } from "../../src/entities/entities"; +import { IEta, IShuttle, IStop, IPassioSystem } from "../../src/entities/entities"; import { addMockEtaToRepository, addMockShuttleToRepository, addMockStopToRepository, @@ -12,7 +12,7 @@ describe("EtaResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - let mockSystem: ISystem; + let mockSystem: IPassioSystem; let mockShuttle: IShuttle; let mockStop: IStop; let expectedEta: IEta; diff --git a/test/resolvers/OrderedStopResolverTests.test.ts b/test/resolvers/OrderedStopResolverTests.test.ts index 4813e2d..39ada5b 100644 --- a/test/resolvers/OrderedStopResolverTests.test.ts +++ b/test/resolvers/OrderedStopResolverTests.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; -import { IRoute, IStop, ISystem } from "../../src/entities/entities"; +import { IRoute, IStop, IPassioSystem } from "../../src/entities/entities"; import { generateMockOrderedStops, generateMockStops } from "../testHelpers/mockDataGenerators"; import { addMockRouteToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); @@ -9,7 +9,7 @@ describe("OrderedStopResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - let mockSystem: ISystem; + let mockSystem: IPassioSystem; let mockRoute: IRoute; let mockStops: IStop[]; diff --git a/test/resolvers/QueryResolverTests.test.ts b/test/resolvers/QueryResolverTests.test.ts index 5d90c57..67a4bcc 100644 --- a/test/resolvers/QueryResolverTests.test.ts +++ b/test/resolvers/QueryResolverTests.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "@jest/globals"; -import { generateMockSystems } from "../testHelpers/mockDataGenerators"; +import { generateMockPassioSystems } from "../testHelpers/mockDataGenerators"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import assert = require("node:assert"); import { addMockShuttleToRepository, addMockStopToRepository } from "../testHelpers/repositorySetupHelpers"; @@ -13,7 +13,7 @@ describe("QueryResolvers", () => { const context = setupTestServerContext(); async function addMockSystems() { - const systems = generateMockSystems(); + const systems = generateMockPassioSystems(); await Promise.all(systems.map(async (system) => { await context.shuttleRepository.updateSystem(system); })); diff --git a/test/resolvers/RouteResolverTests.test.ts b/test/resolvers/RouteResolverTests.test.ts index 909c1d8..5b20ba4 100644 --- a/test/resolvers/RouteResolverTests.test.ts +++ b/test/resolvers/RouteResolverTests.test.ts @@ -6,14 +6,14 @@ import { addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import { generateMockOrderedStops, generateMockShuttles } from "../testHelpers/mockDataGenerators"; -import { IRoute, IStop, ISystem } from "../../src/entities/entities"; +import { IRoute, IStop, IPassioSystem } from "../../src/entities/entities"; import assert = require("node:assert"); describe("RouteResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - let mockSystem: ISystem; + let mockSystem: IPassioSystem; let mockRoute: IRoute; let mockStop: IStop; diff --git a/test/resolvers/ShuttleResolverTests.test.ts b/test/resolvers/ShuttleResolverTests.test.ts index 800f34c..5f78bf5 100644 --- a/test/resolvers/ShuttleResolverTests.test.ts +++ b/test/resolvers/ShuttleResolverTests.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { generateMockEtas, generateMockRoutes } from "../testHelpers/mockDataGenerators"; -import { IShuttle, ISystem } from "../../src/entities/entities"; +import { IShuttle, IPassioSystem } from "../../src/entities/entities"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { addMockShuttleToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); @@ -10,7 +10,7 @@ describe("ShuttleResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - let mockSystem: ISystem; + let mockSystem: IPassioSystem; let mockShuttle: IShuttle; beforeEach(async () => { diff --git a/test/resolvers/StopResolverTests.test.ts b/test/resolvers/StopResolverTests.test.ts index d82ca78..b16076c 100644 --- a/test/resolvers/StopResolverTests.test.ts +++ b/test/resolvers/StopResolverTests.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { generateMockEtas, generateMockOrderedStops } from "../testHelpers/mockDataGenerators"; -import { IStop, ISystem } from "../../src/entities/entities"; +import { IStop, IPassioSystem } from "../../src/entities/entities"; import { addMockStopToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); @@ -10,7 +10,7 @@ describe("StopResolvers", () => { const context = setupTestServerContext(); let mockStop: IStop; - let mockSystem: ISystem; + let mockSystem: IPassioSystem; beforeEach(async () => { mockSystem = await addMockSystemToRepository(context.shuttleRepository); diff --git a/test/resolvers/SystemResolverTests.test.ts b/test/resolvers/SystemResolverTests.test.ts index c9de4a1..577f591 100644 --- a/test/resolvers/SystemResolverTests.test.ts +++ b/test/resolvers/SystemResolverTests.test.ts @@ -7,14 +7,14 @@ import { addMockStopToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; -import { ISystem } from "../../src/entities/entities"; +import { IPassioSystem } from "../../src/entities/entities"; import assert = require("node:assert"); describe("SystemResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - let mockSystem: ISystem; + let mockSystem: IPassioSystem; beforeEach(async () => { mockSystem = await addMockSystemToRepository(context.shuttleRepository); diff --git a/test/testHelpers/mockDataGenerators.ts b/test/testHelpers/mockDataGenerators.ts index 07d14bf..c89517b 100644 --- a/test/testHelpers/mockDataGenerators.ts +++ b/test/testHelpers/mockDataGenerators.ts @@ -1,9 +1,9 @@ -import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../../src/entities/entities"; +import { IEta, IOrderedStop, IRoute, IShuttle, IStop, IPassioSystem } from "../../src/entities/entities"; // Use a single set of generators in case any of the // interfaces change in the future -export function generateMockSystems(): ISystem[] { +export function generateMockPassioSystems(): IPassioSystem[] { return [ { id: "1", name: "System A" }, { id: "2", name: "System B" }, diff --git a/test/testHelpers/repositorySetupHelpers.ts b/test/testHelpers/repositorySetupHelpers.ts index 357d652..266ad0a 100644 --- a/test/testHelpers/repositorySetupHelpers.ts +++ b/test/testHelpers/repositorySetupHelpers.ts @@ -3,12 +3,12 @@ import { generateMockRoutes, generateMockShuttles, generateMockStops, - generateMockSystems + generateMockPassioSystems } from "./mockDataGenerators"; import { ShuttleGetterSetterRepository } from "../../src/repositories/ShuttleGetterSetterRepository"; export async function addMockSystemToRepository(repository: ShuttleGetterSetterRepository) { - const mockSystems = generateMockSystems(); + const mockSystems = generateMockPassioSystems(); const mockSystem = mockSystems[0]; mockSystem.id = "1"; await repository.updateSystem(mockSystem); From 2d4bc6bdd41f4b8544f1afa67ed0d450b4720258 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:55:03 -0700 Subject: [PATCH 16/71] name the name argument correctly --- src/entities/InterchangeSystem.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index a2af349..1c34506 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -13,7 +13,7 @@ export interface InterchangeSystemBuilderArguments { export class InterchangeSystem { constructor( - public systemId: string, + public name: string, public shuttleDataLoader: ShuttleRepositoryLoader, public shuttleRepository: ShuttleGetterSetterRepository, public notificationScheduler: ETANotificationScheduler, From 2d1e3c13d259d44a1607ce39e80d90820ac58d3e Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 10:58:58 -0700 Subject: [PATCH 17/71] add an id string argument for the system --- src/entities/InterchangeSystem.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index 1c34506..5a2dc9f 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -8,12 +8,22 @@ import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSett export interface InterchangeSystemBuilderArguments { name: string; + + /** + * ID to identify the system internally and in the API. + */ + id: string; + + /** + * ID for fetching shuttle data from the Passio GO! system. + */ passioSystemId: string; } export class InterchangeSystem { constructor( public name: string, + public id: string, public shuttleDataLoader: ShuttleRepositoryLoader, public shuttleRepository: ShuttleGetterSetterRepository, public notificationScheduler: ETANotificationScheduler, @@ -38,6 +48,7 @@ export class InterchangeSystem { return new InterchangeSystem( args.name, + args.id, shuttleDataLoader, shuttleRepository, notificationScheduler, From ed2b7dbe5e292050b7f1e1a6f22cb40a17f4338d Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:03:41 -0700 Subject: [PATCH 18/71] update query resolvers to work with updated context --- src/resolvers/QueryResolvers.ts | 34 ++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/resolvers/QueryResolvers.ts b/src/resolvers/QueryResolvers.ts index 1b316c8..34c31e3 100644 --- a/src/resolvers/QueryResolvers.ts +++ b/src/resolvers/QueryResolvers.ts @@ -4,25 +4,49 @@ import { Resolvers } from "../generated/graphql"; export const QueryResolvers: Resolvers = { Query: { systems: async (_parent, args, contextValue, _info) => { - return await contextValue.shuttleRepository.getSystemIfExists(); + return contextValue.systems.map((system) => { + return { + name: system.name, + id: system.id, + }; + }) }, system: async (_parent, args, contextValue, _info) => { if (!args.id) return null; - const system = await contextValue.shuttleRepository.getSystemById(args.id); - if (system === null) return null; + const system = contextValue.systems.find((system) => { + return system.id === args.id; + }); + if (system === undefined) return null; return { name: system.name, id: system.id, }; }, + // TODO: Update the GraphQL schema to require a system ID isNotificationScheduled: async (_parent, args, contextValue, _info) => { const notificationData = args.input; - return await contextValue.notificationRepository.isNotificationScheduled(notificationData); + + for (let system of contextValue.systems) { + const isScheduled = await system.notificationRepository.isNotificationScheduled(notificationData); + if (isScheduled) { + return true; + } + } + + return false; }, secondsThresholdForNotification: async (_parent, args, contextValue, _info) => { const notificationData = args.input; - return await contextValue.notificationRepository.getSecondsThresholdForNotificationIfExists(notificationData); + + for (let system of contextValue.systems) { + const isScheduled = await system.notificationRepository.isNotificationScheduled(notificationData); + if (isScheduled) { + return await system.notificationRepository.getSecondsThresholdForNotificationIfExists(args.input); + } + } + + return null; }, }, } From 9ff388f2d44b379b0496422ff9921c0d1a511e31 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:10:16 -0700 Subject: [PATCH 19/71] update system resolvers --- src/resolvers/SystemResolvers.ts | 40 +++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/resolvers/SystemResolvers.ts b/src/resolvers/SystemResolvers.ts index ae9903a..415d0b3 100644 --- a/src/resolvers/SystemResolvers.ts +++ b/src/resolvers/SystemResolvers.ts @@ -4,14 +4,29 @@ import { ServerContext } from "../ServerContext"; export const SystemResolvers: Resolvers = { System: { routes: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getRoutesBySystemId(parent.id); + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return []; + } + + return await system.shuttleRepository.getRoutesBySystemId(parent.id); }, stops: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getStopsBySystemId(parent.id); + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return []; + } + + return await system.shuttleRepository.getStopsBySystemId(parent.id); }, stop: async (parent, args, contextValue, info) => { if (!args.id) return null; - const stop = await contextValue.shuttleRepository.getStopById(args.id); + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return null; + } + + const stop = await system.shuttleRepository.getStopById(args.id); if (stop === null) return null; if (stop.systemId !== parent.id) return null; @@ -24,7 +39,11 @@ export const SystemResolvers: Resolvers = { }, route: async (parent, args, contextValue, info) => { if (!args.id) return null; - const route = await contextValue.shuttleRepository.getRouteById(args.id); + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return null; + } + const route = await system.shuttleRepository.getRouteById(args.id); if (route === null) return null; if (route.systemId !== parent.id) return null; @@ -38,7 +57,11 @@ export const SystemResolvers: Resolvers = { }, shuttle: async (parent, args, contextValue, info) => { if (!args.id) return null; - const shuttle = await contextValue.shuttleRepository.getShuttleById(args.id); + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return null; + } + const shuttle = await system.shuttleRepository.getShuttleById(args.id); if (shuttle === null) return null; if (shuttle.systemId !== parent.id) return null; @@ -46,7 +69,12 @@ export const SystemResolvers: Resolvers = { return shuttle; }, shuttles: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getShuttlesBySystemId(parent.id); + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return []; + } + + return await system.shuttleRepository.getShuttlesBySystemId(parent.id); } }, } From 95eb2c8f6512d94f4674ce608878942f8fc04e7b Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:15:24 -0700 Subject: [PATCH 20/71] condense shuttle repository methods --- src/loaders/ShuttleRepositoryLoader.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/loaders/ShuttleRepositoryLoader.ts b/src/loaders/ShuttleRepositoryLoader.ts index 3d4a6b4..588d06f 100644 --- a/src/loaders/ShuttleRepositoryLoader.ts +++ b/src/loaders/ShuttleRepositoryLoader.ts @@ -1,12 +1,7 @@ export interface ShuttleRepositoryLoader { - fetchAndUpdateSystemData(): Promise; - fetchAndUpdateRouteDataForExistingSystemInRepository(): Promise; - fetchAndUpdateRouteDataForSystemId(systemId: string): Promise; - fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository(): Promise; - fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(systemId: string): Promise; - fetchAndUpdateShuttleDataForExistingSystemInRepository(): Promise; - fetchAndUpdateShuttleDataForSystemId(systemId: string): Promise; - fetchAndUpdateEtaDataForExistingStopsForSystemInRepository(): Promise; - fetchAndUpdateEtaDataForExistingStopsForSystemId(systemId: string): Promise; + fetchAndUpdateRouteDataForSystem(): Promise; + fetchAndUpdateStopAndPolylineDataForRoutesInSystem(): Promise; + fetchAndUpdateShuttleDataForSystem(): Promise; + fetchAndUpdateEtaDataForExistingStopsForSystem(): Promise; fetchAndUpdateEtaDataForStopId(stopId: string): Promise; } From 8c2fb3a52a9a65c27cb0cb876929051c24216e37 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:21:07 -0700 Subject: [PATCH 21/71] use simplified implementation without system loading --- .../ApiBasedShuttleRepositoryLoader.ts | 80 ++---------- ...iBasedShuttleRepositoryLoaderTests.test.ts | 119 ++---------------- 2 files changed, 21 insertions(+), 178 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index 1e9cf2a..17c6fa0 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -1,5 +1,5 @@ import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; -import { IEntityWithId, IEta, IRoute, IShuttle, IStop, IPassioSystem } from "../entities/entities"; +import { IEntityWithId, IEta, IRoute, IShuttle, IStop } from "../entities/entities"; import { ShuttleRepositoryLoader } from "./ShuttleRepositoryLoader"; export class ApiResponseError extends Error { @@ -32,49 +32,8 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader return ids; } - public async fetchAndUpdateSystemData() { - const params = { - getSystems: "2", - }; - const query = new URLSearchParams(params).toString(); - - const system = await this.repository.getSystemIfExists(); - - try { - const response = await fetch(`${this.baseUrl}?${query}`); - const json = await response.json(); - - if (!response.ok) { - throw new Error(`HTTP error with status ${response.status}`) - } - - if (typeof json.all === "object") { - // filter down to supported systems - const filteredSystem = json.all.find((jsonSystem: any) => jsonSystem.id === this.systemId); - if (filteredSystem !== undefined) { - const constructedSystem: IPassioSystem = { - id: filteredSystem.id, - name: filteredSystem.fullname, - }; - - await this.repository.updateSystem(constructedSystem); - } - } else { - throw new Error("Received JSON object does not contain `all` field") - } - } catch(e: any) { - throw new ApiResponseError(e.message); - } - } - - public async fetchAndUpdateRouteDataForExistingSystemInRepository() { - const system = await this.repository.getSystemIfExists(); - if (system !== null) { - await this.fetchAndUpdateRouteDataForSystemId(system.id); - } - } - - public async fetchAndUpdateRouteDataForSystemId(systemId: string) { + public async fetchAndUpdateRouteDataForSystem() { + const systemId = this.systemId; const routeIdsToPrune = await this.constructExistingEntityIdSet(async () => { return await this.repository.getRoutesBySystemId(systemId); }); @@ -123,14 +82,9 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } } - public async fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository() { - const system = await this.repository.getSystemIfExists(); - if (system !== null) { - await this.fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(system.id); - } - } + public async fetchAndUpdateStopAndPolylineDataForRoutesInSystem() { + const systemId = this.systemId; - public async fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(systemId: string) { // Fetch from the API // Pass JSON output into two different methods to update repository const stopIdsToPrune = await this.constructExistingEntityIdSet(async () => { @@ -169,16 +123,8 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } } - public async fetchAndUpdateShuttleDataForExistingSystemInRepository() { - const system = await this.repository.getSystemIfExists(); - - if (system !== null) { - const systemId = system.id; - await this.fetchAndUpdateShuttleDataForSystemId(systemId); - } - } - - public async fetchAndUpdateShuttleDataForSystemId(systemId: string) { + public async fetchAndUpdateShuttleDataForSystem() { + const systemId = this.systemId; const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => { return await this.repository.getShuttlesBySystemId(systemId); }); @@ -236,16 +182,8 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } } - public async fetchAndUpdateEtaDataForExistingStopsForSystemInRepository() { - const system = await this.repository.getSystemIfExists() - if (system !== null) { - const systemId = system.id; - await this.fetchAndUpdateEtaDataForExistingStopsForSystemId(systemId); - } - } - - public async fetchAndUpdateEtaDataForExistingStopsForSystemId(systemId: string) { - const stops = await this.repository.getStopsBySystemId(systemId); + public async fetchAndUpdateEtaDataForExistingStopsForSystem() { + const stops = await this.repository.getStopsBySystemId(this.systemId); await Promise.all(stops.map(async (stop) => { let stopId = stop.id; await this.fetchAndUpdateEtaDataForStopId(stopId); diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index f4f8e68..7a81d2a 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -26,63 +26,11 @@ describe("ApiBasedRepositoryLoader", () => { let loader: ApiBasedShuttleRepositoryLoader; beforeEach(() => { - loader = new ApiBasedShuttleRepositoryLoader("1", new UnoptimizedInMemoryShuttleRepository()); + loader = new ApiBasedShuttleRepositoryLoader("263", new UnoptimizedInMemoryShuttleRepository()); resetGlobalFetchMockJson(); }); - describe("fetchAndUpdateSystemData", () => { - it("updates system data in repository if response received", async () => { - // Arrange - const systemsToPrune = generateMockPassioSystems(); - await Promise.all(systemsToPrune.map(async (system) => { - await loader.repository.updateSystem(system); - })); - - const numberOfSystemsInResponse = fetchSystemDataSuccessfulResponse.all.length; - updateGlobalFetchMockJson(fetchSystemDataSuccessfulResponse); - - // Act - await loader.fetchAndUpdateSystemData(); - - // Assert - const system = await loader.repository.getSystemIfExists(); - expect(system).not.toBeNull(); - }); - - it("throws the correct error if the API response contains no data", async () => { - updateGlobalFetchMockJson(fetchSystemDataFailedResponse); - - await assertAsyncCallbackThrowsApiResponseError(async () => { - await loader.fetchAndUpdateSystemData(); - }); - }); - - it("throws the correct error if HTTP status code is not 200", async () => { - updateGlobalFetchMockJson(fetchSystemDataFailedResponse, 400); - - await assertAsyncCallbackThrowsApiResponseError(async () => { - await loader.fetchAndUpdateSystemData(); - }); - }); - }); - - - describe("fetchAndUpdateRouteDataForExistingSystemsInRepository", () => { - test("calls fetchAndUpdateRouteDataForSystemId for system in repository", async () => { - const spy = jest.spyOn(loader, "fetchAndUpdateRouteDataForSystemId"); - - const systems = generateMockPassioSystems(); - - await loader.repository.updateSystem(systems[0]); - - await loader.fetchAndUpdateRouteDataForExistingSystemInRepository(); - - expect(spy.mock.calls.length).toBe(1); - expect(spy).toHaveBeenCalledWith(systems[0].id) - }); - }); - - describe("fetchAndUpdateRouteDataForSystemId", () => { + describe("fetchAndUpdateRouteDataForSystem", () => { const systemId = "263"; it("updates route data in repository if response received", async () => { // Arrange @@ -96,7 +44,7 @@ describe("ApiBasedRepositoryLoader", () => { updateGlobalFetchMockJson(fetchRouteDataSuccessfulResponse); // Act - await loader.fetchAndUpdateRouteDataForSystemId(systemId); + await loader.fetchAndUpdateRouteDataForSystem(); // Assert const routes = await loader.repository.getRoutesBySystemId(systemId); @@ -111,26 +59,11 @@ describe("ApiBasedRepositoryLoader", () => { updateGlobalFetchMockJsonToThrowSyntaxError(); await assertAsyncCallbackThrowsApiResponseError(async () => { - await loader.fetchAndUpdateRouteDataForSystemId(systemId); + await loader.fetchAndUpdateRouteDataForSystem(); }); }); }); - describe("fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository", () => { - it("calls fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId for system", async () => { - const spy = jest.spyOn(loader, "fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId"); - - const systems = generateMockPassioSystems(); - - await loader.repository.updateSystem(systems[0]); - - await loader.fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository(); - - expect(spy.mock.calls.length).toBe(1); - expect(spy).toHaveBeenCalledWith(systems[0].id) - }); - }) - describe("fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId", () => { const systemId = "263"; it("updates stop and polyline data if response received", async () => { @@ -146,7 +79,7 @@ describe("ApiBasedRepositoryLoader", () => { const stopsArray = Object.values(fetchStopAndPolylineDataSuccessfulResponse.stops); - await loader.fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(systemId); + await loader.fetchAndUpdateStopAndPolylineDataForRoutesInSystem(); const stops = await loader.repository.getStopsBySystemId(systemId); expect(stops.length).toEqual(stopsArray.length); @@ -166,26 +99,12 @@ describe("ApiBasedRepositoryLoader", () => { updateGlobalFetchMockJsonToThrowSyntaxError(); await assertAsyncCallbackThrowsApiResponseError(async () => { - await loader.fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId(systemId); + await loader.fetchAndUpdateStopAndPolylineDataForRoutesInSystem(); }); }) }); - describe("fetchAndUpdateShuttleDataForExistingSystemsInRepository", () => { - it("calls fetchAndUpdateShuttleDataForSystemId for every system", async () => { - const spy = jest.spyOn(loader, "fetchAndUpdateShuttleDataForSystemId"); - - const systems = generateMockPassioSystems(); - await loader.repository.updateSystem(systems[0]); - - await loader.fetchAndUpdateShuttleDataForExistingSystemInRepository(); - - expect(spy.mock.calls.length).toBe(1); - expect(spy).toHaveBeenCalledWith(systems[0].id) - }); - }); - - describe("fetchAndUpdateShuttleDataForSystemId", () => { + describe("fetchAndUpdateShuttleDataForSystem", () => { const systemId = "263"; it("updates shuttle data in repository if response received", async () => { const shuttlesToPrune = generateMockShuttles(); @@ -197,7 +116,7 @@ describe("ApiBasedRepositoryLoader", () => { updateGlobalFetchMockJson(fetchShuttleDataSuccessfulResponse); const busesInResponse = Object.values(fetchShuttleDataSuccessfulResponse.buses); - await loader.fetchAndUpdateShuttleDataForSystemId(systemId); + await loader.fetchAndUpdateShuttleDataForSystem(); const shuttles = await loader.repository.getShuttlesBySystemId(systemId); @@ -208,39 +127,25 @@ describe("ApiBasedRepositoryLoader", () => { updateGlobalFetchMockJsonToThrowSyntaxError(); await assertAsyncCallbackThrowsApiResponseError(async () => { - await loader.fetchAndUpdateShuttleDataForSystemId(systemId); + await loader.fetchAndUpdateShuttleDataForSystem(); }); }); }); - describe("fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository", () => { - it("calls fetchAndUpdateEtaDataFoExistingStopsForSystemId for every system in repository", async () => { - const spy = jest.spyOn(loader, "fetchAndUpdateEtaDataForExistingStopsForSystemId"); - - const systems = generateMockPassioSystems(); - await loader.repository.updateSystem(systems[0]); - - await loader.fetchAndUpdateEtaDataForExistingStopsForSystemInRepository(); - - expect(spy.mock.calls.length).toBe(1); - expect(spy).toHaveBeenCalledWith(systems[0].id) - }); - }); - - describe("fetchAndUpdateEtaDataForExistingStopsForSystemId", () => { + describe("fetchAndUpdateEtaDataForExistingStopsForSystem", () => { it("calls fetchAndUpdateEtaDataForStopId for every stop in repository", async () => { const spy = jest.spyOn(loader, "fetchAndUpdateEtaDataForStopId"); const stops = generateMockStops(); stops.forEach((stop) => { - stop.systemId = "1"; + stop.systemId = "263"; }); await Promise.all(stops.map(async (stop) => { await loader.repository.addOrUpdateStop(stop); })); - await loader.fetchAndUpdateEtaDataForExistingStopsForSystemId("1"); + await loader.fetchAndUpdateEtaDataForExistingStopsForSystem(); expect(spy.mock.calls.length).toEqual(stops.length); }); From 56466964c1f2542a4281428c4761c8d344349df3 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:23:27 -0700 Subject: [PATCH 22/71] update method calls in TimedApiBasedShuttleRepositoryLoader --- src/loaders/TimedApiBasedShuttleRepositoryLoader.ts | 9 ++++----- .../TimedApiBasedShuttleRepositoryLoaderTests.test.ts | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts index 91847a5..151c218 100644 --- a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts @@ -47,15 +47,14 @@ export class TimedApiBasedShuttleRepositoryLoader extends ApiBasedShuttleReposit if (!this.shouldBeRunning) return; try { - await this.fetchAndUpdateSystemData(); - await this.fetchAndUpdateRouteDataForExistingSystemInRepository(); - await this.fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository(); - await this.fetchAndUpdateShuttleDataForExistingSystemInRepository(); + await this.fetchAndUpdateRouteDataForSystem(); + await this.fetchAndUpdateStopAndPolylineDataForRoutesInSystem(); + await this.fetchAndUpdateShuttleDataForSystem(); // Because ETA method doesn't support pruning yet, // add a call to the clear method here await this.repository.clearEtaData(); - await this.fetchAndUpdateEtaDataForExistingStopsForSystemInRepository(); + await this.fetchAndUpdateEtaDataForExistingStopsForSystem(); } catch (e) { console.error(e); } diff --git a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts index f6c27f5..0ee8537 100644 --- a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts @@ -18,11 +18,10 @@ describe("TimedApiBasedRepositoryLoader", () => { loader = new TimedApiBasedShuttleRepositoryLoader("1", new UnoptimizedInMemoryShuttleRepository()); spies = { - fetchAndUpdateSystemData: jest.spyOn(loader, 'fetchAndUpdateSystemData'), - fetchAndUpdateRouteDataForExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateRouteDataForExistingSystemInRepository'), - fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateStopAndPolylineDataForRoutesInExistingSystemInRepository'), - fetchAndUpdateShuttleDataForExistingSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateShuttleDataForExistingSystemInRepository'), - fetchAndUpdateEtaDataForExistingStopsForSystemsInRepository: jest.spyOn(loader, 'fetchAndUpdateEtaDataForExistingStopsForSystemInRepository') + fetchAndUpdateRouteDataForSystem: jest.spyOn(loader, 'fetchAndUpdateRouteDataForSystem'), + fetchAndUpdateStopAndPolylineDataForRoutesInSystem: jest.spyOn(loader, 'fetchAndUpdateStopAndPolylineDataForRoutesInSystem'), + fetchAndUpdateShuttleDataForSystem: jest.spyOn(loader, 'fetchAndUpdateShuttleDataForSystem'), + fetchAndUpdateEtaDataForExistingStopsForSystem: jest.spyOn(loader, 'fetchAndUpdateEtaDataForExistingStopsForSystem') }; Object.values(spies).forEach((spy: any) => { From bc598f085810a2203a7eab443f17f017a0e53b58 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:26:58 -0700 Subject: [PATCH 23/71] update graphql definition to include system ID in routes, stops, and shuttles --- schema.graphqls | 3 +++ 1 file changed, 3 insertions(+) diff --git a/schema.graphqls b/schema.graphqls index 6db52e7..20106cc 100644 --- a/schema.graphqls +++ b/schema.graphqls @@ -13,6 +13,7 @@ type System { type Route { name: String! id: ID! + systemId: ID! orderedStop(forStopId: ID): OrderedStop shuttles: [Shuttle!] polylineCoordinates: [Coordinates!]! @@ -30,6 +31,7 @@ type OrderedStop { type Stop { id: ID! + systemId: ID! name: String! coordinates: Coordinates! etas: [ETA!] @@ -51,6 +53,7 @@ type ETA { type Shuttle { name: String! + systemId: ID! id: ID!, coordinates: Coordinates! route: Route From 472b3a0b0537671ad9a02818a63fa8dabcff75e7 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:28:13 -0700 Subject: [PATCH 24/71] add system ID as parent ID in system resolvers --- src/resolvers/SystemResolvers.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/resolvers/SystemResolvers.ts b/src/resolvers/SystemResolvers.ts index 415d0b3..dd3c856 100644 --- a/src/resolvers/SystemResolvers.ts +++ b/src/resolvers/SystemResolvers.ts @@ -3,7 +3,7 @@ import { ServerContext } from "../ServerContext"; export const SystemResolvers: Resolvers = { System: { - routes: async (parent, args, contextValue, info) => { + routes: async (parent, args, contextValue, _info) => { const system = contextValue.systems.find((system) => system.id === parent.id); if (!system) { return []; @@ -11,7 +11,7 @@ export const SystemResolvers: Resolvers = { return await system.shuttleRepository.getRoutesBySystemId(parent.id); }, - stops: async (parent, args, contextValue, info) => { + stops: async (parent, args, contextValue, _info) => { const system = contextValue.systems.find((system) => system.id === parent.id); if (!system) { return []; @@ -19,7 +19,7 @@ export const SystemResolvers: Resolvers = { return await system.shuttleRepository.getStopsBySystemId(parent.id); }, - stop: async (parent, args, contextValue, info) => { + stop: async (parent, args, contextValue, _info) => { if (!args.id) return null; const system = contextValue.systems.find((system) => system.id === parent.id); if (!system) { @@ -35,9 +35,10 @@ export const SystemResolvers: Resolvers = { id: stop.id, name: stop.name, coordinates: stop.coordinates as Coordinates, + systemId: parent.id, }; }, - route: async (parent, args, contextValue, info) => { + route: async (parent, args, contextValue, _info) => { if (!args.id) return null; const system = contextValue.systems.find((system) => system.id === parent.id); if (!system) { @@ -53,9 +54,10 @@ export const SystemResolvers: Resolvers = { id: route.id, name: route.name, polylineCoordinates: route.polylineCoordinates as Coordinates[], + systemId: parent.id, }; }, - shuttle: async (parent, args, contextValue, info) => { + shuttle: async (parent, args, contextValue, _info) => { if (!args.id) return null; const system = contextValue.systems.find((system) => system.id === parent.id); if (!system) { @@ -68,7 +70,7 @@ export const SystemResolvers: Resolvers = { return shuttle; }, - shuttles: async (parent, args, contextValue, info) => { + shuttles: async (parent, args, contextValue, _info) => { const system = contextValue.systems.find((system) => system.id === parent.id); if (!system) { return []; From ea4723df856386c6955cf2a899d68d9e12f7bf09 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:30:08 -0700 Subject: [PATCH 25/71] update stop resolvers to look for system --- src/resolvers/StopResolvers.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/resolvers/StopResolvers.ts b/src/resolvers/StopResolvers.ts index 860e3be..9a2b55a 100644 --- a/src/resolvers/StopResolvers.ts +++ b/src/resolvers/StopResolvers.ts @@ -3,11 +3,19 @@ import { ServerContext } from "../ServerContext"; export const StopResolvers: Resolvers = { Stop: { - orderedStops: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getOrderedStopsByStopId(parent.id); + orderedStops: async (parent, args, contextValue, _info) => { + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return []; + } + return await system.shuttleRepository.getOrderedStopsByStopId(parent.id); }, - etas: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getEtasForStopId(parent.id); + etas: async (parent, args, contextValue, _info) => { + const system = contextValue.systems.find((system) => system.id === parent.id); + if (!system) { + return []; + } + return await system.shuttleRepository.getEtasForStopId(parent.id); }, }, } From 8dd2f02783906b79b01787996e7eea0987658f83 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:34:37 -0700 Subject: [PATCH 26/71] add findSystemById method on server context --- src/ServerContext.ts | 1 + src/resolvers/StopResolvers.ts | 4 ++-- src/resolvers/SystemResolvers.ts | 16 ++++++++-------- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ServerContext.ts b/src/ServerContext.ts index bccfcf2..b55a8b1 100644 --- a/src/ServerContext.ts +++ b/src/ServerContext.ts @@ -2,4 +2,5 @@ import { InterchangeSystem } from "./entities/InterchangeSystem"; export interface ServerContext { systems: InterchangeSystem[]; + findSystemById: (id: string) => InterchangeSystem | null; } diff --git a/src/resolvers/StopResolvers.ts b/src/resolvers/StopResolvers.ts index 9a2b55a..89f6444 100644 --- a/src/resolvers/StopResolvers.ts +++ b/src/resolvers/StopResolvers.ts @@ -4,14 +4,14 @@ import { ServerContext } from "../ServerContext"; export const StopResolvers: Resolvers = { Stop: { orderedStops: async (parent, args, contextValue, _info) => { - const system = contextValue.systems.find((system) => system.id === parent.id); + const system = contextValue.findSystemById(parent.id); if (!system) { return []; } return await system.shuttleRepository.getOrderedStopsByStopId(parent.id); }, etas: async (parent, args, contextValue, _info) => { - const system = contextValue.systems.find((system) => system.id === parent.id); + const system = contextValue.findSystemById(parent.id); if (!system) { return []; } diff --git a/src/resolvers/SystemResolvers.ts b/src/resolvers/SystemResolvers.ts index dd3c856..8ea01ae 100644 --- a/src/resolvers/SystemResolvers.ts +++ b/src/resolvers/SystemResolvers.ts @@ -3,16 +3,16 @@ import { ServerContext } from "../ServerContext"; export const SystemResolvers: Resolvers = { System: { - routes: async (parent, args, contextValue, _info) => { - const system = contextValue.systems.find((system) => system.id === parent.id); + routes: async (parent, _args, contextValue, _info) => { + const system = contextValue.findSystemById(parent.id); if (!system) { return []; } return await system.shuttleRepository.getRoutesBySystemId(parent.id); }, - stops: async (parent, args, contextValue, _info) => { - const system = contextValue.systems.find((system) => system.id === parent.id); + stops: async (parent, _args, contextValue, _info) => { + const system = contextValue.findSystemById(parent.id); if (!system) { return []; } @@ -21,7 +21,7 @@ export const SystemResolvers: Resolvers = { }, stop: async (parent, args, contextValue, _info) => { if (!args.id) return null; - const system = contextValue.systems.find((system) => system.id === parent.id); + const system = contextValue.findSystemById(parent.id); if (!system) { return null; } @@ -40,7 +40,7 @@ export const SystemResolvers: Resolvers = { }, route: async (parent, args, contextValue, _info) => { if (!args.id) return null; - const system = contextValue.systems.find((system) => system.id === parent.id); + const system = contextValue.findSystemById(parent.id); if (!system) { return null; } @@ -59,7 +59,7 @@ export const SystemResolvers: Resolvers = { }, shuttle: async (parent, args, contextValue, _info) => { if (!args.id) return null; - const system = contextValue.systems.find((system) => system.id === parent.id); + const system = contextValue.findSystemById(parent.id); if (!system) { return null; } @@ -71,7 +71,7 @@ export const SystemResolvers: Resolvers = { return shuttle; }, shuttles: async (parent, args, contextValue, _info) => { - const system = contextValue.systems.find((system) => system.id === parent.id); + const system = contextValue.findSystemById(parent.id); if (!system) { return []; } From 8a600565dcb099a480749bbee1c9db2184e013ce Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:36:25 -0700 Subject: [PATCH 27/71] update shuttle resolvers --- src/resolvers/ShuttleResolvers.ts | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/resolvers/ShuttleResolvers.ts b/src/resolvers/ShuttleResolvers.ts index b264306..3034ca8 100644 --- a/src/resolvers/ShuttleResolvers.ts +++ b/src/resolvers/ShuttleResolvers.ts @@ -5,7 +5,11 @@ export const ShuttleResolvers: Resolvers = { Shuttle: { eta: async (parent, args, contextValue, info) => { if (!args.forStopId) return null; - const etaForStopId = await contextValue.shuttleRepository.getEtaForShuttleAndStopId(parent.id, args.forStopId); + + const system = contextValue.findSystemById(parent.systemId); + if (!system) return null; + + const etaForStopId = await system.shuttleRepository.getEtaForShuttleAndStopId(parent.id, args.forStopId); if (etaForStopId === null) return null; return { @@ -16,7 +20,10 @@ export const ShuttleResolvers: Resolvers = { }; }, etas: async (parent, args, contextValue, info) => { - const etasForShuttle = await contextValue.shuttleRepository.getEtasForShuttleId(parent.id); + const system = contextValue.findSystemById(parent.systemId); + if (!system) return null; + + const etasForShuttle = await system.shuttleRepository.getEtasForShuttleId(parent.id); if (!etasForShuttle) return null; const computedEtas = await Promise.all(etasForShuttle.map(async ({ @@ -38,7 +45,10 @@ export const ShuttleResolvers: Resolvers = { return []; }, route: async (parent, args, contextValue, info) => { - const route = await contextValue.shuttleRepository.getRouteById(parent.routeId); + const system = contextValue.findSystemById(parent.systemId); + if (!system) return null; + + const route = await system.shuttleRepository.getRouteById(parent.routeId); if (route === null) return null; return { @@ -46,6 +56,7 @@ export const ShuttleResolvers: Resolvers = { id: route.id, name: route.name, polylineCoordinates: route.polylineCoordinates, + systemId: parent.systemId, } } }, From 28c3e2f5f51e2e3397acf5c6dd65a125c914f860 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:37:53 -0700 Subject: [PATCH 28/71] fix incorrect id passed into find system method for stop resolvers --- src/resolvers/StopResolvers.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resolvers/StopResolvers.ts b/src/resolvers/StopResolvers.ts index 89f6444..0c3ea54 100644 --- a/src/resolvers/StopResolvers.ts +++ b/src/resolvers/StopResolvers.ts @@ -4,14 +4,14 @@ import { ServerContext } from "../ServerContext"; export const StopResolvers: Resolvers = { Stop: { orderedStops: async (parent, args, contextValue, _info) => { - const system = contextValue.findSystemById(parent.id); + const system = contextValue.findSystemById(parent.systemId); if (!system) { return []; } return await system.shuttleRepository.getOrderedStopsByStopId(parent.id); }, etas: async (parent, args, contextValue, _info) => { - const system = contextValue.findSystemById(parent.id); + const system = contextValue.findSystemById(parent.systemId); if (!system) { return []; } From 1629f7929905131d65aa6aad9574b4bf516cd0c8 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:38:46 -0700 Subject: [PATCH 29/71] update route resolvers --- src/resolvers/RouteResolvers.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/resolvers/RouteResolvers.ts b/src/resolvers/RouteResolvers.ts index a0adc01..2b5dfa8 100644 --- a/src/resolvers/RouteResolvers.ts +++ b/src/resolvers/RouteResolvers.ts @@ -4,7 +4,10 @@ import { ServerContext } from "../ServerContext"; export const RouteResolvers: Resolvers = { Route: { shuttles: async (parent, args, contextValue, info) => { - const shuttles = await contextValue.shuttleRepository.getShuttlesByRouteId(parent.id); + const system = contextValue.findSystemById(parent.systemId); + if (!system) return null; + + const shuttles = await system.shuttleRepository.getShuttlesByRouteId(parent.id); return shuttles.map(({ coordinates, @@ -17,15 +20,20 @@ export const RouteResolvers: Resolvers = { route: parent, routeId: parent.id, id, - orientationInDegrees + orientationInDegrees, + systemId: parent.systemId, })); }, orderedStop: async (parent, args, contextValue, info) => { if (!args.forStopId) return null; - const orderedStop = await contextValue.shuttleRepository.getOrderedStopByRouteAndStopId(parent.id, args.forStopId); + + const system = contextValue.findSystemById(parent.systemId); + if (!system) return null; + + const orderedStop = await system.shuttleRepository.getOrderedStopByRouteAndStopId(parent.id, args.forStopId); if (!orderedStop) return null; - const stop = await contextValue.shuttleRepository.getStopById(orderedStop.stopId); + const stop = await system.shuttleRepository.getStopById(orderedStop.stopId); if (!stop) return null; return { From 7136f9201d82a929025073935c380f0375ae360a Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 11:42:33 -0700 Subject: [PATCH 30/71] update ordered stop resolvers --- src/resolvers/OrderedStopResolvers.ts | 36 +++++++++++++++++++-------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/src/resolvers/OrderedStopResolvers.ts b/src/resolvers/OrderedStopResolvers.ts index fe047aa..6190814 100644 --- a/src/resolvers/OrderedStopResolvers.ts +++ b/src/resolvers/OrderedStopResolvers.ts @@ -3,17 +3,21 @@ import { ServerContext } from "../ServerContext"; export const OrderedStopResolvers: Resolvers = { OrderedStop: { - nextStop: async (parent, args, contextValue, info): Promise => { + nextStop: async (parent, args, contextValue, _info): Promise => { const routeId = parent.routeId; const stopId = parent.stopId; - const currentOrderedStop = await contextValue.shuttleRepository.getOrderedStopByRouteAndStopId(routeId, stopId); + if (!parent.stop) return null; + const system = contextValue.findSystemById(parent.stop.systemId); + if (!system) return null; + + const currentOrderedStop = await system.shuttleRepository.getOrderedStopByRouteAndStopId(routeId, stopId); if (!currentOrderedStop) return null; const nextOrderedStop = currentOrderedStop.nextStop; if (!nextOrderedStop) return null; - const nextOrderedStopObject = await contextValue.shuttleRepository.getStopById(nextOrderedStop.stopId); + const nextOrderedStopObject = await system.shuttleRepository.getStopById(nextOrderedStop.stopId); if (!nextOrderedStopObject) return null; return { @@ -22,17 +26,21 @@ export const OrderedStopResolvers: Resolvers = { stopId: nextOrderedStopObject.id, } }, - previousStop: async (parent, args, contextValue, info): Promise => { + previousStop: async (parent, args, contextValue, _info): Promise => { const routeId = parent.routeId; const stopId = parent.stopId; - const currentOrderedStop = await contextValue.shuttleRepository.getOrderedStopByRouteAndStopId(routeId, stopId); + if (!parent.stop) return null; + const system = contextValue.findSystemById(parent.stop.systemId); + if (!system) return null; + + const currentOrderedStop = await system.shuttleRepository.getOrderedStopByRouteAndStopId(routeId, stopId); if (!currentOrderedStop) return null; const previousOrderedStop = currentOrderedStop.previousStop; if (!previousOrderedStop) return null; - const previousOrderedStopObject = await contextValue.shuttleRepository.getStopById(previousOrderedStop.stopId); + const previousOrderedStopObject = await system.shuttleRepository.getStopById(previousOrderedStop.stopId); if (!previousOrderedStopObject) return null; return { @@ -41,11 +49,19 @@ export const OrderedStopResolvers: Resolvers = { stopId: previousOrderedStopObject.id, } }, - stop: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getStopById(parent.stopId); + stop: async (parent, args, contextValue, _info) => { + if (!parent.stop) return null; + const system = contextValue.findSystemById(parent.stop.systemId); + if (!system) return null; + + return await system.shuttleRepository.getStopById(parent.stopId); }, - route: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getRouteById(parent.routeId); + route: async (parent, args, contextValue, _info) => { + if (!parent.stop) return null; + const system = contextValue.findSystemById(parent.stop.systemId); + if (!system) return null; + + return await system.shuttleRepository.getRouteById(parent.routeId); }, }, From f113dc1ec2f0cecba46b80716329075de01b1920 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 12:44:23 -0700 Subject: [PATCH 31/71] update ETA resolvers --- src/resolvers/EtaResolvers.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/resolvers/EtaResolvers.ts b/src/resolvers/EtaResolvers.ts index b5e7c65..0dabe62 100644 --- a/src/resolvers/EtaResolvers.ts +++ b/src/resolvers/EtaResolvers.ts @@ -4,10 +4,18 @@ import { ServerContext } from "../ServerContext"; export const EtaResolvers: Resolvers = { ETA: { stop: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getStopById(parent.stopId); + if (!parent.shuttle) return null; + const system = contextValue.findSystemById(parent.shuttle.systemId); + if (!system) return null; + + return await system.shuttleRepository.getStopById(parent.stopId); }, shuttle: async (parent, args, contextValue, info) => { - return await contextValue.shuttleRepository.getShuttleById(parent.shuttleId); + if (!parent.stop) return null; + const system = contextValue.findSystemById(parent.stop.systemId); + if (!system) return null; + + return await system.shuttleRepository.getShuttleById(parent.shuttleId); }, }, } From af57063b15b182c69242fcedaf01a1938805c0eb Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 12:54:22 -0700 Subject: [PATCH 32/71] update mutation resolvers with temporary method to locate system --- src/resolvers/MutationResolvers.ts | 47 ++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/resolvers/MutationResolvers.ts b/src/resolvers/MutationResolvers.ts index 9b48a7d..8d266c8 100644 --- a/src/resolvers/MutationResolvers.ts +++ b/src/resolvers/MutationResolvers.ts @@ -1,21 +1,47 @@ -import { NotificationResponse, Resolvers } from "../generated/graphql"; +import { MutationScheduleNotificationArgs, NotificationResponse, Resolvers } from "../generated/graphql"; import { ServerContext } from "../ServerContext"; import { ETANotificationScheduler, } from "../notifications/schedulers/ETANotificationScheduler"; import { ScheduledNotification } from "../repositories/NotificationRepository"; +import { InterchangeSystem } from "../entities/InterchangeSystem"; + +async function temp_findMatchingSystemBasedOnShuttleId(context: ServerContext, args: Omit & { + input: NonNullable +}) { + let matchingSystem: InterchangeSystem | undefined; + await Promise.all(context.systems.map(async (system) => { + const shuttle = await system.shuttleRepository.getShuttleById(args.input.shuttleId); + // Theoretically, there should only be one + if (shuttle !== null) { + matchingSystem = system; + } + return shuttle; + })); + return matchingSystem; +} export const MutationResolvers: Resolvers = { + // TODO: Require system ID on these endpoints Mutation: { scheduleNotification: async (_parent, args, context, _info) => { - const shuttle = await context.shuttleRepository.getShuttleById(args.input.shuttleId); + let matchingSystem = await temp_findMatchingSystemBasedOnShuttleId(context, args); + + if (!matchingSystem) { + return { + message: "Shuttle ID doesn't exist", + success: false, + } + } + + const shuttle = await matchingSystem.shuttleRepository.getShuttleById(args.input.shuttleId); if (!shuttle) { return { message: "Shuttle ID doesn't exist", success: false, } } - const stop = await context.shuttleRepository.getStopById(args.input.stopId); + const stop = await matchingSystem.shuttleRepository.getStopById(args.input.stopId); if (!stop) { return { message: "Stop ID doesn't exist", @@ -30,7 +56,7 @@ export const MutationResolvers: Resolvers = { : ETANotificationScheduler.defaultSecondsThresholdForNotificationToFire, } - await context.notificationRepository.addOrUpdateNotification(notificationData); + await matchingSystem.notificationRepository.addOrUpdateNotification(notificationData); const response: NotificationResponse = { message: "Notification scheduled", @@ -40,9 +66,18 @@ export const MutationResolvers: Resolvers = { return response; }, cancelNotification: async (_parent, args, context, _info) => { - const isScheduled = await context.notificationRepository.isNotificationScheduled(args.input) + const matchingSystem = await temp_findMatchingSystemBasedOnShuttleId(context, args); + if (!matchingSystem) { + return { + success: false, + message: "Unable to find correct system", + data: args.input, + } + } + + const isScheduled = await matchingSystem.notificationRepository.isNotificationScheduled(args.input) if (isScheduled) { - await context.notificationRepository.deleteNotificationIfExists(args.input); + await matchingSystem.notificationRepository.deleteNotificationIfExists(args.input); return { success: true, message: "Notification cancelled", From f31e01082822269c2ee84bdb65cfc3235652d021 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 12:56:12 -0700 Subject: [PATCH 33/71] update method to set up test server context --- test/testHelpers/apolloTestServerHelpers.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/test/testHelpers/apolloTestServerHelpers.ts b/test/testHelpers/apolloTestServerHelpers.ts index a7512ec..b0d2b05 100644 --- a/test/testHelpers/apolloTestServerHelpers.ts +++ b/test/testHelpers/apolloTestServerHelpers.ts @@ -6,6 +6,7 @@ import { beforeEach } from "@jest/globals"; import { ServerContext } from "../../src/ServerContext"; import { ETANotificationScheduler } from "../../src/notifications/schedulers/ETANotificationScheduler"; import { InMemoryNotificationRepository } from "../../src/repositories/InMemoryNotificationRepository"; +import { InterchangeSystem } from "../../src/entities/InterchangeSystem"; function setUpTestServer() { @@ -25,9 +26,17 @@ function setUpTestServer() { export function setupTestServerContext() { const context: { [key: string] : any } = {}; + const systems = [ + InterchangeSystem.build( + { + id: "1", name: "Chapman University", passioSystemId: "263" + }, + new InMemoryNotificationRepository() + ), + ] + beforeEach(() => { - context.shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); - context.notificationRepository = new InMemoryNotificationRepository(); + context.systems = systems; }); return context as ServerContext; From d95d112bf24be7fef06912a14f61e45f513be566 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 14:38:02 -0700 Subject: [PATCH 34/71] define findSystemById method --- test/testHelpers/apolloTestServerHelpers.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/testHelpers/apolloTestServerHelpers.ts b/test/testHelpers/apolloTestServerHelpers.ts index b0d2b05..d537881 100644 --- a/test/testHelpers/apolloTestServerHelpers.ts +++ b/test/testHelpers/apolloTestServerHelpers.ts @@ -37,6 +37,7 @@ export function setupTestServerContext() { beforeEach(() => { context.systems = systems; + context.findSystemById = async (_: string) => systems[0]; }); return context as ServerContext; From c32dcb9610a13676149690ac823d700c313153dc Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Sun, 6 Apr 2025 14:40:08 -0700 Subject: [PATCH 35/71] remove async label from test server construction of context --- test/testHelpers/apolloTestServerHelpers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testHelpers/apolloTestServerHelpers.ts b/test/testHelpers/apolloTestServerHelpers.ts index d537881..00f422b 100644 --- a/test/testHelpers/apolloTestServerHelpers.ts +++ b/test/testHelpers/apolloTestServerHelpers.ts @@ -37,7 +37,7 @@ export function setupTestServerContext() { beforeEach(() => { context.systems = systems; - context.findSystemById = async (_: string) => systems[0]; + context.findSystemById = (_: string) => systems[0]; }); return context as ServerContext; From dbb56f207db4661f0a329e924f83b85ef05bd3be Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 11:58:07 -0700 Subject: [PATCH 36/71] add system ID field to ordered stop --- schema.graphqls | 1 + 1 file changed, 1 insertion(+) diff --git a/schema.graphqls b/schema.graphqls index 20106cc..b7634ef 100644 --- a/schema.graphqls +++ b/schema.graphqls @@ -27,6 +27,7 @@ type OrderedStop { routeId: ID! stop: Stop stopId: ID! + systemId: ID! } type Stop { From 9c414be8ceff3bd1db6af8f65c6332de6fd86eab Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:07:32 -0700 Subject: [PATCH 37/71] fix test references after removal of addMockSystemToRepository --- test/resolvers/EtaResolverTests.test.ts | 11 ++---- test/resolvers/MutationResolverTests.test.ts | 37 +++++++++---------- .../OrderedStopResolverTests.test.ts | 34 ++++++++--------- test/resolvers/QueryResolverTests.test.ts | 18 +++------ test/resolvers/RouteResolverTests.test.ts | 17 ++++----- test/resolvers/ShuttleResolverTests.test.ts | 10 ++--- test/resolvers/StopResolverTests.test.ts | 10 ++--- test/resolvers/SystemResolverTests.test.ts | 28 ++++++-------- test/testHelpers/repositorySetupHelpers.ts | 10 ----- 9 files changed, 73 insertions(+), 102 deletions(-) diff --git a/test/resolvers/EtaResolverTests.test.ts b/test/resolvers/EtaResolverTests.test.ts index 89fe12b..1238f22 100644 --- a/test/resolvers/EtaResolverTests.test.ts +++ b/test/resolvers/EtaResolverTests.test.ts @@ -4,7 +4,6 @@ import { IEta, IShuttle, IStop, IPassioSystem } from "../../src/entities/entitie import { addMockEtaToRepository, addMockShuttleToRepository, addMockStopToRepository, - addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); @@ -12,23 +11,21 @@ describe("EtaResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - let mockSystem: IPassioSystem; let mockShuttle: IShuttle; let mockStop: IStop; let expectedEta: IEta; beforeEach(async () => { - mockSystem = await addMockSystemToRepository(context.shuttleRepository); - mockShuttle = await addMockShuttleToRepository(context.shuttleRepository, mockSystem.id); - mockStop = await addMockStopToRepository(context.shuttleRepository, mockSystem.id); - expectedEta = await addMockEtaToRepository(context.shuttleRepository, mockStop.id, mockShuttle.id); + mockShuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, context.systems[0].id); + mockStop = await addMockStopToRepository(context.systems[0].shuttleRepository, context.systems[0].id); + expectedEta = await addMockEtaToRepository(context.systems[0].shuttleRepository, mockStop.id, mockShuttle.id); }); async function getResponseForEtaQuery(query: string) { const response = await holder.testServer.executeOperation({ query, variables: { - systemId: mockSystem.id, + systemId: context.systems[0].id, shuttleId: mockShuttle.id, }, }, { diff --git a/test/resolvers/MutationResolverTests.test.ts b/test/resolvers/MutationResolverTests.test.ts index 055195e..04dbf69 100644 --- a/test/resolvers/MutationResolverTests.test.ts +++ b/test/resolvers/MutationResolverTests.test.ts @@ -3,7 +3,6 @@ import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/ap import { addMockShuttleToRepository, addMockStopToRepository, - addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); import { NotificationInput } from "../../src/generated/graphql"; @@ -44,14 +43,14 @@ describe("MutationResolvers", () => { const notificationResponse = response.body.singleResult.data?.scheduleNotification as any; expect(notificationResponse.success).toBe(false); - expect(await context.notificationRepository.isNotificationScheduled(notificationInput)).toBe(false); + expect(await context.systems[0].notificationRepository.isNotificationScheduled(notificationInput)).toBe(false); } it("adds a notification to the notification service", async () => { - const system = await addMockSystemToRepository(context.shuttleRepository); - const shuttle = await addMockShuttleToRepository(context.shuttleRepository, system.id); - const stop = await addMockStopToRepository(context.shuttleRepository, system.id); + const system = context.systems[0]; + const shuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, system.id); + const stop = await addMockStopToRepository(context.systems[0].shuttleRepository, system.id); const notificationInput = { deviceId: "1", @@ -72,13 +71,13 @@ describe("MutationResolvers", () => { expect(notificationResponse?.success).toBe(true); expect(notificationResponse?.data).toEqual(expectedNotificationData); - expect(await context.notificationRepository.getSecondsThresholdForNotificationIfExists(expectedNotificationData)).toBe(240); + expect(await context.systems[0].notificationRepository.getSecondsThresholdForNotificationIfExists(expectedNotificationData)).toBe(240); }); it("adds a notification with the default seconds threshold if none is provided", async () => { - const system = await addMockSystemToRepository(context.shuttleRepository); - const shuttle = await addMockShuttleToRepository(context.shuttleRepository, system.id); - const stop = await addMockStopToRepository(context.shuttleRepository, system.id); + const system = context.systems[0]; + const shuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, system.id); + const stop = await addMockStopToRepository(context.systems[0].shuttleRepository, system.id); const notificationInput = { deviceId: "1", @@ -93,12 +92,12 @@ describe("MutationResolvers", () => { const notificationResponse = response.body.singleResult.data?.scheduleNotification as any; expect(notificationResponse?.success).toBe(true); - expect(await context.notificationRepository.getSecondsThresholdForNotificationIfExists(notificationInput)).toBe(180); + expect(await context.systems[0].notificationRepository.getSecondsThresholdForNotificationIfExists(notificationInput)).toBe(180); }); it("fails if the shuttle ID doesn't exist", async () => { - const system = await addMockSystemToRepository(context.shuttleRepository); - const stop = await addMockStopToRepository(context.shuttleRepository, system.id); + const system = context.systems[0]; + const stop = await addMockStopToRepository(context.systems[0].shuttleRepository, system.id); const notificationInput = { deviceId: "1", @@ -110,8 +109,8 @@ describe("MutationResolvers", () => { }); it("fails if the stop ID doesn't exist", async () => { - const system = await addMockSystemToRepository(context.shuttleRepository); - const shuttle = await addMockShuttleToRepository(context.shuttleRepository, system.id); + const system = context.systems[0]; + const shuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, system.id); const notificationInput = { deviceId: "1", @@ -140,9 +139,9 @@ describe("MutationResolvers", () => { ` it("removes the notification from the notification service", async () => { - const system = await addMockSystemToRepository(context.shuttleRepository); - const shuttle = await addMockShuttleToRepository(context.shuttleRepository, system.id); - const stop = await addMockStopToRepository(context.shuttleRepository, system.id); + const system = context.systems[0]; + const shuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, system.id); + const stop = await addMockStopToRepository(context.systems[0].shuttleRepository, system.id); const notificationInput: any = { deviceId: "1", @@ -150,7 +149,7 @@ describe("MutationResolvers", () => { stopId: stop.id, secondsThreshold: 180, } - await context.notificationRepository.addOrUpdateNotification(notificationInput); + await context.systems[0].notificationRepository.addOrUpdateNotification(notificationInput); const notificationLookup = { ...notificationInput @@ -166,7 +165,7 @@ describe("MutationResolvers", () => { expect(notificationResponse.success).toBe(true); expect(notificationResponse.data).toEqual(notificationLookup); - expect(await context.notificationRepository.isNotificationScheduled(notificationLookup)).toBe(false); + expect(await context.systems[0].notificationRepository.isNotificationScheduled(notificationLookup)).toBe(false); }); it("fails if the notification doesn't exist", async () => { diff --git a/test/resolvers/OrderedStopResolverTests.test.ts b/test/resolvers/OrderedStopResolverTests.test.ts index 39ada5b..855fbd4 100644 --- a/test/resolvers/OrderedStopResolverTests.test.ts +++ b/test/resolvers/OrderedStopResolverTests.test.ts @@ -2,25 +2,23 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { IRoute, IStop, IPassioSystem } from "../../src/entities/entities"; import { generateMockOrderedStops, generateMockStops } from "../testHelpers/mockDataGenerators"; -import { addMockRouteToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; +import { addMockRouteToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); describe("OrderedStopResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - let mockSystem: IPassioSystem; let mockRoute: IRoute; let mockStops: IStop[]; beforeEach(async () => { - mockSystem = await addMockSystemToRepository(context.shuttleRepository); - mockRoute = await addMockRouteToRepository(context.shuttleRepository, mockSystem.id); + mockRoute = await addMockRouteToRepository(context.systems[0].shuttleRepository, context.systems[0].id); mockStops = generateMockStops(); await Promise.all(mockStops.map(async (mockStop) => { - mockStop.systemId = mockSystem.id; - await context.shuttleRepository.addOrUpdateStop(mockStop); + mockStop.systemId = context.systems[0].id; + await context.systems[0].shuttleRepository.addOrUpdateStop(mockStop); })); }); @@ -38,8 +36,8 @@ describe("OrderedStopResolvers", () => { // Link the stops together orderedStops[0].nextStop = orderedStops[1]; orderedStops[1].previousStop = orderedStops[0]; - await context.shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); - await context.shuttleRepository.addOrUpdateOrderedStop(orderedStops[1]); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(orderedStops[1]); return orderedStops; } @@ -63,7 +61,7 @@ describe("OrderedStopResolvers", () => { return await holder.testServer.executeOperation({ query, variables: { - systemId: mockSystem.id, + systemId: context.systems[0].id, routeId: mockRoute.id, stopId, }, @@ -93,7 +91,7 @@ describe("OrderedStopResolvers", () => { it("returns null if there is no next stop in the repository", async () => { const orderedStops = await setUpOrderedStopsInRepository(); orderedStops[0].nextStop = undefined; - await context.shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); const response = await getResponseForNextStopQuery(orderedStops[0].stopId); @@ -104,7 +102,7 @@ describe("OrderedStopResolvers", () => { it("returns null if the next stop object no longer exists", async () => { const orderedStops = await setUpOrderedStopsInRepository(); - await context.shuttleRepository.removeStopIfExists(orderedStops[1].stopId); + await context.systems[0].shuttleRepository.removeStopIfExists(orderedStops[1].stopId); const response = await getResponseForNextStopQuery(orderedStops[0].stopId); @@ -134,7 +132,7 @@ describe("OrderedStopResolvers", () => { return await holder.testServer.executeOperation({ query, variables: { - systemId: mockSystem.id, + systemId: context.systems[0].id, routeId: mockRoute.id, stopId, }, @@ -163,7 +161,7 @@ describe("OrderedStopResolvers", () => { it("returns null if there is no previous stop in the repository", async () => { const orderedStops = await setUpOrderedStopsInRepository(); orderedStops[1].previousStop = undefined; - await context.shuttleRepository.addOrUpdateOrderedStop(orderedStops[1]); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(orderedStops[1]); const response = await getResponseForPreviousStopQuery(orderedStops[1].stopId); @@ -174,7 +172,7 @@ describe("OrderedStopResolvers", () => { it("returns null if the current stop no longer exists", async () => { const orderedStops = await setUpOrderedStopsInRepository(); - await context.shuttleRepository.removeStopIfExists(orderedStops[0].stopId); + await context.systems[0].shuttleRepository.removeStopIfExists(orderedStops[0].stopId); const response = await getResponseForPreviousStopQuery(orderedStops[1].stopId); @@ -208,7 +206,7 @@ describe("OrderedStopResolvers", () => { return await holder.testServer.executeOperation({ query, variables: { - systemId: mockSystem.id, + systemId: context.systems[0].id, stopId, } }, { @@ -223,7 +221,7 @@ describe("OrderedStopResolvers", () => { orderedStops[0].stopId = mockStops[0].id; // Add one stop only - await context.shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); const response = await getResponseForRouteQuery(orderedStops[1].stopId); @@ -257,7 +255,7 @@ describe("OrderedStopResolvers", () => { return await holder.testServer.executeOperation({ query, variables: { - systemId: mockSystem.id, + systemId: context.systems[0].id, routeId: mockRoute.id, stopId, } @@ -270,7 +268,7 @@ describe("OrderedStopResolvers", () => { it("returns the associated stop if it exists", async () => { const orderedStops = await setUpOrderedStopsInRepository(); orderedStops[0].stopId = mockStops[0].id; - await context.shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(orderedStops[0]); const response = await getResponseForStopQuery(orderedStops[0].stopId); diff --git a/test/resolvers/QueryResolverTests.test.ts b/test/resolvers/QueryResolverTests.test.ts index 67a4bcc..a6c9a40 100644 --- a/test/resolvers/QueryResolverTests.test.ts +++ b/test/resolvers/QueryResolverTests.test.ts @@ -12,17 +12,9 @@ describe("QueryResolvers", () => { const holder = setupTestServerHolder(); const context = setupTestServerContext(); - async function addMockSystems() { - const systems = generateMockPassioSystems(); - await Promise.all(systems.map(async (system) => { - await context.shuttleRepository.updateSystem(system); - })); - return systems; - } - describe("systems", () => { it("returns systems from the repository", async () => { - const systems = await addMockSystems(); + const systems = context.systems; const query = ` query GetSystems @@ -58,7 +50,7 @@ describe("QueryResolvers", () => { `; it("returns a system for an ID from the repository", async () => { - const systems = await addMockSystems(); + const systems = context.systems; const systemToGet = systems[1]; const response = await holder.testServer.executeOperation({ @@ -103,8 +95,8 @@ describe("QueryResolvers", () => { it("returns correct data if the notification is scheduled", async () => { // Arrange - const shuttle = await addMockShuttleToRepository(context.shuttleRepository, "1"); - const stop = await addMockStopToRepository(context.shuttleRepository, "1") + const shuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, "1"); + const stop = await addMockStopToRepository(context.systems[0].shuttleRepository, "1") const notification: ScheduledNotification = { shuttleId: shuttle.id, @@ -112,7 +104,7 @@ describe("QueryResolvers", () => { deviceId: "1", secondsThreshold: 240, }; - await context.notificationRepository.addOrUpdateNotification(notification); + await context.systems[0].notificationRepository.addOrUpdateNotification(notification); const notificationLookup: any = { ...notification, diff --git a/test/resolvers/RouteResolverTests.test.ts b/test/resolvers/RouteResolverTests.test.ts index 5b20ba4..71c7815 100644 --- a/test/resolvers/RouteResolverTests.test.ts +++ b/test/resolvers/RouteResolverTests.test.ts @@ -2,8 +2,7 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { addMockRouteToRepository, - addMockStopToRepository, - addMockSystemToRepository + addMockStopToRepository } from "../testHelpers/repositorySetupHelpers"; import { generateMockOrderedStops, generateMockShuttles } from "../testHelpers/mockDataGenerators"; import { IRoute, IStop, IPassioSystem } from "../../src/entities/entities"; @@ -18,11 +17,11 @@ describe("RouteResolvers", () => { let mockStop: IStop; beforeEach(async () => { - mockSystem = await addMockSystemToRepository(context.shuttleRepository); + mockSystem = context.systems[0]; const systemId = mockSystem.id; - mockRoute = await addMockRouteToRepository(context.shuttleRepository, systemId); - mockStop = await addMockStopToRepository(context.shuttleRepository, systemId); + mockRoute = await addMockRouteToRepository(context.systems[0].shuttleRepository, systemId); + mockStop = await addMockStopToRepository(context.systems[0].shuttleRepository, systemId); }); @@ -58,7 +57,7 @@ describe("RouteResolvers", () => { const expectedShuttle = expectedShuttles[0]; expectedShuttle.systemId = mockSystem.id; expectedShuttle.routeId = mockRoute.id; - await context.shuttleRepository.addOrUpdateShuttle(expectedShuttle); + await context.systems[0].shuttleRepository.addOrUpdateShuttle(expectedShuttle); const response = await getResponseForShuttlesQuery(); @@ -113,7 +112,7 @@ describe("RouteResolvers", () => { const expectedOrderedStop = orderedStops[0]; expectedOrderedStop.stopId = mockStop.id; expectedOrderedStop.routeId = mockRoute.id; - await context.shuttleRepository.addOrUpdateOrderedStop(expectedOrderedStop); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(expectedOrderedStop); const response = await getResponseForOrderedStopQuery(); @@ -130,9 +129,9 @@ describe("RouteResolvers", () => { const expectedOrderedStop = orderedStops[0]; expectedOrderedStop.stopId = mockStop.id; expectedOrderedStop.routeId = mockRoute.id; - await context.shuttleRepository.addOrUpdateOrderedStop(expectedOrderedStop); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(expectedOrderedStop); - await context.shuttleRepository.removeStopIfExists(mockStop.id); + await context.systems[0].shuttleRepository.removeStopIfExists(mockStop.id); const response = await getResponseForOrderedStopQuery(); diff --git a/test/resolvers/ShuttleResolverTests.test.ts b/test/resolvers/ShuttleResolverTests.test.ts index 5f78bf5..31ba7a5 100644 --- a/test/resolvers/ShuttleResolverTests.test.ts +++ b/test/resolvers/ShuttleResolverTests.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { generateMockEtas, generateMockRoutes } from "../testHelpers/mockDataGenerators"; import { IShuttle, IPassioSystem } from "../../src/entities/entities"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; -import { addMockShuttleToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; +import { addMockShuttleToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); @@ -14,8 +14,8 @@ describe("ShuttleResolvers", () => { let mockShuttle: IShuttle; beforeEach(async () => { - mockSystem = await addMockSystemToRepository(context.shuttleRepository); - mockShuttle = await addMockShuttleToRepository(context.shuttleRepository, + mockSystem = context.systems[0]; + mockShuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, mockSystem.id); }); @@ -24,7 +24,7 @@ describe("ShuttleResolvers", () => { const etas = generateMockEtas(); await Promise.all(etas.map(async (eta) => { eta.shuttleId = shuttleId; - await context.shuttleRepository.addOrUpdateEta(eta); + await context.systems[0].shuttleRepository.addOrUpdateEta(eta); })); return etas; } @@ -175,7 +175,7 @@ describe("ShuttleResolvers", () => { it("returns the route if it exists", async () => { const mockRoute = generateMockRoutes()[0]; - await context.shuttleRepository.addOrUpdateRoute(mockRoute); + await context.systems[0].shuttleRepository.addOrUpdateRoute(mockRoute); const response = await getResponseForQuery(); diff --git a/test/resolvers/StopResolverTests.test.ts b/test/resolvers/StopResolverTests.test.ts index b16076c..13425e4 100644 --- a/test/resolvers/StopResolverTests.test.ts +++ b/test/resolvers/StopResolverTests.test.ts @@ -2,7 +2,7 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; import { generateMockEtas, generateMockOrderedStops } from "../testHelpers/mockDataGenerators"; import { IStop, IPassioSystem } from "../../src/entities/entities"; -import { addMockStopToRepository, addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; +import { addMockStopToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); describe("StopResolvers", () => { @@ -13,8 +13,8 @@ describe("StopResolvers", () => { let mockSystem: IPassioSystem; beforeEach(async () => { - mockSystem = await addMockSystemToRepository(context.shuttleRepository); - mockStop = await addMockStopToRepository(context.shuttleRepository, mockSystem.id); + mockSystem = context.systems[0]; + mockStop = await addMockStopToRepository(context.systems[0].shuttleRepository, mockSystem.id); }) async function getResponseForQuery(query: string) { @@ -49,7 +49,7 @@ describe("StopResolvers", () => { mockOrderedStops = mockOrderedStops.filter((orderedStop) => orderedStop.stopId === mockOrderedStops[0].stopId); await Promise.all(mockOrderedStops.map(async orderedStop => { orderedStop.stopId = mockStop.id; - await context.shuttleRepository.addOrUpdateOrderedStop(orderedStop); + await context.systems[0].shuttleRepository.addOrUpdateOrderedStop(orderedStop); })); const response = await getResponseForQuery(query); @@ -86,7 +86,7 @@ describe("StopResolvers", () => { mockEtas = mockEtas.filter((eta) => eta.stopId === mockEtas[0].stopId); await Promise.all(mockEtas.map(async eta => { eta.stopId = mockStop.id; - await context.shuttleRepository.addOrUpdateEta(eta); + await context.systems[0].shuttleRepository.addOrUpdateEta(eta); })); const response = await getResponseForQuery(query); diff --git a/test/resolvers/SystemResolverTests.test.ts b/test/resolvers/SystemResolverTests.test.ts index 577f591..af37384 100644 --- a/test/resolvers/SystemResolverTests.test.ts +++ b/test/resolvers/SystemResolverTests.test.ts @@ -5,7 +5,6 @@ import { addMockRouteToRepository, addMockShuttleToRepository, addMockStopToRepository, - addMockSystemToRepository } from "../testHelpers/repositorySetupHelpers"; import { IPassioSystem } from "../../src/entities/entities"; import assert = require("node:assert"); @@ -17,7 +16,7 @@ describe("SystemResolvers", () => { let mockSystem: IPassioSystem; beforeEach(async () => { - mockSystem = await addMockSystemToRepository(context.shuttleRepository); + mockSystem = context.systems[0]; }); // TODO: Consolidate these into one single method taking an object @@ -29,7 +28,7 @@ describe("SystemResolvers", () => { }, }, { contextValue: { - shuttleRepository: context.shuttleRepository + shuttleRepository: context.systems[0].shuttleRepository, }, }); } @@ -50,7 +49,7 @@ describe("SystemResolvers", () => { const expectedRoutes = generateMockRoutes(); await Promise.all(expectedRoutes.map(async (route) => { route.systemId = mockSystem.id; - await context.shuttleRepository.addOrUpdateRoute(route); + await context.systems[0].shuttleRepository.addOrUpdateRoute(route); })); const response = await getResponseFromQueryNeedingSystemId(query); @@ -78,7 +77,7 @@ describe("SystemResolvers", () => { const expectedStops = generateMockStops(); await Promise.all(expectedStops.map(async (stop) => { stop.systemId = mockSystem.id; - await context.shuttleRepository.addOrUpdateStop(stop); + await context.systems[0].shuttleRepository.addOrUpdateStop(stop); })); const response = await getResponseFromQueryNeedingSystemId(query); @@ -111,13 +110,13 @@ describe("SystemResolvers", () => { }, }, { contextValue: { - shuttleRepository: context.shuttleRepository, + shuttleRepository: context.systems[0].shuttleRepository, } }); } it("gets the stop with the correct id", async () => { - const mockStop = await addMockStopToRepository(context.shuttleRepository, mockSystem.id); + const mockStop = await addMockStopToRepository(context.systems[0].shuttleRepository, mockSystem.id); const response = await getResponseForStopQuery(mockStop.id); @@ -133,9 +132,8 @@ describe("SystemResolvers", () => { ...mockSystem, id: "2", } - await context.shuttleRepository.updateSystem(updatedSystem); - const mockStop = await addMockStopToRepository(context.shuttleRepository, updatedSystem.id); + const mockStop = await addMockStopToRepository(context.systems[0].shuttleRepository, updatedSystem.id); const response = await getResponseForStopQuery(mockStop.id); @@ -182,7 +180,7 @@ describe("SystemResolvers", () => { } it("gets the route with the correct id", async () => { - const mockRoute = await addMockRouteToRepository(context.shuttleRepository, mockSystem.id); + const mockRoute = await addMockRouteToRepository(context.systems[0].shuttleRepository, mockSystem.id); const response = await getResponseForRouteQuery(mockRoute.id); @@ -199,9 +197,8 @@ describe("SystemResolvers", () => { ...mockSystem, id: "2", } - await context.shuttleRepository.updateSystem(updatedSystem); - const mockRoute = await addMockRouteToRepository(context.shuttleRepository, updatedSystem.id); + const mockRoute = await addMockRouteToRepository(context.systems[0].shuttleRepository, updatedSystem.id); const response = await getResponseForRouteQuery(mockRoute.id); @@ -249,7 +246,7 @@ describe("SystemResolvers", () => { } it("gets the shuttle with the correct id", async () => { - const mockShuttle = await addMockShuttleToRepository(context.shuttleRepository, mockSystem.id); + const mockShuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, mockSystem.id); const response = await getResponseForShuttleQuery(mockShuttle.id); @@ -265,9 +262,8 @@ describe("SystemResolvers", () => { ...mockSystem, id: "2", } - await context.shuttleRepository.updateSystem(updatedSystem); - const mockShuttle = await addMockShuttleToRepository(context.shuttleRepository, updatedSystem.id); + const mockShuttle = await addMockShuttleToRepository(context.systems[0].shuttleRepository, updatedSystem.id); const response = await getResponseForShuttleQuery(mockShuttle.id); @@ -305,7 +301,7 @@ describe("SystemResolvers", () => { const expectedShuttles = generateMockShuttles(); await Promise.all(expectedShuttles.map(async (shuttle) => { shuttle.systemId = mockSystem.id; - await context.shuttleRepository.addOrUpdateShuttle(shuttle); + await context.systems[0].shuttleRepository.addOrUpdateShuttle(shuttle); })); const response = await getResponseFromQueryNeedingSystemId(query); diff --git a/test/testHelpers/repositorySetupHelpers.ts b/test/testHelpers/repositorySetupHelpers.ts index 266ad0a..85e5e1e 100644 --- a/test/testHelpers/repositorySetupHelpers.ts +++ b/test/testHelpers/repositorySetupHelpers.ts @@ -3,19 +3,9 @@ import { generateMockRoutes, generateMockShuttles, generateMockStops, - generateMockPassioSystems } from "./mockDataGenerators"; import { ShuttleGetterSetterRepository } from "../../src/repositories/ShuttleGetterSetterRepository"; -export async function addMockSystemToRepository(repository: ShuttleGetterSetterRepository) { - const mockSystems = generateMockPassioSystems(); - const mockSystem = mockSystems[0]; - mockSystem.id = "1"; - await repository.updateSystem(mockSystem); - - return mockSystem; -} - export async function addMockRouteToRepository(repository: ShuttleGetterSetterRepository, systemId: string) { const mockRoutes = generateMockRoutes(); const mockRoute = mockRoutes[0]; From 4b610c3ba9076e096a1f9de499c457fa9f274dcf Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:09:52 -0700 Subject: [PATCH 38/71] add systemId to ordered stop and ETA entities --- src/entities/entities.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/entities/entities.ts b/src/entities/entities.ts index 8d1f0ad..f98faa5 100644 --- a/src/entities/entities.ts +++ b/src/entities/entities.ts @@ -40,6 +40,7 @@ export interface IEta extends IEntityWithOptionalTimestamp { secondsRemaining: number; shuttleId: string; stopId: string; + systemId: string; } export interface IOrderedStop extends IEntityWithOptionalTimestamp { @@ -48,5 +49,6 @@ export interface IOrderedStop extends IEntityWithOptionalTimestamp { routeId: string; stopId: string; position: number; + systemId: string; } From 973867bd6d59d920f0866b157e31ef8ee8f0501d Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:11:36 -0700 Subject: [PATCH 39/71] update loader to add system ID to ordered stop and ETA --- src/loaders/ApiBasedShuttleRepositoryLoader.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index 17c6fa0..5d6e952 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -215,6 +215,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader shuttleId: `${shuttleId}`, stopId: stopId, millisecondsSinceEpoch: Date.now(), + systemId: this.systemId, }; this.repository.addOrUpdateEta(eta); @@ -272,6 +273,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader routeId, stopId, position: index + 1, + systemId: this.systemId, }; } @@ -280,6 +282,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader routeId, stopId: jsonOrderedStopData[index - 1][1], position: index, + systemId: this.systemId, }; } if (index < jsonOrderedStopData.length - 1) { @@ -287,6 +290,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader routeId, stopId: jsonOrderedStopData[index + 1][1], position: index + 2, + systemId: this.systemId, }; } From 329f21beb78130dcdc0d51e2126f704a9da65703 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:12:08 -0700 Subject: [PATCH 40/71] add systemId to ordered stop and route resolvers --- src/resolvers/OrderedStopResolvers.ts | 2 ++ src/resolvers/RouteResolvers.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/src/resolvers/OrderedStopResolvers.ts b/src/resolvers/OrderedStopResolvers.ts index 6190814..21b4f31 100644 --- a/src/resolvers/OrderedStopResolvers.ts +++ b/src/resolvers/OrderedStopResolvers.ts @@ -24,6 +24,7 @@ export const OrderedStopResolvers: Resolvers = { route: parent.route, routeId: parent.routeId, stopId: nextOrderedStopObject.id, + systemId: system.id, } }, previousStop: async (parent, args, contextValue, _info): Promise => { @@ -47,6 +48,7 @@ export const OrderedStopResolvers: Resolvers = { route: parent.route, routeId: parent.routeId, stopId: previousOrderedStopObject.id, + systemId: system.id, } }, stop: async (parent, args, contextValue, _info) => { diff --git a/src/resolvers/RouteResolvers.ts b/src/resolvers/RouteResolvers.ts index 2b5dfa8..aa29fdc 100644 --- a/src/resolvers/RouteResolvers.ts +++ b/src/resolvers/RouteResolvers.ts @@ -40,6 +40,7 @@ export const RouteResolvers: Resolvers = { stopId: args.forStopId, routeId: parent.id, route: parent, + systemId: system.id, } }, }, From 3d13bad11c1e0c40c9aeaafd6f2d538ab00d2d7a Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:14:12 -0700 Subject: [PATCH 41/71] update mock data generators --- test/testHelpers/mockDataGenerators.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/testHelpers/mockDataGenerators.ts b/test/testHelpers/mockDataGenerators.ts index c89517b..8f2afa4 100644 --- a/test/testHelpers/mockDataGenerators.ts +++ b/test/testHelpers/mockDataGenerators.ts @@ -67,17 +67,17 @@ export function generateMockStops(): IStop[] { export function generateMockOrderedStops(): IOrderedStop[] { return [ - { stopId: "st1", routeId: "r1", position: 1 }, - { stopId: "st1", routeId: "r2", position: 2 }, - { stopId: "st2", routeId: "r1", position: 3 }, - { stopId: "st2", routeId: "r2", position: 4 }, + { stopId: "st1", routeId: "r1", position: 1, systemId: "sys1" }, + { stopId: "st1", routeId: "r2", position: 2, systemId: "sys1" }, + { stopId: "st2", routeId: "r1", position: 3, systemId: "sys1" }, + { stopId: "st2", routeId: "r2", position: 4, systemId: "sys1" }, ]; } export function generateMockEtas(): IEta[] { return [ - { shuttleId: "sh1", stopId: "st1", secondsRemaining: 120 }, - { shuttleId: "sh1", stopId: "st2", secondsRemaining: 180 }, - { shuttleId: "sh2", stopId: "st3", secondsRemaining: 240 }, + { shuttleId: "sh1", stopId: "st1", secondsRemaining: 120, systemId: "sys1" }, + { shuttleId: "sh1", stopId: "st2", secondsRemaining: 180, systemId: "sys1" }, + { shuttleId: "sh2", stopId: "st3", secondsRemaining: 240, systemId: "sys1" }, ]; } From d950156161fd94ea662b115ab316977f52b4f1da Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:18:07 -0700 Subject: [PATCH 42/71] use findSystemById function in query resolvers --- src/resolvers/QueryResolvers.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/resolvers/QueryResolvers.ts b/src/resolvers/QueryResolvers.ts index 34c31e3..08a415f 100644 --- a/src/resolvers/QueryResolvers.ts +++ b/src/resolvers/QueryResolvers.ts @@ -13,10 +13,8 @@ export const QueryResolvers: Resolvers = { }, system: async (_parent, args, contextValue, _info) => { if (!args.id) return null; - const system = contextValue.systems.find((system) => { - return system.id === args.id; - }); - if (system === undefined) return null; + const system = contextValue.findSystemById(args.id); + if (system === null) return null; return { name: system.name, From 2ba64a9b0da7fd55258b6b6daf24c03384a11a35 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:18:26 -0700 Subject: [PATCH 43/71] attach the context correctly in system resolver tests --- test/resolvers/SystemResolverTests.test.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/resolvers/SystemResolverTests.test.ts b/test/resolvers/SystemResolverTests.test.ts index af37384..bf86d8e 100644 --- a/test/resolvers/SystemResolverTests.test.ts +++ b/test/resolvers/SystemResolverTests.test.ts @@ -27,9 +27,7 @@ describe("SystemResolvers", () => { systemId: mockSystem.id, }, }, { - contextValue: { - shuttleRepository: context.systems[0].shuttleRepository, - }, + contextValue: context, }); } @@ -109,9 +107,7 @@ describe("SystemResolvers", () => { stopId: stopId, }, }, { - contextValue: { - shuttleRepository: context.systems[0].shuttleRepository, - } + contextValue: context, }); } From d20711d53d5d87646ef24e46f63315662d9b4999 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:26:18 -0700 Subject: [PATCH 44/71] update setup method to correctly create new system for testing every test --- test/testHelpers/apolloTestServerHelpers.ts | 26 ++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/test/testHelpers/apolloTestServerHelpers.ts b/test/testHelpers/apolloTestServerHelpers.ts index 00f422b..6db5542 100644 --- a/test/testHelpers/apolloTestServerHelpers.ts +++ b/test/testHelpers/apolloTestServerHelpers.ts @@ -19,6 +19,17 @@ function setUpTestServer() { }); } +const systemInfoForTesting = { + id: "1", name: "Chapman University", passioSystemId: "263" +}; + +export function buildSystemForTesting() { + return InterchangeSystem.build( + systemInfoForTesting, + new InMemoryNotificationRepository() + ); +} + /** * Returns a `ServerContext` object which can be passed to requests * for testing. @@ -26,18 +37,11 @@ function setUpTestServer() { export function setupTestServerContext() { const context: { [key: string] : any } = {}; - const systems = [ - InterchangeSystem.build( - { - id: "1", name: "Chapman University", passioSystemId: "263" - }, - new InMemoryNotificationRepository() - ), - ] - beforeEach(() => { - context.systems = systems; - context.findSystemById = (_: string) => systems[0]; + context.systems = [ + buildSystemForTesting(), + ]; + context.findSystemById = (_: string) => context.systems[0]; }); return context as ServerContext; From 1e7082813ddacd5b94657262c2e37b393ebf4131 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:26:49 -0700 Subject: [PATCH 45/71] reference correct system which is rebuilt every test --- test/resolvers/StopResolverTests.test.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/resolvers/StopResolverTests.test.ts b/test/resolvers/StopResolverTests.test.ts index 13425e4..ac732e8 100644 --- a/test/resolvers/StopResolverTests.test.ts +++ b/test/resolvers/StopResolverTests.test.ts @@ -1,7 +1,10 @@ import { beforeEach, describe, expect, it } from "@jest/globals"; -import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; +import { + setupTestServerContext, + setupTestServerHolder +} from "../testHelpers/apolloTestServerHelpers"; import { generateMockEtas, generateMockOrderedStops } from "../testHelpers/mockDataGenerators"; -import { IStop, IPassioSystem } from "../../src/entities/entities"; +import { IStop } from "../../src/entities/entities"; import { addMockStopToRepository } from "../testHelpers/repositorySetupHelpers"; import assert = require("node:assert"); @@ -10,18 +13,16 @@ describe("StopResolvers", () => { const context = setupTestServerContext(); let mockStop: IStop; - let mockSystem: IPassioSystem; beforeEach(async () => { - mockSystem = context.systems[0]; - mockStop = await addMockStopToRepository(context.systems[0].shuttleRepository, mockSystem.id); + mockStop = await addMockStopToRepository(context.systems[0].shuttleRepository, context.systems[0].id); }) async function getResponseForQuery(query: string) { return await holder.testServer.executeOperation({ query, variables: { - systemId: mockSystem.id, + systemId: context.systems[0].id, stopId: mockStop.id, }, }, { From a830dadbeecda2566011ae10877636744ad18064 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:31:16 -0700 Subject: [PATCH 46/71] use system ID provided on ordered stop to look for system --- src/resolvers/OrderedStopResolvers.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/resolvers/OrderedStopResolvers.ts b/src/resolvers/OrderedStopResolvers.ts index 21b4f31..0410e46 100644 --- a/src/resolvers/OrderedStopResolvers.ts +++ b/src/resolvers/OrderedStopResolvers.ts @@ -7,8 +7,7 @@ export const OrderedStopResolvers: Resolvers = { const routeId = parent.routeId; const stopId = parent.stopId; - if (!parent.stop) return null; - const system = contextValue.findSystemById(parent.stop.systemId); + const system = contextValue.findSystemById(parent.systemId); if (!system) return null; const currentOrderedStop = await system.shuttleRepository.getOrderedStopByRouteAndStopId(routeId, stopId); @@ -31,8 +30,7 @@ export const OrderedStopResolvers: Resolvers = { const routeId = parent.routeId; const stopId = parent.stopId; - if (!parent.stop) return null; - const system = contextValue.findSystemById(parent.stop.systemId); + const system = contextValue.findSystemById(parent.systemId); if (!system) return null; const currentOrderedStop = await system.shuttleRepository.getOrderedStopByRouteAndStopId(routeId, stopId); @@ -52,15 +50,13 @@ export const OrderedStopResolvers: Resolvers = { } }, stop: async (parent, args, contextValue, _info) => { - if (!parent.stop) return null; - const system = contextValue.findSystemById(parent.stop.systemId); + const system = contextValue.findSystemById(parent.systemId); if (!system) return null; return await system.shuttleRepository.getStopById(parent.stopId); }, route: async (parent, args, contextValue, _info) => { - if (!parent.stop) return null; - const system = contextValue.findSystemById(parent.stop.systemId); + const system = contextValue.findSystemById(parent.systemId); if (!system) return null; return await system.shuttleRepository.getRouteById(parent.routeId); From c8ea8226265fc3ce87374e131b39053d9b54032b Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:37:08 -0700 Subject: [PATCH 47/71] update query resolver tests to modify the context --- test/resolvers/QueryResolverTests.test.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test/resolvers/QueryResolverTests.test.ts b/test/resolvers/QueryResolverTests.test.ts index a6c9a40..c471549 100644 --- a/test/resolvers/QueryResolverTests.test.ts +++ b/test/resolvers/QueryResolverTests.test.ts @@ -1,6 +1,10 @@ import { describe, expect, it } from "@jest/globals"; import { generateMockPassioSystems } from "../testHelpers/mockDataGenerators"; -import { setupTestServerContext, setupTestServerHolder } from "../testHelpers/apolloTestServerHelpers"; +import { + buildSystemForTesting, + setupTestServerContext, + setupTestServerHolder +} from "../testHelpers/apolloTestServerHelpers"; import assert = require("node:assert"); import { addMockShuttleToRepository, addMockStopToRepository } from "../testHelpers/repositorySetupHelpers"; import { ScheduledNotification } from "../../src/repositories/NotificationRepository"; @@ -50,6 +54,13 @@ describe("QueryResolvers", () => { `; it("returns a system for an ID from the repository", async () => { + context.systems = [ + buildSystemForTesting(), + buildSystemForTesting(), + ]; + context.findSystemById = (_: string) => context.systems[1]; + context.systems[1].id = "test-id"; + const systems = context.systems; const systemToGet = systems[1]; @@ -69,6 +80,8 @@ describe("QueryResolvers", () => { }); it("returns null if there is no system", async () => { + context.findSystemById = (_: string) => null; + const response = await holder.testServer.executeOperation({ query, variables: { From ea46115b86050a3bec627a3e3f9426bed6787ae0 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:40:53 -0700 Subject: [PATCH 48/71] add system ID to ETA object in graphql schema --- schema.graphqls | 1 + src/resolvers/ShuttleResolvers.ts | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/schema.graphqls b/schema.graphqls index b7634ef..8449ef8 100644 --- a/schema.graphqls +++ b/schema.graphqls @@ -50,6 +50,7 @@ type ETA { shuttle: Shuttle shuttleId: ID! secondsRemaining: Float! + systemId: ID! } type Shuttle { diff --git a/src/resolvers/ShuttleResolvers.ts b/src/resolvers/ShuttleResolvers.ts index 3034ca8..103e40f 100644 --- a/src/resolvers/ShuttleResolvers.ts +++ b/src/resolvers/ShuttleResolvers.ts @@ -17,6 +17,7 @@ export const ShuttleResolvers: Resolvers = { secondsRemaining: etaForStopId.secondsRemaining, shuttleId: parent.id, shuttle: parent, + systemId: system.id, }; }, etas: async (parent, args, contextValue, info) => { @@ -35,6 +36,7 @@ export const ShuttleResolvers: Resolvers = { stopId, shuttle: parent, shuttleId: parent.id, + systemId: system.id, } })); @@ -56,7 +58,7 @@ export const ShuttleResolvers: Resolvers = { id: route.id, name: route.name, polylineCoordinates: route.polylineCoordinates, - systemId: parent.systemId, + systemId: system.id, } } }, From bed2fbc7c32ab2dde78cba65362ca523c2dc514c Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:41:04 -0700 Subject: [PATCH 49/71] update shuttle test data for integration tests --- src/loaders/loadShuttleTestData.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/loaders/loadShuttleTestData.ts b/src/loaders/loadShuttleTestData.ts index ef0c13c..3332ee5 100644 --- a/src/loaders/loadShuttleTestData.ts +++ b/src/loaders/loadShuttleTestData.ts @@ -4375,11 +4375,13 @@ const orderedStopsForRedRoute: IOrderedStop[] = [ routeId: routes[0].id, stopId: stops[0].id, position: 1, + systemId: "1", }, { routeId: routes[0].id, stopId: stops[2].id, position: 2, + systemId: "1", }, ]; @@ -4388,16 +4390,19 @@ const orderedStopsForTealRoute: IOrderedStop[] = [ routeId: routes[1].id, stopId: stops[0].id, position: 1, + systemId: "1", }, { routeId: routes[1].id, stopId: stops[1].id, position: 2, + systemId: "1", }, { routeId: routes[1].id, stopId: stops[2].id, position: 2, + systemId: "1", }, ] @@ -4436,21 +4441,25 @@ const etas: IEta[] = [ stopId: stops[0].id, shuttleId: shuttles[0].id, secondsRemaining: 12.023, + systemId: "1", }, { stopId: stops[2].id, shuttleId: shuttles[0].id, secondsRemaining: 600.123, + systemId: "1", }, { stopId: stops[2].id, shuttleId: shuttles[1].id, secondsRemaining: 172.015, + systemId: "1", }, { stopId: stops[0].id, shuttleId: shuttles[1].id, secondsRemaining: 710.152, + systemId: "1", } ]; From 6e9478cd18b679c17c6a3d0a9f9b478c6dd34321 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:41:27 -0700 Subject: [PATCH 50/71] update parent system ID reference for ETA resolvers --- src/resolvers/EtaResolvers.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/resolvers/EtaResolvers.ts b/src/resolvers/EtaResolvers.ts index 0dabe62..0a2219f 100644 --- a/src/resolvers/EtaResolvers.ts +++ b/src/resolvers/EtaResolvers.ts @@ -4,15 +4,13 @@ import { ServerContext } from "../ServerContext"; export const EtaResolvers: Resolvers = { ETA: { stop: async (parent, args, contextValue, info) => { - if (!parent.shuttle) return null; - const system = contextValue.findSystemById(parent.shuttle.systemId); + const system = contextValue.findSystemById(parent.systemId); if (!system) return null; return await system.shuttleRepository.getStopById(parent.stopId); }, shuttle: async (parent, args, contextValue, info) => { - if (!parent.stop) return null; - const system = contextValue.findSystemById(parent.stop.systemId); + const system = contextValue.findSystemById(parent.systemId); if (!system) return null; return await system.shuttleRepository.getShuttleById(parent.shuttleId); From 0525ccc7e47bbe300dae86eca55dad73b4ed8e7d Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:42:34 -0700 Subject: [PATCH 51/71] update system ID in ETA notification scheduler test --- .../schedulers/ETANotificationSchedulerTests.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/notifications/schedulers/ETANotificationSchedulerTests.test.ts b/test/notifications/schedulers/ETANotificationSchedulerTests.test.ts index 7d9392f..58ee0b3 100644 --- a/test/notifications/schedulers/ETANotificationSchedulerTests.test.ts +++ b/test/notifications/schedulers/ETANotificationSchedulerTests.test.ts @@ -50,6 +50,7 @@ describe("ETANotificationScheduler", () => { shuttleId: shuttle.id, stopId: stop.id, secondsRemaining: 120, + systemId: "1", }; const notificationData1 = { From 87dfd0dab1a8ee703a41728c0351e0a8beb8defd Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:47:31 -0700 Subject: [PATCH 52/71] rename build method to buildForTesting --- src/entities/InterchangeSystem.ts | 6 +++--- test/testHelpers/apolloTestServerHelpers.ts | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index 5a2dc9f..106ea01 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -5,6 +5,7 @@ import { UnoptimizedInMemoryShuttleRepository } from "../repositories/Unoptimize import { RedisNotificationRepository } from "../repositories/RedisNotificationRepository"; import { NotificationRepository } from "../repositories/NotificationRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; +import { InMemoryNotificationRepository } from "../repositories/InMemoryNotificationRepository"; export interface InterchangeSystemBuilderArguments { name: string; @@ -35,15 +36,14 @@ export class InterchangeSystem { * Construct an instance of the class where all composited * classes are correctly linked. * @param args - * @param notificationRepository */ - static build( + static buildForTesting( args: InterchangeSystemBuilderArguments, - notificationRepository: NotificationRepository = new RedisNotificationRepository() ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); + const notificationRepository = new InMemoryNotificationRepository(); const notificationScheduler = new ETANotificationScheduler(shuttleRepository, notificationRepository); return new InterchangeSystem( diff --git a/test/testHelpers/apolloTestServerHelpers.ts b/test/testHelpers/apolloTestServerHelpers.ts index 6db5542..731ae98 100644 --- a/test/testHelpers/apolloTestServerHelpers.ts +++ b/test/testHelpers/apolloTestServerHelpers.ts @@ -24,9 +24,8 @@ const systemInfoForTesting = { }; export function buildSystemForTesting() { - return InterchangeSystem.build( + return InterchangeSystem.buildForTesting( systemInfoForTesting, - new InMemoryNotificationRepository() ); } From 96d4acb762f8509fe2579caee94a3ee92bb84b31 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:49:06 -0700 Subject: [PATCH 53/71] construct AppleNotificationSender to not send notifications --- src/entities/InterchangeSystem.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index 106ea01..4db31a6 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -6,6 +6,7 @@ import { RedisNotificationRepository } from "../repositories/RedisNotificationRe import { NotificationRepository } from "../repositories/NotificationRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; import { InMemoryNotificationRepository } from "../repositories/InMemoryNotificationRepository"; +import { AppleNotificationSender } from "../notifications/senders/AppleNotificationSender"; export interface InterchangeSystemBuilderArguments { name: string; @@ -44,7 +45,11 @@ export class InterchangeSystem { const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); const notificationRepository = new InMemoryNotificationRepository(); - const notificationScheduler = new ETANotificationScheduler(shuttleRepository, notificationRepository); + const notificationScheduler = new ETANotificationScheduler( + shuttleRepository, + notificationRepository, + new AppleNotificationSender(false), + ); return new InterchangeSystem( args.name, From 554898b097b9110164acc01f2da9ec6b2486e2f7 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:50:49 -0700 Subject: [PATCH 54/71] add another build method for use in development/production --- src/entities/InterchangeSystem.ts | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index 4db31a6..b21a2ba 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -35,7 +35,36 @@ export class InterchangeSystem { /** * Construct an instance of the class where all composited - * classes are correctly linked. + * classes are correctly linked, meant for use in development and production. + * @param args + */ + static build( + args: InterchangeSystemBuilderArguments, + ) { + const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); + const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); + + const notificationRepository = new RedisNotificationRepository(); + const notificationScheduler = new ETANotificationScheduler( + shuttleRepository, + notificationRepository, + new AppleNotificationSender(), + ); + + return new InterchangeSystem( + args.name, + args.id, + shuttleDataLoader, + shuttleRepository, + notificationScheduler, + notificationRepository, + ); + } + + /** + * Construct an instance of the class where all composited + * classes are correctly linked, meant for unit tests, and server/app + * integration tests. * @param args */ static buildForTesting( From 60256ce572663ed88241bb26bbdd64ac3e737ece Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:55:10 -0700 Subject: [PATCH 55/71] update integration test data to use interchange system builder arguments --- src/loaders/loadShuttleTestData.ts | 32 ++++++++++++++++-------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/loaders/loadShuttleTestData.ts b/src/loaders/loadShuttleTestData.ts index 3332ee5..c59b4bf 100644 --- a/src/loaders/loadShuttleTestData.ts +++ b/src/loaders/loadShuttleTestData.ts @@ -1,11 +1,13 @@ // Mock data import { IEta, IOrderedStop, IRoute, IShuttle, IStop, IPassioSystem } from "../entities/entities"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; +import { InterchangeSystemBuilderArguments } from "../entities/InterchangeSystem"; -const systems: IPassioSystem[] = [ +export const supportedIntegrationTestSystems: InterchangeSystemBuilderArguments[] = [ { id: "1", name: "Chapman University", + passioSystemId: "263", }, ]; @@ -4327,14 +4329,14 @@ const routes: IRoute[] = [ { name: "Red Route", id: "1", - systemId: systems[0].id, + systemId: supportedIntegrationTestSystems[0].id, polylineCoordinates: redRoutePolylineCoordinates, color: "#db2316", }, { name: "Teal Route", id: "2", - systemId: systems[0].id, + systemId: supportedIntegrationTestSystems[0].id, polylineCoordinates: tealRoutePolylineCoordinates, color: "#21bdd1", }, @@ -4348,7 +4350,7 @@ const stops: IStop[] = [ latitude: 33.796001, longitude: -117.8892805, }, - systemId: systems[0].id, + systemId: supportedIntegrationTestSystems[0].id, }, { id: "2", @@ -4357,7 +4359,7 @@ const stops: IStop[] = [ latitude: 33.804433, longitude: -117.895966, }, - systemId: systems[0].id, + systemId: supportedIntegrationTestSystems[0].id, }, { id: "3", @@ -4366,7 +4368,7 @@ const stops: IStop[] = [ "latitude": 33.793325, "longitude": -117.85281 }, - systemId: systems[0].id, + systemId: supportedIntegrationTestSystems[0].id, } ]; @@ -4390,19 +4392,19 @@ const orderedStopsForTealRoute: IOrderedStop[] = [ routeId: routes[1].id, stopId: stops[0].id, position: 1, - systemId: "1", + systemId: supportedIntegrationTestSystems[0].id, }, { routeId: routes[1].id, stopId: stops[1].id, position: 2, - systemId: "1", + systemId: supportedIntegrationTestSystems[0].id, }, { routeId: routes[1].id, stopId: stops[2].id, position: 2, - systemId: "1", + systemId: supportedIntegrationTestSystems[0].id, }, ] @@ -4420,7 +4422,7 @@ const shuttles: IShuttle[] = [ longitude: -117.883698, }, routeId: routes[0].id, - systemId: systems[0].id, + systemId: supportedIntegrationTestSystems[0].id, orientationInDegrees: 45.91, }, { @@ -4431,7 +4433,7 @@ const shuttles: IShuttle[] = [ longitude: -117.862825, }, routeId: routes[0].id, - systemId: systems[0].id, + systemId: supportedIntegrationTestSystems[0].id, orientationInDegrees: 90.24, } ]; @@ -4441,25 +4443,25 @@ const etas: IEta[] = [ stopId: stops[0].id, shuttleId: shuttles[0].id, secondsRemaining: 12.023, - systemId: "1", + systemId: supportedIntegrationTestSystems[0].id, }, { stopId: stops[2].id, shuttleId: shuttles[0].id, secondsRemaining: 600.123, - systemId: "1", + systemId: supportedIntegrationTestSystems[0].id, }, { stopId: stops[2].id, shuttleId: shuttles[1].id, secondsRemaining: 172.015, - systemId: "1", + systemId: supportedIntegrationTestSystems[0].id, }, { stopId: stops[0].id, shuttleId: shuttles[1].id, secondsRemaining: 710.152, - systemId: "1", + systemId: supportedIntegrationTestSystems[0].id, } ]; From 476b96c423922ad34ff1cffb11a6d14d391cb6b7 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 12:59:04 -0700 Subject: [PATCH 56/71] listen for notification updates in the builder methods --- src/entities/InterchangeSystem.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index b21a2ba..4b543c1 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -50,6 +50,7 @@ export class InterchangeSystem { notificationRepository, new AppleNotificationSender(), ); + notificationScheduler.startListeningForUpdates(); return new InterchangeSystem( args.name, @@ -79,6 +80,7 @@ export class InterchangeSystem { notificationRepository, new AppleNotificationSender(false), ); + notificationScheduler.startListeningForUpdates(); return new InterchangeSystem( args.name, From e4ff597385abce290b296547fe5ccdf6193927d2 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:00:24 -0700 Subject: [PATCH 57/71] swap shuttle data loaders for buildForTesting method --- src/entities/InterchangeSystem.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index 4b543c1..9fb4bba 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -7,6 +7,7 @@ import { NotificationRepository } from "../repositories/NotificationRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository"; import { InMemoryNotificationRepository } from "../repositories/InMemoryNotificationRepository"; import { AppleNotificationSender } from "../notifications/senders/AppleNotificationSender"; +import { ApiBasedShuttleRepositoryLoader } from "../loaders/ApiBasedShuttleRepositoryLoader"; export interface InterchangeSystemBuilderArguments { name: string; @@ -72,7 +73,7 @@ export class InterchangeSystem { args: InterchangeSystemBuilderArguments, ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); - const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); + const shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); const notificationRepository = new InMemoryNotificationRepository(); const notificationScheduler = new ETANotificationScheduler( From 34765a0f3bd7ed79100c640b44a239368f6eb8df Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:02:13 -0700 Subject: [PATCH 58/71] update initialization of systems in index file --- src/index.ts | 71 +++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/src/index.ts b/src/index.ts index de49b21..a169a0c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,17 +3,20 @@ import { ApolloServer } from "@apollo/server"; import { startStandaloneServer } from "@apollo/server/standalone"; import { MergedResolvers } from "./MergedResolvers"; import { ServerContext } from "./ServerContext"; -import { UnoptimizedInMemoryShuttleRepository } from "./repositories/UnoptimizedInMemoryShuttleRepository"; -import { TimedApiBasedShuttleRepositoryLoader } from "./loaders/TimedApiBasedShuttleRepositoryLoader"; -import { ETANotificationScheduler } from "./notifications/schedulers/ETANotificationScheduler"; -import { loadShuttleTestData } from "./loaders/loadShuttleTestData"; -import { AppleNotificationSender } from "./notifications/senders/AppleNotificationSender"; -import { InMemoryNotificationRepository } from "./repositories/InMemoryNotificationRepository"; -import { NotificationRepository } from "./repositories/NotificationRepository"; -import { RedisNotificationRepository } from "./repositories/RedisNotificationRepository"; +import { loadShuttleTestData, supportedIntegrationTestSystems } from "./loaders/loadShuttleTestData"; +import { InterchangeSystem, InterchangeSystemBuilderArguments } from "./entities/InterchangeSystem"; const typeDefs = readFileSync("./schema.graphqls", "utf8"); +// In the future this can be stored as a separate file +const supportedSystems: InterchangeSystemBuilderArguments[] = [ + { + id: "1", + passioSystemId: "263", + name: "Chapman University", + } +] + async function main() { const server = new ApolloServer({ typeDefs, @@ -21,39 +24,27 @@ async function main() { introspection: process.env.NODE_ENV !== "production", }); - const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); - - let notificationRepository: NotificationRepository; - let notificationService: ETANotificationScheduler; + let systems: InterchangeSystem[]; if (process.argv.length > 2 && process.argv[2] == "integration-testing") { console.log("Using integration testing setup") - await loadShuttleTestData(shuttleRepository); - const appleNotificationSender = new AppleNotificationSender(false); - notificationRepository = new InMemoryNotificationRepository(); + systems = await Promise.all(supportedIntegrationTestSystems.map( + async (systemArguments) => { + const system = InterchangeSystem.buildForTesting(systemArguments); - notificationService = new ETANotificationScheduler( - shuttleRepository, - notificationRepository, - appleNotificationSender - ); - notificationService.startListeningForUpdates(); + // Have loading of different data for different systems in the future + await loadShuttleTestData(system.shuttleRepository); + + return system; + } + )); } else { - const repositoryDataUpdater = new TimedApiBasedShuttleRepositoryLoader( - shuttleRepository, - ); - await repositoryDataUpdater.start(); - - const redisNotificationRepository = new RedisNotificationRepository(); - await redisNotificationRepository.connect(); - - notificationRepository = redisNotificationRepository; - notificationService = new ETANotificationScheduler( - shuttleRepository, - notificationRepository - ); - notificationService.startListeningForUpdates(); + systems = await Promise.all(supportedSystems.map( + async (systemArguments) => { + return InterchangeSystem.buildForTesting(systemArguments); + }, + )); } const { url } = await startStandaloneServer(server, { @@ -62,8 +53,14 @@ async function main() { }, context: async () => { return { - shuttleRepository, - notificationRepository, + systems, + findSystemById: (id: string) => { + const system = systems.find((system) => system.id === id); + if (!system) { + return null; + } + return system; + }, } }, }); From 12f0a411533441005f4a267f36b93acff62f9865 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:19:43 -0700 Subject: [PATCH 59/71] update builder method and use in index --- src/entities/InterchangeSystem.ts | 4 +++- src/index.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index 9fb4bba..efe30cd 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -39,13 +39,15 @@ export class InterchangeSystem { * classes are correctly linked, meant for use in development and production. * @param args */ - static build( + static async build( args: InterchangeSystemBuilderArguments, ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); + await shuttleDataLoader.start(); const notificationRepository = new RedisNotificationRepository(); + await notificationRepository.connect(); const notificationScheduler = new ETANotificationScheduler( shuttleRepository, notificationRepository, diff --git a/src/index.ts b/src/index.ts index a169a0c..434cc54 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,7 +42,7 @@ async function main() { } else { systems = await Promise.all(supportedSystems.map( async (systemArguments) => { - return InterchangeSystem.buildForTesting(systemArguments); + return await InterchangeSystem.build(systemArguments); }, )); } From 25f2a8c4581e20b8876644ef92fdf62a6fc1269b Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:26:19 -0700 Subject: [PATCH 60/71] differentiate between passio system ID and internal ID in loader class --- src/entities/InterchangeSystem.ts | 12 ++++++++-- .../ApiBasedShuttleRepositoryLoader.ts | 23 ++++++++++--------- .../TimedApiBasedShuttleRepositoryLoader.ts | 5 ++-- ...iBasedShuttleRepositoryLoaderTests.test.ts | 8 +++---- ...iBasedShuttleRepositoryLoaderTests.test.ts | 6 ++++- 5 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/entities/InterchangeSystem.ts b/src/entities/InterchangeSystem.ts index efe30cd..abd045f 100644 --- a/src/entities/InterchangeSystem.ts +++ b/src/entities/InterchangeSystem.ts @@ -43,7 +43,11 @@ export class InterchangeSystem { args: InterchangeSystemBuilderArguments, ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); - const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); + const shuttleDataLoader = new TimedApiBasedShuttleRepositoryLoader( + args.passioSystemId, + args.id, + shuttleRepository + ); await shuttleDataLoader.start(); const notificationRepository = new RedisNotificationRepository(); @@ -75,7 +79,11 @@ export class InterchangeSystem { args: InterchangeSystemBuilderArguments, ) { const shuttleRepository = new UnoptimizedInMemoryShuttleRepository(); - const shuttleDataLoader = new ApiBasedShuttleRepositoryLoader(args.passioSystemId, shuttleRepository); + const shuttleDataLoader = new ApiBasedShuttleRepositoryLoader( + args.passioSystemId, + args.id, + shuttleRepository + ); const notificationRepository = new InMemoryNotificationRepository(); const notificationScheduler = new ETANotificationScheduler( diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index 5d6e952..278985e 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -18,7 +18,8 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader baseUrl = "https://passiogo.com/mapGetData.php"; constructor( - public systemId: string, + public passioSystemId: string, + public systemIdForConstructedData: string, public repository: ShuttleGetterSetterRepository, ) { } @@ -33,7 +34,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateRouteDataForSystem() { - const systemId = this.systemId; + const systemId = this.passioSystemId; const routeIdsToPrune = await this.constructExistingEntityIdSet(async () => { return await this.repository.getRoutesBySystemId(systemId); }); @@ -65,7 +66,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader color: jsonRoute.color, id: jsonRoute.myid, polylineCoordinates: [], - systemId: systemId, + systemId: this.systemIdForConstructedData, }; await this.repository.addOrUpdateRoute(constructedRoute); @@ -83,7 +84,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateStopAndPolylineDataForRoutesInSystem() { - const systemId = this.systemId; + const systemId = this.passioSystemId; // Fetch from the API // Pass JSON output into two different methods to update repository @@ -124,7 +125,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateShuttleDataForSystem() { - const systemId = this.systemId; + const systemId = this.passioSystemId; const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => { return await this.repository.getShuttlesBySystemId(systemId); }); @@ -163,7 +164,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader longitude: parseFloat(jsonBus.longitude), }, routeId: jsonBus.routeId, - systemId: systemId, + systemId: this.systemIdForConstructedData, id: `${jsonBus.busId}`, orientationInDegrees: parseFloat(jsonBus.calculatedCourse) } @@ -183,7 +184,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateEtaDataForExistingStopsForSystem() { - const stops = await this.repository.getStopsBySystemId(this.systemId); + const stops = await this.repository.getStopsBySystemId(this.passioSystemId); await Promise.all(stops.map(async (stop) => { let stopId = stop.id; await this.fetchAndUpdateEtaDataForStopId(stopId); @@ -215,7 +216,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader shuttleId: `${shuttleId}`, stopId: stopId, millisecondsSinceEpoch: Date.now(), - systemId: this.systemId, + systemId: this.systemIdForConstructedData, }; this.repository.addOrUpdateEta(eta); @@ -273,7 +274,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader routeId, stopId, position: index + 1, - systemId: this.systemId, + systemId: this.systemIdForConstructedData, }; } @@ -282,7 +283,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader routeId, stopId: jsonOrderedStopData[index - 1][1], position: index, - systemId: this.systemId, + systemId: this.systemIdForConstructedData, }; } if (index < jsonOrderedStopData.length - 1) { @@ -290,7 +291,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader routeId, stopId: jsonOrderedStopData[index + 1][1], position: index + 2, - systemId: this.systemId, + systemId: this.systemIdForConstructedData, }; } diff --git a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts index 151c218..15a7d59 100644 --- a/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/TimedApiBasedShuttleRepositoryLoader.ts @@ -22,10 +22,11 @@ export class TimedApiBasedShuttleRepositoryLoader extends ApiBasedShuttleReposit readonly timeout = 10000; constructor( - public systemId: string, + public passioSystemId: string, + public systemIdForConstructedData: string, repository: ShuttleGetterSetterRepository, ) { - super(systemId, repository); + super(passioSystemId, systemIdForConstructedData, repository); this.startFetchDataAndUpdate = this.startFetchDataAndUpdate.bind(this); } diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index 7a81d2a..3392428 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -1,13 +1,11 @@ -import { beforeEach, describe, expect, it, jest, test } from "@jest/globals"; +import { beforeEach, describe, expect, it, jest } from "@jest/globals"; import { ApiBasedShuttleRepositoryLoader, ApiResponseError } from "../../src/loaders/ApiBasedShuttleRepositoryLoader"; import { UnoptimizedInMemoryShuttleRepository } from "../../src/repositories/UnoptimizedInMemoryShuttleRepository"; -import { fetchSystemDataSuccessfulResponse } from "../jsonSnapshots/fetchSystemData/fetchSystemDataSuccessfulResponse"; -import { fetchSystemDataFailedResponse } from "../jsonSnapshots/fetchSystemData/fetchSystemDataFailedResponse"; import { fetchRouteDataSuccessfulResponse } from "../jsonSnapshots/fetchRouteData/fetchRouteDataSuccessfulResponse"; import { fetchStopAndPolylineDataSuccessfulResponse } from "../jsonSnapshots/fetchStopAndPolylineData/fetchStopAndPolylineDataSuccessfulResponse"; -import { generateMockRoutes, generateMockShuttles, generateMockStops, generateMockPassioSystems } from "../testHelpers/mockDataGenerators"; +import { generateMockRoutes, generateMockShuttles, generateMockStops } from "../testHelpers/mockDataGenerators"; import { fetchShuttleDataSuccessfulResponse } from "../jsonSnapshots/fetchShuttleData/fetchShuttleDataSuccessfulResponse"; @@ -26,7 +24,7 @@ describe("ApiBasedRepositoryLoader", () => { let loader: ApiBasedShuttleRepositoryLoader; beforeEach(() => { - loader = new ApiBasedShuttleRepositoryLoader("263", new UnoptimizedInMemoryShuttleRepository()); + loader = new ApiBasedShuttleRepositoryLoader("263", "1", new UnoptimizedInMemoryShuttleRepository()); resetGlobalFetchMockJson(); }); diff --git a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts index 0ee8537..80a8c4d 100644 --- a/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/TimedApiBasedShuttleRepositoryLoaderTests.test.ts @@ -15,7 +15,11 @@ describe("TimedApiBasedRepositoryLoader", () => { beforeEach(() => { resetGlobalFetchMockJson(); - loader = new TimedApiBasedShuttleRepositoryLoader("1", new UnoptimizedInMemoryShuttleRepository()); + loader = new TimedApiBasedShuttleRepositoryLoader( + "1", + "1", + new UnoptimizedInMemoryShuttleRepository() + ); spies = { fetchAndUpdateRouteDataForSystem: jest.spyOn(loader, 'fetchAndUpdateRouteDataForSystem'), From 6767cc88a3eca0d41435631f9bf24d3db57c574d Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:32:45 -0700 Subject: [PATCH 61/71] make clear that data loading for different integration test systems is a TODO --- src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.ts b/src/index.ts index 434cc54..a370258 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,7 +33,7 @@ async function main() { async (systemArguments) => { const system = InterchangeSystem.buildForTesting(systemArguments); - // Have loading of different data for different systems in the future + // TODO: Have loading of different data for different systems in the future await loadShuttleTestData(system.shuttleRepository); return system; From fe6db035f1bfe03daad9adb6a949447c37dc1fd9 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:47:36 -0700 Subject: [PATCH 62/71] fix pruning and construction ID issues with repository loader --- src/loaders/ApiBasedShuttleRepositoryLoader.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index 278985e..199ca8d 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -36,7 +36,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader public async fetchAndUpdateRouteDataForSystem() { const systemId = this.passioSystemId; const routeIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getRoutesBySystemId(systemId); + return await this.repository.getRoutesBySystemId(this.systemIdForConstructedData); }); const params = { @@ -84,12 +84,12 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateStopAndPolylineDataForRoutesInSystem() { - const systemId = this.passioSystemId; + const passioSystemId = this.passioSystemId; // Fetch from the API // Pass JSON output into two different methods to update repository const stopIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getStopsBySystemId(systemId); + return await this.repository.getStopsBySystemId(this.systemIdForConstructedData); }); const params = { @@ -97,7 +97,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader }; const formDataJsonObject = { - "s0": systemId, + "s0": passioSystemId, "sA": 1 }; const formData = new FormData(); @@ -112,7 +112,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader }); const json = await response.json(); - await this.updateStopDataForSystemAndApiResponse(systemId, json, stopIdsToPrune); + await this.updateStopDataForSystemAndApiResponse(json, stopIdsToPrune); await this.updateOrderedStopDataForExistingStops(json); await this.updatePolylineDataForExistingRoutesAndApiResponse(json); @@ -127,7 +127,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader public async fetchAndUpdateShuttleDataForSystem() { const systemId = this.passioSystemId; const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getShuttlesBySystemId(systemId); + return await this.repository.getShuttlesBySystemId(this.systemIdForConstructedData); }); const params = { @@ -228,7 +228,6 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } protected async updateStopDataForSystemAndApiResponse( - systemId: string, json: any, setOfIdsToPrune: Set = new Set(), ) { @@ -239,7 +238,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader const constructedStop: IStop = { name: stop.name, id: stop.id, - systemId, + systemId: this.systemIdForConstructedData, coordinates: { latitude: parseFloat(stop.latitude), longitude: parseFloat(stop.longitude), From 8e3765abfb98522bbb31d6ff57fada2ed43688ca Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:47:50 -0700 Subject: [PATCH 63/71] update tests to correctly test internal system ID and passio ID --- test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index 3392428..965803b 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -28,8 +28,8 @@ describe("ApiBasedRepositoryLoader", () => { resetGlobalFetchMockJson(); }); + const systemId = "1"; describe("fetchAndUpdateRouteDataForSystem", () => { - const systemId = "263"; it("updates route data in repository if response received", async () => { // Arrange // Test pruning @@ -63,7 +63,6 @@ describe("ApiBasedRepositoryLoader", () => { }); describe("fetchAndUpdateStopAndPolylineDataForRoutesWithSystemId", () => { - const systemId = "263"; it("updates stop and polyline data if response received", async () => { // Arrange // Test pruning of stops only @@ -103,7 +102,6 @@ describe("ApiBasedRepositoryLoader", () => { }); describe("fetchAndUpdateShuttleDataForSystem", () => { - const systemId = "263"; it("updates shuttle data in repository if response received", async () => { const shuttlesToPrune = generateMockShuttles(); await Promise.all(shuttlesToPrune.map(async (shuttle) => { From 059a9f5067573d55e066625d8a909f99f5a388a1 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:56:26 -0700 Subject: [PATCH 64/71] fix ETA data not loading via repository loader --- src/loaders/ApiBasedShuttleRepositoryLoader.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index 199ca8d..00cf75a 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -184,7 +184,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateEtaDataForExistingStopsForSystem() { - const stops = await this.repository.getStopsBySystemId(this.passioSystemId); + const stops = await this.repository.getStopsBySystemId(this.systemIdForConstructedData); await Promise.all(stops.map(async (stop) => { let stopId = stop.id; await this.fetchAndUpdateEtaDataForStopId(stopId); From 4f7d24acf0203f9b53c6abc6cd47cd7e110bc048 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:57:14 -0700 Subject: [PATCH 65/71] add TODO to be resolved before merge --- src/repositories/ShuttleGetterRepository.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/repositories/ShuttleGetterRepository.ts b/src/repositories/ShuttleGetterRepository.ts index 0006f5f..e86cb2e 100644 --- a/src/repositories/ShuttleGetterRepository.ts +++ b/src/repositories/ShuttleGetterRepository.ts @@ -1,6 +1,7 @@ import { IEta, IOrderedStop, IRoute, IShuttle, IStop } from "../entities/entities"; export interface ShuttleGetterRepository { + // TODO: Remove system ID argument from all getters getStopsBySystemId(systemId: string): Promise; getStopById(stopId: string): Promise; From 495a946e78a25d4f3568b44bc472bbe01b83b657 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 13:59:11 -0700 Subject: [PATCH 66/71] use the correct system ID for mock data in eta loader test --- test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index 965803b..f08a19c 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -134,7 +134,7 @@ describe("ApiBasedRepositoryLoader", () => { const stops = generateMockStops(); stops.forEach((stop) => { - stop.systemId = "263"; + stop.systemId = "1"; }); await Promise.all(stops.map(async (stop) => { From 0076d987ca919e31ec7b41739812d06b0269d3ba Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 19:06:03 -0700 Subject: [PATCH 67/71] rename methods in getter repository --- .../ApiBasedShuttleRepositoryLoader.ts | 8 +-- src/repositories/ShuttleGetterRepository.ts | 11 ++-- .../UnoptimizedInMemoryShuttleRepository.ts | 8 +-- src/resolvers/ShuttleResolvers.ts | 2 +- src/resolvers/SystemResolvers.ts | 6 +-- ...iBasedShuttleRepositoryLoaderTests.test.ts | 8 +-- ...izedInMemoryShuttleRepositoryTests.test.ts | 52 +++++++++---------- 7 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index 00cf75a..e7f916f 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -36,7 +36,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader public async fetchAndUpdateRouteDataForSystem() { const systemId = this.passioSystemId; const routeIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getRoutesBySystemId(this.systemIdForConstructedData); + return await this.repository.getRoutes(this.systemIdForConstructedData); }); const params = { @@ -89,7 +89,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader // Fetch from the API // Pass JSON output into two different methods to update repository const stopIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getStopsBySystemId(this.systemIdForConstructedData); + return await this.repository.getStops(this.systemIdForConstructedData); }); const params = { @@ -127,7 +127,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader public async fetchAndUpdateShuttleDataForSystem() { const systemId = this.passioSystemId; const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getShuttlesBySystemId(this.systemIdForConstructedData); + return await this.repository.getShuttles(this.systemIdForConstructedData); }); const params = { @@ -184,7 +184,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateEtaDataForExistingStopsForSystem() { - const stops = await this.repository.getStopsBySystemId(this.systemIdForConstructedData); + const stops = await this.repository.getStops(this.systemIdForConstructedData); await Promise.all(stops.map(async (stop) => { let stopId = stop.id; await this.fetchAndUpdateEtaDataForStopId(stopId); diff --git a/src/repositories/ShuttleGetterRepository.ts b/src/repositories/ShuttleGetterRepository.ts index e86cb2e..ca17231 100644 --- a/src/repositories/ShuttleGetterRepository.ts +++ b/src/repositories/ShuttleGetterRepository.ts @@ -1,18 +1,21 @@ import { IEta, IOrderedStop, IRoute, IShuttle, IStop } from "../entities/entities"; +/** + * Shuttle getter repository to be linked to a system. + */ export interface ShuttleGetterRepository { // TODO: Remove system ID argument from all getters - getStopsBySystemId(systemId: string): Promise; + getStops(systemId: string): Promise; getStopById(stopId: string): Promise; - getRoutesBySystemId(systemId: string): Promise; + getRoutes(systemId: string): Promise; getRouteById(routeId: string): Promise; - getShuttlesBySystemId(systemId: string): Promise; + getShuttles(systemId: string): Promise; getShuttleById(shuttleId: string): Promise; getShuttlesByRouteId(routeId: string): Promise; - getEtasForShuttleId(shuttleId: string): Promise; + getEtas(shuttleId: string): Promise; getEtasForStopId(stopId: string): Promise; getEtaForShuttleAndStopId(shuttleId: string, stopId: string): Promise; diff --git a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts index 6d613f2..0246a9c 100644 --- a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts @@ -15,7 +15,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter private subscribers: ((eta: IEta) => void)[] = []; - public async getStopsBySystemId(systemId: string) { + public async getStops(systemId: string) { return this.stops.filter(stop => stop.systemId === systemId); } @@ -23,7 +23,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return this.findEntityById(stopId, this.stops); } - public async getRoutesBySystemId(systemId: string) { + public async getRoutes(systemId: string) { return this.routes.filter(route => route.systemId === systemId); } @@ -31,7 +31,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return this.findEntityById(routeId, this.routes); } - public async getShuttlesBySystemId(systemId: string) { + public async getShuttles(systemId: string) { return this.shuttles.filter(shuttle => shuttle.systemId === systemId); } @@ -43,7 +43,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return this.findEntityById(shuttleId, this.shuttles); } - public async getEtasForShuttleId(shuttleId: string) { + public async getEtas(shuttleId: string) { return this.etas.filter(eta => eta.shuttleId === shuttleId); } diff --git a/src/resolvers/ShuttleResolvers.ts b/src/resolvers/ShuttleResolvers.ts index 103e40f..c3f60f6 100644 --- a/src/resolvers/ShuttleResolvers.ts +++ b/src/resolvers/ShuttleResolvers.ts @@ -24,7 +24,7 @@ export const ShuttleResolvers: Resolvers = { const system = contextValue.findSystemById(parent.systemId); if (!system) return null; - const etasForShuttle = await system.shuttleRepository.getEtasForShuttleId(parent.id); + const etasForShuttle = await system.shuttleRepository.getEtas(parent.id); if (!etasForShuttle) return null; const computedEtas = await Promise.all(etasForShuttle.map(async ({ diff --git a/src/resolvers/SystemResolvers.ts b/src/resolvers/SystemResolvers.ts index 8ea01ae..febd308 100644 --- a/src/resolvers/SystemResolvers.ts +++ b/src/resolvers/SystemResolvers.ts @@ -9,7 +9,7 @@ export const SystemResolvers: Resolvers = { return []; } - return await system.shuttleRepository.getRoutesBySystemId(parent.id); + return await system.shuttleRepository.getRoutes(parent.id); }, stops: async (parent, _args, contextValue, _info) => { const system = contextValue.findSystemById(parent.id); @@ -17,7 +17,7 @@ export const SystemResolvers: Resolvers = { return []; } - return await system.shuttleRepository.getStopsBySystemId(parent.id); + return await system.shuttleRepository.getStops(parent.id); }, stop: async (parent, args, contextValue, _info) => { if (!args.id) return null; @@ -76,7 +76,7 @@ export const SystemResolvers: Resolvers = { return []; } - return await system.shuttleRepository.getShuttlesBySystemId(parent.id); + return await system.shuttleRepository.getShuttles(parent.id); } }, } diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index f08a19c..0bbd8df 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -45,7 +45,7 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateRouteDataForSystem(); // Assert - const routes = await loader.repository.getRoutesBySystemId(systemId); + const routes = await loader.repository.getRoutes(systemId); expect(routes.length).toEqual(fetchRouteDataSuccessfulResponse.all.length) }); @@ -78,7 +78,7 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateStopAndPolylineDataForRoutesInSystem(); - const stops = await loader.repository.getStopsBySystemId(systemId); + const stops = await loader.repository.getStops(systemId); expect(stops.length).toEqual(stopsArray.length); await Promise.all(stops.map(async (stop) => { @@ -86,7 +86,7 @@ describe("ApiBasedRepositoryLoader", () => { expect(orderedStops.length).toBeGreaterThan(0); })); - const routes = await loader.repository.getRoutesBySystemId(systemId); + const routes = await loader.repository.getRoutes(systemId); routes.forEach((route) => { expect(route.polylineCoordinates.length).toBeGreaterThan(0); }); @@ -114,7 +114,7 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateShuttleDataForSystem(); - const shuttles = await loader.repository.getShuttlesBySystemId(systemId); + const shuttles = await loader.repository.getShuttles(systemId); expect(shuttles.length).toEqual(busesInResponse.length); }); diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index 4cb2419..d6f6018 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -27,12 +27,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateStop(stop); } - const result = await repository.getStopsBySystemId("sys1"); + const result = await repository.getStops("sys1"); expect(result).toEqual(mockStops.filter((stop) => stop.systemId === "sys1")); }); test("returns an empty list if there are no stops for the given system ID", async () => { - const result = await repository.getStopsBySystemId("nonexistent-system"); + const result = await repository.getStops("nonexistent-system"); expect(result).toEqual([]); }); }); @@ -60,12 +60,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateRoute(route); } - const result = await repository.getRoutesBySystemId("sys1"); + const result = await repository.getRoutes("sys1"); expect(result).toEqual(mockRoutes.filter((route) => route.systemId === "sys1")); }); test("returns an empty list if there are no routes for the system ID", async () => { - const result = await repository.getRoutesBySystemId("nonexistent-system"); + const result = await repository.getRoutes("nonexistent-system"); expect(result).toEqual([]); }); }); @@ -92,12 +92,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateShuttle(shuttle); } - const result = await repository.getShuttlesBySystemId("sys1"); + const result = await repository.getShuttles("sys1"); expect(result).toEqual(mockShuttles.filter((sh) => sh.systemId === "sys1")); }); test("returns an empty list if there are no shuttles for the system ID", async () => { - const result = await repository.getShuttlesBySystemId("nonexistent-system"); + const result = await repository.getShuttles("nonexistent-system"); expect(result).toEqual([]); }); }); @@ -143,12 +143,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateEta(eta); } - const result = await repository.getEtasForShuttleId("sh1"); + const result = await repository.getEtas("sh1"); expect(result).toEqual(mockEtas.filter((eta) => eta.shuttleId === "sh1")); }); test("returns an empty list if there are no ETAs for the shuttle ID", async () => { - const result = await repository.getEtasForShuttleId("nonexistent-shuttle"); + const result = await repository.getEtas("nonexistent-shuttle"); expect(result).toEqual([]); }); }); @@ -292,7 +292,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateRoute(newRoute); - const result = await repository.getRoutesBySystemId("sys1"); + const result = await repository.getRoutes("sys1"); expect(result).toEqual([newRoute]); }); @@ -305,7 +305,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateRoute(existingRoute); await repository.addOrUpdateRoute(updatedRoute); - const result = await repository.getRoutesBySystemId("sys1"); + const result = await repository.getRoutes("sys1"); expect(result).toEqual([updatedRoute]); }); }); @@ -317,7 +317,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateShuttle(newShuttle); - const result = await repository.getShuttlesBySystemId("sys1"); + const result = await repository.getShuttles("sys1"); expect(result).toEqual([newShuttle]); }); @@ -330,7 +330,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateShuttle(existingShuttle); await repository.addOrUpdateShuttle(updatedShuttle); - const result = await repository.getShuttlesBySystemId("sys1"); + const result = await repository.getShuttles("sys1"); expect(result).toEqual([updatedShuttle]); }); }); @@ -342,7 +342,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateStop(newStop); - const result = await repository.getStopsBySystemId("sys1"); + const result = await repository.getStops("sys1"); expect(result).toEqual([newStop]); }); @@ -355,7 +355,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateStop(existingStop); await repository.addOrUpdateStop(updatedStop); - const result = await repository.getStopsBySystemId("sys1"); + const result = await repository.getStops("sys1"); expect(result).toEqual([updatedStop]); }); }); @@ -392,7 +392,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateEta(newEta); - const result = await repository.getEtasForShuttleId(newEta.shuttleId); + const result = await repository.getEtas(newEta.shuttleId); expect(result).toEqual([newEta]); }); @@ -405,7 +405,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateEta(existingEta); await repository.addOrUpdateEta(updatedEta); - const result = await repository.getEtasForShuttleId(existingEta.shuttleId); + const result = await repository.getEtas(existingEta.shuttleId); expect(result).toEqual([updatedEta]); }); }); @@ -422,7 +422,7 @@ describe("UnoptimizedInMemoryRepository", () => { const routeToRemove = mockRoutes[0]; await repository.removeRouteIfExists(routeToRemove.id); - const remainingRoutes = await repository.getRoutesBySystemId(systemId); + const remainingRoutes = await repository.getRoutes(systemId); expect(remainingRoutes).toHaveLength(mockRoutes.length - 1); }); @@ -436,7 +436,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.removeRouteIfExists("nonexistent-id"); - const remainingRoutes = await repository.getRoutesBySystemId(systemId); + const remainingRoutes = await repository.getRoutes(systemId); expect(remainingRoutes).toHaveLength(mockRoutes.length); }); }); @@ -453,7 +453,7 @@ describe("UnoptimizedInMemoryRepository", () => { const shuttleToRemove = mockShuttles[0]; await repository.removeShuttleIfExists(shuttleToRemove.id); - const remainingShuttles = await repository.getShuttlesBySystemId(systemId); + const remainingShuttles = await repository.getShuttles(systemId); expect(remainingShuttles).toHaveLength(mockShuttles.length - 1); }); @@ -467,7 +467,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.removeShuttleIfExists("nonexistent-id"); - const remainingShuttles = await repository.getShuttlesBySystemId(systemId); + const remainingShuttles = await repository.getShuttles(systemId); expect(remainingShuttles).toHaveLength(mockShuttles.length); }); }); @@ -484,7 +484,7 @@ describe("UnoptimizedInMemoryRepository", () => { const stopToRemove = mockStops[0]; await repository.removeStopIfExists(stopToRemove.id); - const remainingStops = await repository.getStopsBySystemId(systemId); + const remainingStops = await repository.getStops(systemId); expect(remainingStops).toHaveLength(mockStops.length - 1); }); @@ -498,7 +498,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.removeStopIfExists("nonexistent-id"); - const remainingStops = await repository.getStopsBySystemId(systemId); + const remainingStops = await repository.getStops(systemId); expect(remainingStops).toHaveLength(mockStops.length); }); }); @@ -580,7 +580,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearShuttleData(); - const result = await repository.getShuttlesBySystemId("sys1"); + const result = await repository.getShuttles("sys1"); expect(result).toEqual([]); }); }); @@ -594,7 +594,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearEtaData(); - const result = await repository.getEtasForShuttleId("shuttle1"); + const result = await repository.getEtas("shuttle1"); expect(result).toEqual([]); }); }); @@ -622,7 +622,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearRouteData(); - const result = await repository.getRoutesBySystemId("sys1"); + const result = await repository.getRoutes("sys1"); expect(result).toEqual([]); }); }); @@ -636,7 +636,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearStopData(); - const result = await repository.getStopsBySystemId("sys1"); + const result = await repository.getStops("sys1"); expect(result).toEqual([]); }); }); From b6f3e4ccdeeda7c003ef519c0cff2be6c216a191 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 19:17:14 -0700 Subject: [PATCH 68/71] update method signatures to not include system id --- .../ApiBasedShuttleRepositoryLoader.ts | 8 +-- src/repositories/ShuttleGetterRepository.ts | 9 ++-- .../UnoptimizedInMemoryShuttleRepository.ts | 8 +-- src/resolvers/ShuttleResolvers.ts | 2 +- src/resolvers/SystemResolvers.ts | 6 +-- ...iBasedShuttleRepositoryLoaderTests.test.ts | 8 +-- ...izedInMemoryShuttleRepositoryTests.test.ts | 52 +++++++++---------- 7 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/loaders/ApiBasedShuttleRepositoryLoader.ts b/src/loaders/ApiBasedShuttleRepositoryLoader.ts index e7f916f..49031ef 100644 --- a/src/loaders/ApiBasedShuttleRepositoryLoader.ts +++ b/src/loaders/ApiBasedShuttleRepositoryLoader.ts @@ -36,7 +36,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader public async fetchAndUpdateRouteDataForSystem() { const systemId = this.passioSystemId; const routeIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getRoutes(this.systemIdForConstructedData); + return await this.repository.getRoutes(); }); const params = { @@ -89,7 +89,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader // Fetch from the API // Pass JSON output into two different methods to update repository const stopIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getStops(this.systemIdForConstructedData); + return await this.repository.getStops(); }); const params = { @@ -127,7 +127,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader public async fetchAndUpdateShuttleDataForSystem() { const systemId = this.passioSystemId; const shuttleIdsToPrune = await this.constructExistingEntityIdSet(async () => { - return await this.repository.getShuttles(this.systemIdForConstructedData); + return await this.repository.getShuttles(); }); const params = { @@ -184,7 +184,7 @@ export class ApiBasedShuttleRepositoryLoader implements ShuttleRepositoryLoader } public async fetchAndUpdateEtaDataForExistingStopsForSystem() { - const stops = await this.repository.getStops(this.systemIdForConstructedData); + const stops = await this.repository.getStops(); await Promise.all(stops.map(async (stop) => { let stopId = stop.id; await this.fetchAndUpdateEtaDataForStopId(stopId); diff --git a/src/repositories/ShuttleGetterRepository.ts b/src/repositories/ShuttleGetterRepository.ts index ca17231..8f59578 100644 --- a/src/repositories/ShuttleGetterRepository.ts +++ b/src/repositories/ShuttleGetterRepository.ts @@ -4,18 +4,17 @@ import { IEta, IOrderedStop, IRoute, IShuttle, IStop } from "../entities/entitie * Shuttle getter repository to be linked to a system. */ export interface ShuttleGetterRepository { - // TODO: Remove system ID argument from all getters - getStops(systemId: string): Promise; + getStops(): Promise; getStopById(stopId: string): Promise; - getRoutes(systemId: string): Promise; + getRoutes(): Promise; getRouteById(routeId: string): Promise; - getShuttles(systemId: string): Promise; + getShuttles(): Promise; getShuttleById(shuttleId: string): Promise; getShuttlesByRouteId(routeId: string): Promise; - getEtas(shuttleId: string): Promise; + getEtasForShuttleId(shuttleId: string): Promise; getEtasForStopId(stopId: string): Promise; getEtaForShuttleAndStopId(shuttleId: string, stopId: string): Promise; diff --git a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts index 0246a9c..42f3ecc 100644 --- a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts @@ -15,7 +15,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter private subscribers: ((eta: IEta) => void)[] = []; - public async getStops(systemId: string) { + public async getStops(): Promise { return this.stops.filter(stop => stop.systemId === systemId); } @@ -23,7 +23,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return this.findEntityById(stopId, this.stops); } - public async getRoutes(systemId: string) { + public async getRoutes(): Promise { return this.routes.filter(route => route.systemId === systemId); } @@ -31,7 +31,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return this.findEntityById(routeId, this.routes); } - public async getShuttles(systemId: string) { + public async getShuttles(): Promise { return this.shuttles.filter(shuttle => shuttle.systemId === systemId); } @@ -43,7 +43,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter return this.findEntityById(shuttleId, this.shuttles); } - public async getEtas(shuttleId: string) { + public async getEtasForShuttleId(shuttleId: string): Promise { return this.etas.filter(eta => eta.shuttleId === shuttleId); } diff --git a/src/resolvers/ShuttleResolvers.ts b/src/resolvers/ShuttleResolvers.ts index c3f60f6..bb5d0f0 100644 --- a/src/resolvers/ShuttleResolvers.ts +++ b/src/resolvers/ShuttleResolvers.ts @@ -24,7 +24,7 @@ export const ShuttleResolvers: Resolvers = { const system = contextValue.findSystemById(parent.systemId); if (!system) return null; - const etasForShuttle = await system.shuttleRepository.getEtas(parent.id); + const etasForShuttle = await system.shuttleRepository.getEtasForShuttleId(); if (!etasForShuttle) return null; const computedEtas = await Promise.all(etasForShuttle.map(async ({ diff --git a/src/resolvers/SystemResolvers.ts b/src/resolvers/SystemResolvers.ts index febd308..de8e3b0 100644 --- a/src/resolvers/SystemResolvers.ts +++ b/src/resolvers/SystemResolvers.ts @@ -9,7 +9,7 @@ export const SystemResolvers: Resolvers = { return []; } - return await system.shuttleRepository.getRoutes(parent.id); + return await system.shuttleRepository.getRoutes(); }, stops: async (parent, _args, contextValue, _info) => { const system = contextValue.findSystemById(parent.id); @@ -17,7 +17,7 @@ export const SystemResolvers: Resolvers = { return []; } - return await system.shuttleRepository.getStops(parent.id); + return await system.shuttleRepository.getStops(); }, stop: async (parent, args, contextValue, _info) => { if (!args.id) return null; @@ -76,7 +76,7 @@ export const SystemResolvers: Resolvers = { return []; } - return await system.shuttleRepository.getShuttles(parent.id); + return await system.shuttleRepository.getShuttles(); } }, } diff --git a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts index 0bbd8df..7ff472d 100644 --- a/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts +++ b/test/loaders/ApiBasedShuttleRepositoryLoaderTests.test.ts @@ -45,7 +45,7 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateRouteDataForSystem(); // Assert - const routes = await loader.repository.getRoutes(systemId); + const routes = await loader.repository.getRoutes(); expect(routes.length).toEqual(fetchRouteDataSuccessfulResponse.all.length) }); @@ -78,7 +78,7 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateStopAndPolylineDataForRoutesInSystem(); - const stops = await loader.repository.getStops(systemId); + const stops = await loader.repository.getStops(); expect(stops.length).toEqual(stopsArray.length); await Promise.all(stops.map(async (stop) => { @@ -86,7 +86,7 @@ describe("ApiBasedRepositoryLoader", () => { expect(orderedStops.length).toBeGreaterThan(0); })); - const routes = await loader.repository.getRoutes(systemId); + const routes = await loader.repository.getRoutes(); routes.forEach((route) => { expect(route.polylineCoordinates.length).toBeGreaterThan(0); }); @@ -114,7 +114,7 @@ describe("ApiBasedRepositoryLoader", () => { await loader.fetchAndUpdateShuttleDataForSystem(); - const shuttles = await loader.repository.getShuttles(systemId); + const shuttles = await loader.repository.getShuttles(); expect(shuttles.length).toEqual(busesInResponse.length); }); diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index d6f6018..835ef39 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -27,12 +27,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateStop(stop); } - const result = await repository.getStops("sys1"); + const result = await repository.getStops(); expect(result).toEqual(mockStops.filter((stop) => stop.systemId === "sys1")); }); test("returns an empty list if there are no stops for the given system ID", async () => { - const result = await repository.getStops("nonexistent-system"); + const result = await repository.getStops(); expect(result).toEqual([]); }); }); @@ -60,12 +60,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateRoute(route); } - const result = await repository.getRoutes("sys1"); + const result = await repository.getRoutes(); expect(result).toEqual(mockRoutes.filter((route) => route.systemId === "sys1")); }); test("returns an empty list if there are no routes for the system ID", async () => { - const result = await repository.getRoutes("nonexistent-system"); + const result = await repository.getRoutes(); expect(result).toEqual([]); }); }); @@ -92,12 +92,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateShuttle(shuttle); } - const result = await repository.getShuttles("sys1"); + const result = await repository.getShuttles(); expect(result).toEqual(mockShuttles.filter((sh) => sh.systemId === "sys1")); }); test("returns an empty list if there are no shuttles for the system ID", async () => { - const result = await repository.getShuttles("nonexistent-system"); + const result = await repository.getShuttles(); expect(result).toEqual([]); }); }); @@ -143,12 +143,12 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateEta(eta); } - const result = await repository.getEtas("sh1"); + const result = await repository.getEtasForShuttleId("sh1"); expect(result).toEqual(mockEtas.filter((eta) => eta.shuttleId === "sh1")); }); test("returns an empty list if there are no ETAs for the shuttle ID", async () => { - const result = await repository.getEtas("nonexistent-shuttle"); + const result = await repository.getEtasForShuttleId("nonexistent-shuttle"); expect(result).toEqual([]); }); }); @@ -292,7 +292,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateRoute(newRoute); - const result = await repository.getRoutes("sys1"); + const result = await repository.getRoutes(); expect(result).toEqual([newRoute]); }); @@ -305,7 +305,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateRoute(existingRoute); await repository.addOrUpdateRoute(updatedRoute); - const result = await repository.getRoutes("sys1"); + const result = await repository.getRoutes(); expect(result).toEqual([updatedRoute]); }); }); @@ -317,7 +317,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateShuttle(newShuttle); - const result = await repository.getShuttles("sys1"); + const result = await repository.getShuttles(); expect(result).toEqual([newShuttle]); }); @@ -330,7 +330,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateShuttle(existingShuttle); await repository.addOrUpdateShuttle(updatedShuttle); - const result = await repository.getShuttles("sys1"); + const result = await repository.getShuttles(); expect(result).toEqual([updatedShuttle]); }); }); @@ -342,7 +342,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateStop(newStop); - const result = await repository.getStops("sys1"); + const result = await repository.getStops(); expect(result).toEqual([newStop]); }); @@ -355,7 +355,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateStop(existingStop); await repository.addOrUpdateStop(updatedStop); - const result = await repository.getStops("sys1"); + const result = await repository.getStops(); expect(result).toEqual([updatedStop]); }); }); @@ -392,7 +392,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateEta(newEta); - const result = await repository.getEtas(newEta.shuttleId); + const result = await repository.getEtasForShuttleId(newEta.shuttleId); expect(result).toEqual([newEta]); }); @@ -405,7 +405,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.addOrUpdateEta(existingEta); await repository.addOrUpdateEta(updatedEta); - const result = await repository.getEtas(existingEta.shuttleId); + const result = await repository.getEtasForShuttleId(existingEta.shuttleId); expect(result).toEqual([updatedEta]); }); }); @@ -422,7 +422,7 @@ describe("UnoptimizedInMemoryRepository", () => { const routeToRemove = mockRoutes[0]; await repository.removeRouteIfExists(routeToRemove.id); - const remainingRoutes = await repository.getRoutes(systemId); + const remainingRoutes = await repository.getRoutes(); expect(remainingRoutes).toHaveLength(mockRoutes.length - 1); }); @@ -436,7 +436,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.removeRouteIfExists("nonexistent-id"); - const remainingRoutes = await repository.getRoutes(systemId); + const remainingRoutes = await repository.getRoutes(); expect(remainingRoutes).toHaveLength(mockRoutes.length); }); }); @@ -453,7 +453,7 @@ describe("UnoptimizedInMemoryRepository", () => { const shuttleToRemove = mockShuttles[0]; await repository.removeShuttleIfExists(shuttleToRemove.id); - const remainingShuttles = await repository.getShuttles(systemId); + const remainingShuttles = await repository.getShuttles(); expect(remainingShuttles).toHaveLength(mockShuttles.length - 1); }); @@ -467,7 +467,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.removeShuttleIfExists("nonexistent-id"); - const remainingShuttles = await repository.getShuttles(systemId); + const remainingShuttles = await repository.getShuttles(); expect(remainingShuttles).toHaveLength(mockShuttles.length); }); }); @@ -484,7 +484,7 @@ describe("UnoptimizedInMemoryRepository", () => { const stopToRemove = mockStops[0]; await repository.removeStopIfExists(stopToRemove.id); - const remainingStops = await repository.getStops(systemId); + const remainingStops = await repository.getStops(); expect(remainingStops).toHaveLength(mockStops.length - 1); }); @@ -498,7 +498,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.removeStopIfExists("nonexistent-id"); - const remainingStops = await repository.getStops(systemId); + const remainingStops = await repository.getStops(); expect(remainingStops).toHaveLength(mockStops.length); }); }); @@ -580,7 +580,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearShuttleData(); - const result = await repository.getShuttles("sys1"); + const result = await repository.getShuttles(); expect(result).toEqual([]); }); }); @@ -594,7 +594,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearEtaData(); - const result = await repository.getEtas("shuttle1"); + const result = await repository.getEtasForShuttleId("shuttle1"); expect(result).toEqual([]); }); }); @@ -622,7 +622,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearRouteData(); - const result = await repository.getRoutes("sys1"); + const result = await repository.getRoutes(); expect(result).toEqual([]); }); }); @@ -636,7 +636,7 @@ describe("UnoptimizedInMemoryRepository", () => { await repository.clearStopData(); - const result = await repository.getStops("sys1"); + const result = await repository.getStops(); expect(result).toEqual([]); }); }); From 4f855a8225b69c0f8162345db2d1c9675b5304ab Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 19:18:30 -0700 Subject: [PATCH 69/71] update implementation of repository to get all entities --- src/repositories/UnoptimizedInMemoryShuttleRepository.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts index 42f3ecc..b8dda6f 100644 --- a/src/repositories/UnoptimizedInMemoryShuttleRepository.ts +++ b/src/repositories/UnoptimizedInMemoryShuttleRepository.ts @@ -16,7 +16,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter private subscribers: ((eta: IEta) => void)[] = []; public async getStops(): Promise { - return this.stops.filter(stop => stop.systemId === systemId); + return this.stops; } public async getStopById(stopId: string) { @@ -24,7 +24,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter } public async getRoutes(): Promise { - return this.routes.filter(route => route.systemId === systemId); + return this.routes; } public async getRouteById(routeId: string) { @@ -32,7 +32,7 @@ export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetter } public async getShuttles(): Promise { - return this.shuttles.filter(shuttle => shuttle.systemId === systemId); + return this.shuttles; } public async getShuttlesByRouteId(routeId: string) { From f0c754908d9813626aa28eee0b709c06146c44c5 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 19:19:10 -0700 Subject: [PATCH 70/71] update incorrect argument in shuttle resolver --- src/resolvers/ShuttleResolvers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolvers/ShuttleResolvers.ts b/src/resolvers/ShuttleResolvers.ts index bb5d0f0..103e40f 100644 --- a/src/resolvers/ShuttleResolvers.ts +++ b/src/resolvers/ShuttleResolvers.ts @@ -24,7 +24,7 @@ export const ShuttleResolvers: Resolvers = { const system = contextValue.findSystemById(parent.systemId); if (!system) return null; - const etasForShuttle = await system.shuttleRepository.getEtasForShuttleId(); + const etasForShuttle = await system.shuttleRepository.getEtasForShuttleId(parent.id); if (!etasForShuttle) return null; const computedEtas = await Promise.all(etasForShuttle.map(async ({ From c7666c092c1bdb64c6a81f05029433722d213c78 Mon Sep 17 00:00:00 2001 From: Brendan Chen Date: Mon, 7 Apr 2025 19:55:25 -0700 Subject: [PATCH 71/71] update remaining tests --- ...optimizedInMemoryShuttleRepositoryTests.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts index 835ef39..e1d9ba7 100644 --- a/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts +++ b/test/repositories/UnoptimizedInMemoryShuttleRepositoryTests.test.ts @@ -20,15 +20,15 @@ describe("UnoptimizedInMemoryRepository", () => { repository = new UnoptimizedInMemoryShuttleRepository(); }); - describe("getStopsBySystemId", () => { - test("gets stops by system ID", async () => { + describe("getStops", () => { + test("gets all stops in the repository", async () => { const mockStops = generateMockStops(); for (const stop of mockStops) { await repository.addOrUpdateStop(stop); } const result = await repository.getStops(); - expect(result).toEqual(mockStops.filter((stop) => stop.systemId === "sys1")); + expect(result).toEqual(mockStops); }); test("returns an empty list if there are no stops for the given system ID", async () => { @@ -53,7 +53,7 @@ describe("UnoptimizedInMemoryRepository", () => { }); }); - describe("getRoutesBySystemId", () => { + describe("getRoutes", () => { test("gets all routes for a specific system ID", async () => { const mockRoutes = generateMockRoutes(); for (const route of mockRoutes) { @@ -61,7 +61,7 @@ describe("UnoptimizedInMemoryRepository", () => { } const result = await repository.getRoutes(); - expect(result).toEqual(mockRoutes.filter((route) => route.systemId === "sys1")); + expect(result).toEqual(mockRoutes); }); test("returns an empty list if there are no routes for the system ID", async () => { @@ -85,7 +85,7 @@ describe("UnoptimizedInMemoryRepository", () => { expect(result).toBeNull(); }); }); - describe("getShuttlesBySystemId", () => { + describe("getShuttles", () => { test("gets all shuttles for a specific system ID", async () => { const mockShuttles = generateMockShuttles(); for (const shuttle of mockShuttles) { @@ -93,7 +93,7 @@ describe("UnoptimizedInMemoryRepository", () => { } const result = await repository.getShuttles(); - expect(result).toEqual(mockShuttles.filter((sh) => sh.systemId === "sys1")); + expect(result).toEqual(mockShuttles); }); test("returns an empty list if there are no shuttles for the system ID", async () => {