rename existing repository to shuttle repository

This commit is contained in:
2025-03-27 09:32:29 -07:00
parent 3a85f3da8b
commit fab99db755
15 changed files with 46 additions and 47 deletions

View File

@@ -1,7 +1,7 @@
import { ETANotificationScheduler } from "./notifications/schedulers/ETANotificationScheduler"; import { ETANotificationScheduler } from "./notifications/schedulers/ETANotificationScheduler";
import { GetterSetterRepository } from "./repositories/GetterSetterRepository"; import { ShuttleGetterSetterRepository } from "./repositories/ShuttleGetterSetterRepository";
export interface ServerContext { export interface ServerContext {
repository: GetterSetterRepository; repository: ShuttleGetterSetterRepository;
notificationService: ETANotificationScheduler; notificationService: ETANotificationScheduler;
} }

View File

@@ -3,7 +3,7 @@ import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone"; import { startStandaloneServer } from "@apollo/server/standalone";
import { MergedResolvers } from "./MergedResolvers"; import { MergedResolvers } from "./MergedResolvers";
import { ServerContext } from "./ServerContext"; import { ServerContext } from "./ServerContext";
import { UnoptimizedInMemoryRepository } from "./repositories/UnoptimizedInMemoryRepository"; import { UnoptimizedInMemoryShuttleRepository } from "./repositories/UnoptimizedInMemoryShuttleRepository";
import { TimedApiBasedRepositoryLoader } from "./loaders/TimedApiBasedRepositoryLoader"; import { TimedApiBasedRepositoryLoader } from "./loaders/TimedApiBasedRepositoryLoader";
import { ETANotificationScheduler } from "./notifications/schedulers/ETANotificationScheduler"; import { ETANotificationScheduler } from "./notifications/schedulers/ETANotificationScheduler";
import { loadTestData } from "./loaders/loadTestData"; import { loadTestData } from "./loaders/loadTestData";
@@ -18,7 +18,7 @@ async function main() {
introspection: process.env.NODE_ENV !== "production", introspection: process.env.NODE_ENV !== "production",
}); });
const repository = new UnoptimizedInMemoryRepository(); const repository = new UnoptimizedInMemoryShuttleRepository();
let notificationService: ETANotificationScheduler; let notificationService: ETANotificationScheduler;
if (process.argv.length > 2 && process.argv[2] == "integration-testing") { if (process.argv.length > 2 && process.argv[2] == "integration-testing") {
console.log("Using integration testing setup") console.log("Using integration testing setup")
@@ -37,7 +37,7 @@ async function main() {
listen: { listen: {
port: process.env.PORT ? parseInt(process.env.PORT) : 4000, port: process.env.PORT ? parseInt(process.env.PORT) : 4000,
}, },
context: async ({ req, res }) => { context: async () => {
return { return {
repository, repository,
notificationService, notificationService,

View File

@@ -1,4 +1,4 @@
import { GetterSetterRepository } from "../repositories/GetterSetterRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository";
import { IEntityWithId, IEta, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; import { IEntityWithId, IEta, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
import { RepositoryLoader } from "./RepositoryLoader"; import { RepositoryLoader } from "./RepositoryLoader";
@@ -19,7 +19,7 @@ export class ApiBasedRepositoryLoader implements RepositoryLoader {
baseUrl = "https://passiogo.com/mapGetData.php"; baseUrl = "https://passiogo.com/mapGetData.php";
constructor( constructor(
public repository: GetterSetterRepository, public repository: ShuttleGetterSetterRepository,
) { ) {
} }

View File

@@ -1,5 +1,4 @@
import { GetterSetterRepository } from "../repositories/GetterSetterRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository";
import { IEta, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
import { ApiBasedRepositoryLoader } from "./ApiBasedRepositoryLoader"; import { ApiBasedRepositoryLoader } from "./ApiBasedRepositoryLoader";
// Ideas to break this into smaller pieces in the future: // Ideas to break this into smaller pieces in the future:
@@ -23,7 +22,7 @@ export class TimedApiBasedRepositoryLoader extends ApiBasedRepositoryLoader {
readonly timeout = 10000; readonly timeout = 10000;
constructor( constructor(
repository: GetterSetterRepository, repository: ShuttleGetterSetterRepository,
) { ) {
super(repository); super(repository);
this.startFetchDataAndUpdate = this.startFetchDataAndUpdate.bind(this); this.startFetchDataAndUpdate = this.startFetchDataAndUpdate.bind(this);

View File

@@ -1,6 +1,6 @@
// Mock data // Mock data
import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
import { GetterSetterRepository } from "../repositories/GetterSetterRepository"; import { ShuttleGetterSetterRepository } from "../repositories/ShuttleGetterSetterRepository";
const systems: ISystem[] = [ const systems: ISystem[] = [
{ {
@@ -4454,7 +4454,7 @@ const etas: IEta[] = [
} }
]; ];
export async function loadTestData(repository: GetterSetterRepository) { export async function loadTestData(repository: ShuttleGetterSetterRepository) {
await Promise.all(systems.map(async (system) => { await Promise.all(systems.map(async (system) => {
await repository.addOrUpdateSystem(system); await repository.addOrUpdateSystem(system);
})); }));

View File

@@ -1,4 +1,4 @@
import { GetterRepository } from "../../repositories/GetterRepository"; import { ShuttleGetterRepository } from "../../repositories/ShuttleGetterRepository";
import { TupleKey } from "../../types/TupleKey"; import { TupleKey } from "../../types/TupleKey";
import { IEta } from "../../entities/entities"; import { IEta } from "../../entities/entities";
import { AppleNotificationSender, NotificationAlertArguments } from "../senders/AppleNotificationSender"; import { AppleNotificationSender, NotificationAlertArguments } from "../senders/AppleNotificationSender";
@@ -24,7 +24,7 @@ type DeviceIdSecondsThresholdAssociation = { [key: string]: number };
export class ETANotificationScheduler { export class ETANotificationScheduler {
public static readonly defaultSecondsThresholdForNotificationToFire = 180; public static readonly defaultSecondsThresholdForNotificationToFire = 180;
constructor(private repository: GetterRepository, constructor(private shuttleRepository: ShuttleGetterRepository,
private appleNotificationSender = new AppleNotificationSender() private appleNotificationSender = new AppleNotificationSender()
) { ) {
this.etaSubscriberCallback = this.etaSubscriberCallback.bind(this); this.etaSubscriberCallback = this.etaSubscriberCallback.bind(this);
@@ -50,9 +50,9 @@ export class ETANotificationScheduler {
private async sendEtaNotificationImmediately(notificationData: NotificationSchedulingArguments): Promise<boolean> { private async sendEtaNotificationImmediately(notificationData: NotificationSchedulingArguments): Promise<boolean> {
const { deviceId, shuttleId, stopId } = notificationData; const { deviceId, shuttleId, stopId } = notificationData;
const shuttle = await this.repository.getShuttleById(shuttleId); const shuttle = await this.shuttleRepository.getShuttleById(shuttleId);
const stop = await this.repository.getStopById(stopId); const stop = await this.shuttleRepository.getStopById(stopId);
const eta = await this.repository.getEtaForShuttleAndStopId(shuttleId, stopId); const eta = await this.shuttleRepository.getEtaForShuttleAndStopId(shuttleId, stopId);
if (!shuttle) { if (!shuttle) {
console.warn(`Notification ${notificationData} fell through; no associated shuttle`); console.warn(`Notification ${notificationData} fell through; no associated shuttle`);
return false; return false;
@@ -127,8 +127,8 @@ export class ETANotificationScheduler {
this.deviceIdsToDeliverTo[tuple.toString()][deviceId] = secondsThreshold; this.deviceIdsToDeliverTo[tuple.toString()][deviceId] = secondsThreshold;
this.repository.unsubscribeFromEtaUpdates(this.etaSubscriberCallback); this.shuttleRepository.unsubscribeFromEtaUpdates(this.etaSubscriberCallback);
this.repository.subscribeToEtaUpdates(this.etaSubscriberCallback); this.shuttleRepository.subscribeToEtaUpdates(this.etaSubscriberCallback);
} }
/** /**

View File

@@ -1,6 +1,6 @@
import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
export interface GetterRepository { export interface ShuttleGetterRepository {
getSystems(): Promise<ISystem[]>; getSystems(): Promise<ISystem[]>;
getSystemById(systemId: string): Promise<ISystem | null>; getSystemById(systemId: string): Promise<ISystem | null>;

View File

@@ -1,16 +1,16 @@
// If types match closely, we can use TypeScript "casting" // If types match closely, we can use TypeScript "casting"
// to convert from data repo to GraphQL schema // to convert from data repo to GraphQL schema
import { GetterRepository } from "./GetterRepository"; import { ShuttleGetterRepository } from "./ShuttleGetterRepository";
import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
/** /**
* GetterRepository interface for data derived from Passio API. * ShuttleGetterRepository interface for data derived from Passio API.
* The repository is not designed to have write locks in place. * The repository is not designed to have write locks in place.
* Objects passed from/to the repository should be treated * Objects passed from/to the repository should be treated
* as disposable. * as disposable.
*/ */
export interface GetterSetterRepository extends GetterRepository { export interface ShuttleGetterSetterRepository extends ShuttleGetterRepository {
// Setter methods // Setter methods
addOrUpdateSystem(system: ISystem): Promise<void>; addOrUpdateSystem(system: ISystem): Promise<void>;
addOrUpdateRoute(route: IRoute): Promise<void>; addOrUpdateRoute(route: IRoute): Promise<void>;

View File

@@ -1,4 +1,4 @@
import { GetterSetterRepository } from "./GetterSetterRepository"; import { ShuttleGetterSetterRepository } from "./ShuttleGetterSetterRepository";
import { IEntityWithId, IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities"; import { IEntityWithId, IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
/** /**
@@ -6,7 +6,7 @@ import { IEntityWithId, IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } f
* (I would optimize it with actual data structures, but I'm * (I would optimize it with actual data structures, but I'm
* switching to another data store later anyways) * switching to another data store later anyways)
*/ */
export class UnoptimizedInMemoryRepository implements GetterSetterRepository { export class UnoptimizedInMemoryShuttleRepository implements ShuttleGetterSetterRepository {
private systems: ISystem[] = []; private systems: ISystem[] = [];
private stops: IStop[] = []; private stops: IStop[] = [];
private routes: IRoute[] = []; private routes: IRoute[] = [];

View File

@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, jest, test } from "@jest/globals"; import { beforeEach, describe, expect, it, jest, test } from "@jest/globals";
import { ApiBasedRepositoryLoader, ApiResponseError } from "../../src/loaders/ApiBasedRepositoryLoader"; import { ApiBasedRepositoryLoader, ApiResponseError } from "../../src/loaders/ApiBasedRepositoryLoader";
import { UnoptimizedInMemoryRepository } from "../../src/repositories/UnoptimizedInMemoryRepository"; import { UnoptimizedInMemoryShuttleRepository } from "../../src/repositories/UnoptimizedInMemoryShuttleRepository";
import { fetchSystemDataSuccessfulResponse } from "../jsonSnapshots/fetchSystemData/fetchSystemDataSuccessfulResponse"; import { fetchSystemDataSuccessfulResponse } from "../jsonSnapshots/fetchSystemData/fetchSystemDataSuccessfulResponse";
import { fetchSystemDataFailedResponse } from "../jsonSnapshots/fetchSystemData/fetchSystemDataFailedResponse"; import { fetchSystemDataFailedResponse } from "../jsonSnapshots/fetchSystemData/fetchSystemDataFailedResponse";
import { fetchRouteDataSuccessfulResponse } from "../jsonSnapshots/fetchRouteData/fetchRouteDataSuccessfulResponse"; import { fetchRouteDataSuccessfulResponse } from "../jsonSnapshots/fetchRouteData/fetchRouteDataSuccessfulResponse";
@@ -26,7 +26,7 @@ describe("ApiBasedRepositoryLoader", () => {
let loader: ApiBasedRepositoryLoader; let loader: ApiBasedRepositoryLoader;
beforeEach(() => { beforeEach(() => {
loader = new ApiBasedRepositoryLoader(new UnoptimizedInMemoryRepository()); loader = new ApiBasedRepositoryLoader(new UnoptimizedInMemoryShuttleRepository());
resetGlobalFetchMockJson(); resetGlobalFetchMockJson();
}); });

View File

@@ -1,7 +1,7 @@
import { afterEach, beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals"; import { afterEach, beforeAll, beforeEach, describe, expect, it, jest } from "@jest/globals";
import { TimedApiBasedRepositoryLoader } from "../../src/loaders/TimedApiBasedRepositoryLoader"; import { TimedApiBasedRepositoryLoader } from "../../src/loaders/TimedApiBasedRepositoryLoader";
import { resetGlobalFetchMockJson } from "../testHelpers/fetchMockHelpers"; import { resetGlobalFetchMockJson } from "../testHelpers/fetchMockHelpers";
import { UnoptimizedInMemoryRepository } from "../../src/repositories/UnoptimizedInMemoryRepository"; import { UnoptimizedInMemoryShuttleRepository } from "../../src/repositories/UnoptimizedInMemoryShuttleRepository";
describe("TimedApiBasedRepositoryLoader", () => { describe("TimedApiBasedRepositoryLoader", () => {
let loader: TimedApiBasedRepositoryLoader; let loader: TimedApiBasedRepositoryLoader;
@@ -15,7 +15,7 @@ describe("TimedApiBasedRepositoryLoader", () => {
beforeEach(() => { beforeEach(() => {
resetGlobalFetchMockJson(); resetGlobalFetchMockJson();
loader = new TimedApiBasedRepositoryLoader(new UnoptimizedInMemoryRepository()); loader = new TimedApiBasedRepositoryLoader(new UnoptimizedInMemoryShuttleRepository());
spies = { spies = {
fetchAndUpdateSystemData: jest.spyOn(loader, 'fetchAndUpdateSystemData'), fetchAndUpdateSystemData: jest.spyOn(loader, 'fetchAndUpdateSystemData'),

View File

@@ -1,6 +1,6 @@
import { beforeEach, describe, expect, it, jest } from "@jest/globals"; import { beforeEach, describe, expect, it, jest } from "@jest/globals";
import { ETANotificationScheduler } from "../../../src/notifications/schedulers/ETANotificationScheduler"; import { ETANotificationScheduler } from "../../../src/notifications/schedulers/ETANotificationScheduler";
import { UnoptimizedInMemoryRepository } from "../../../src/repositories/UnoptimizedInMemoryRepository"; import { UnoptimizedInMemoryShuttleRepository } from "../../../src/repositories/UnoptimizedInMemoryShuttleRepository";
import http2 from "http2"; import http2 from "http2";
import { IEta, IShuttle, IStop } from "../../../src/entities/entities"; import { IEta, IShuttle, IStop } from "../../../src/entities/entities";
import { addMockShuttleToRepository, addMockStopToRepository } from "../../testHelpers/repositorySetupHelpers"; import { addMockShuttleToRepository, addMockStopToRepository } from "../../testHelpers/repositorySetupHelpers";
@@ -42,11 +42,11 @@ async function waitForMilliseconds(ms: number): Promise<void> {
describe("ETANotificationScheduler", () => { describe("ETANotificationScheduler", () => {
let repository: UnoptimizedInMemoryRepository let repository: UnoptimizedInMemoryShuttleRepository
let notificationService: ETANotificationScheduler; let notificationService: ETANotificationScheduler;
beforeEach(() => { beforeEach(() => {
repository = new UnoptimizedInMemoryRepository(); repository = new UnoptimizedInMemoryShuttleRepository();
mockNotificationSenderMethods(true); mockNotificationSenderMethods(true);

View File

@@ -1,5 +1,5 @@
import { beforeEach, describe, expect, jest, test } from "@jest/globals"; import { beforeEach, describe, expect, jest, test } from "@jest/globals";
import { UnoptimizedInMemoryRepository } from "../../src/repositories/UnoptimizedInMemoryRepository"; import { UnoptimizedInMemoryShuttleRepository } from "../../src/repositories/UnoptimizedInMemoryShuttleRepository";
import { import {
generateMockEtas, generateMockEtas,
generateMockOrderedStops, generateMockOrderedStops,
@@ -11,14 +11,14 @@ import {
// For repositories created in the future, reuse core testing // For repositories created in the future, reuse core testing
// logic from here and differentiate setup (e.g. creating mocks) // logic from here and differentiate setup (e.g. creating mocks)
// Do this by creating a function which takes a GetterRepository // Do this by creating a function which takes a ShuttleGetterRepository
// or GetterSetterRepository instance // or ShuttleGetterSetterRepository instance
describe("UnoptimizedInMemoryRepository", () => { describe("UnoptimizedInMemoryRepository", () => {
let repository: UnoptimizedInMemoryRepository; let repository: UnoptimizedInMemoryShuttleRepository;
beforeEach(() => { beforeEach(() => {
repository = new UnoptimizedInMemoryRepository(); repository = new UnoptimizedInMemoryShuttleRepository();
}); });
describe("getSystems", () => { describe("getSystems", () => {

View File

@@ -1,7 +1,7 @@
import { readFileSync } from "fs"; import { readFileSync } from "fs";
import { ApolloServer } from "@apollo/server"; import { ApolloServer } from "@apollo/server";
import { MergedResolvers } from "../../src/MergedResolvers"; import { MergedResolvers } from "../../src/MergedResolvers";
import { UnoptimizedInMemoryRepository } from "../../src/repositories/UnoptimizedInMemoryRepository"; import { UnoptimizedInMemoryShuttleRepository } from "../../src/repositories/UnoptimizedInMemoryShuttleRepository";
import { beforeEach } from "@jest/globals"; import { beforeEach } from "@jest/globals";
import { ServerContext } from "../../src/ServerContext"; import { ServerContext } from "../../src/ServerContext";
import { ETANotificationScheduler } from "../../src/notifications/schedulers/ETANotificationScheduler"; import { ETANotificationScheduler } from "../../src/notifications/schedulers/ETANotificationScheduler";
@@ -25,7 +25,7 @@ export function setupTestServerContext() {
const context: { [key: string] : any } = {}; const context: { [key: string] : any } = {};
beforeEach(() => { beforeEach(() => {
context.repository = new UnoptimizedInMemoryRepository(); context.repository = new UnoptimizedInMemoryShuttleRepository();
context.notificationService = new ETANotificationScheduler(context.repository); context.notificationService = new ETANotificationScheduler(context.repository);
}); });

View File

@@ -5,9 +5,9 @@ import {
generateMockStops, generateMockStops,
generateMockSystems generateMockSystems
} from "./mockDataGenerators"; } from "./mockDataGenerators";
import { GetterSetterRepository } from "../../src/repositories/GetterSetterRepository"; import { ShuttleGetterSetterRepository } from "../../src/repositories/ShuttleGetterSetterRepository";
export async function addMockSystemToRepository(repository: GetterSetterRepository) { export async function addMockSystemToRepository(repository: ShuttleGetterSetterRepository) {
const mockSystems = generateMockSystems(); const mockSystems = generateMockSystems();
const mockSystem = mockSystems[0]; const mockSystem = mockSystems[0];
mockSystem.id = "1"; mockSystem.id = "1";
@@ -16,7 +16,7 @@ export async function addMockSystemToRepository(repository: GetterSetterReposito
return mockSystem; return mockSystem;
} }
export async function addMockRouteToRepository(repository: GetterSetterRepository, systemId: string) { export async function addMockRouteToRepository(repository: ShuttleGetterSetterRepository, systemId: string) {
const mockRoutes = generateMockRoutes(); const mockRoutes = generateMockRoutes();
const mockRoute = mockRoutes[0]; const mockRoute = mockRoutes[0];
mockRoute.systemId = systemId; mockRoute.systemId = systemId;
@@ -25,7 +25,7 @@ export async function addMockRouteToRepository(repository: GetterSetterRepositor
return mockRoute; return mockRoute;
} }
export async function addMockStopToRepository(repository: GetterSetterRepository, systemId: string) { export async function addMockStopToRepository(repository: ShuttleGetterSetterRepository, systemId: string) {
const mockStops = generateMockStops(); const mockStops = generateMockStops();
const mockStop = mockStops[0]; const mockStop = mockStops[0];
mockStop.systemId = systemId; mockStop.systemId = systemId;
@@ -34,7 +34,7 @@ export async function addMockStopToRepository(repository: GetterSetterRepository
return mockStop; return mockStop;
} }
export async function addMockShuttleToRepository(repository: GetterSetterRepository, systemId: string) { export async function addMockShuttleToRepository(repository: ShuttleGetterSetterRepository, systemId: string) {
const mockShuttles = generateMockShuttles(); const mockShuttles = generateMockShuttles();
const mockShuttle = mockShuttles[0]; const mockShuttle = mockShuttles[0];
mockShuttle.systemId = systemId; mockShuttle.systemId = systemId;
@@ -42,7 +42,7 @@ export async function addMockShuttleToRepository(repository: GetterSetterReposit
return mockShuttle; return mockShuttle;
} }
export async function addMockEtaToRepository(repository: GetterSetterRepository, stopId: string, shuttleId: string) { export async function addMockEtaToRepository(repository: ShuttleGetterSetterRepository, stopId: string, shuttleId: string) {
const etas = generateMockEtas(); const etas = generateMockEtas();
const expectedEta = etas[0]; const expectedEta = etas[0];
expectedEta.stopId = stopId; expectedEta.stopId = stopId;