remove ApiBasedRepository.ts and tests

This commit is contained in:
2025-01-21 13:26:52 -08:00
parent 17e1ef2945
commit 26d82390c6
4 changed files with 0 additions and 821 deletions

View File

@@ -2,5 +2,4 @@ import { GetterRepository } from "./repositories/GetterRepository";
export interface ServerContext {
repository: GetterRepository;
apiBasedRepository: GetterRepository;
}

View File

@@ -2,11 +2,9 @@ import { readFileSync } from "fs";
import { ApolloServer } from "@apollo/server";
import { startStandaloneServer } from "@apollo/server/standalone";
import { resolvers } from "./resolvers";
import { loadTestData } from "./loaders/loadTestData";
import { ServerContext } from "./ServerContext";
import { UnoptimizedInMemoryRepository } from "./repositories/UnoptimizedInMemoryRepository";
import { RepositoryDataLoader } from "./loaders/RepositoryDataLoader";
import { ApiBasedRepository } from "./repositories/ApiBasedRepository";
const typeDefs = readFileSync("./schema.graphqls", "utf8");
@@ -25,14 +23,6 @@ async function main() {
);
await repositoryDataUpdater.start();
// TODO: Migrate all logic over to this repository
const apiBasedRepository = new ApiBasedRepository();
const systemIds = ["263"];
await Promise.all(systemIds.map(async (systemId) => {
await apiBasedRepository.seedCacheForSystemId(systemId);
}));
const { url } = await startStandaloneServer(server, {
listen: {
port: process.env.PORT ? parseInt(process.env.PORT) : 4000,
@@ -40,7 +30,6 @@ async function main() {
context: async ({ req, res }) => {
return {
repository,
apiBasedRepository,
}
},
});

View File

@@ -1,387 +0,0 @@
import { GetterRepository } from "./GetterRepository";
import { IEta, IOrderedStop, IRoute, IShuttle, IStop, ISystem } from "../entities/entities";
const baseUrl = "https://passiogo.com/mapGetData.php"
// TODO: implement TTL functionality
// TODO: add TTL values to everything
// TODO: remove RepositoryDataLoader and UnoptimizedInMemoryRepository
// TODO: make milliseconds (TTL) required on everything
// TODO: extract cache into its own class
export interface ApiBasedRepositoryCache {
etasForShuttleId?: {
[shuttleId: string]: IEta[],
},
etasForStopId?: {
[stopId: string]: IEta[],
},
stopsBySystemId?: {
[systemId: string]: IStop[],
},
stopByStopId?: {
[stopId: string]: IStop,
},
shuttleByShuttleId?: {
[shuttleId: string]: IShuttle,
},
shuttlesBySystemId?: {
[systemId: string]: IShuttle[],
},
// To speed things up, implement caches for other data later
}
export interface ApiBasedRepositoryMillisecondTTLs {
etasForShuttleId?: number,
etasForStopId?: number,
shuttleByShuttleId?: number,
shuttlesBySystemId?: number,
}
const emptyCache: ApiBasedRepositoryCache = {
etasForShuttleId: {},
etasForStopId: {},
shuttleByShuttleId: {},
shuttlesBySystemId: {},
}
const defaultTtls: ApiBasedRepositoryMillisecondTTLs = {
etasForShuttleId: 10000,
etasForStopId: 10000,
}
export class ApiBasedRepository implements GetterRepository {
private cache: ApiBasedRepositoryCache;
constructor(
initialCache: ApiBasedRepositoryCache | undefined = emptyCache,
private ttls: ApiBasedRepositoryMillisecondTTLs = defaultTtls,
) {
this.cache = initialCache;
}
/**
* Seed the initial data in the cache, so data can be updated
* given the correct ID.
* Alternatively, pass in an `initialCache` with existing data
* (useful for testing).
* @param systemId
*/
public async seedCacheForSystemId(systemId: string): Promise<void> {
await this.updateShuttlesForSystemIfTTL(systemId);
await this.updateEtasForSystemIfTTL(systemId);
await this.updateStopsForSystemIdIfTTL(systemId);
}
public async getEtaForShuttleAndStopId(shuttleId: string, stopId: string): Promise<IEta | null> {
const shuttle = await this.getShuttleById(shuttleId);
const systemId = shuttle?.systemId;
if (!systemId) {
return null;
}
await this.updateEtasForSystemIfTTL(systemId);
if (this.cache?.etasForStopId && this.cache.etasForStopId[stopId]) {
const etas = this.cache.etasForStopId[stopId];
const foundEta = etas.find((eta) => eta.shuttleId === shuttleId);
if (foundEta) {
return foundEta;
}
}
return null;
}
public async getEtasForShuttleId(shuttleId: string): Promise<IEta[]> {
const shuttle = await this.getShuttleById(shuttleId);
const systemId = shuttle?.systemId;
if (!systemId) {
return [];
}
await this.updateEtasForSystemIfTTL(systemId);
if (!this.cache?.etasForShuttleId || !this.cache.etasForShuttleId[shuttleId]) {
return [];
}
return this.cache.etasForShuttleId[shuttleId];
}
public async getEtasForStopId(stopId: string): Promise<IEta[]> {
const stop = await this.getStopById(stopId);
const systemId = stop?.systemId;
if (!systemId) {
return [];
}
await this.updateEtasForSystemIfTTL(systemId);
if (!this.cache?.etasForStopId || !this.cache.etasForStopId[stopId]) {
return [];
}
return this.cache.etasForStopId[stopId];
}
public async updateEtasForSystemIfTTL(systemId: string) {
// TODO: check if TTL
try {
const stops = await this.getStopsBySystemId(systemId);
await Promise.all(stops.map(async (stop) => {
const params = {
eta: "3",
stopIds: stop.id,
};
const query = new URLSearchParams(params).toString();
const response = await fetch(`${baseUrl}?${query}`, {
method: "GET",
});
const json = await response.json();
if (json.ETAs && json.ETAs[stop.id]) {
if (!this.cache.etasForStopId) {
this.cache.etasForStopId = {};
}
this.cache.etasForStopId[stop.id] = [];
// This is technically incorrect, the entire shuttle cache
// should not be reset like this
// TODO: restore normal cache behavior
this.cache.etasForShuttleId = {};
// Continue with the parsing
json.ETAs[stop.id].forEach((jsonEta: any) => {
// Update cache
if (!this.cache.etasForStopId) {
this.cache.etasForStopId = {};
}
if (!this.cache.etasForShuttleId) {
this.cache.etasForShuttleId = {};
}
// TODO: create cache abstraction to deal with possibly undefined properties
const shuttleId: string = jsonEta.busId;
if (!this.cache.etasForShuttleId[shuttleId]) {
this.cache.etasForShuttleId[shuttleId] = [];
}
const eta: IEta = {
secondsRemaining: jsonEta.secondsSpent,
shuttleId: `${shuttleId}`,
stopId: stop.id,
millisecondsSinceEpoch: Date.now(),
};
this.cache.etasForStopId[stop.id].push(eta);
this.cache.etasForShuttleId[shuttleId].push(eta);
});
}
}));
} catch (e) {
console.error(e);
}
}
// TODO: migrate rest of logic over to this class
public async getOrderedStopByRouteAndStopId(routeId: string, stopId: string): Promise<| null> {
return null;
}
public async getOrderedStopsByRouteId(routeId: string): Promise<[]> {
return Promise.resolve([]);
}
public async getOrderedStopsByStopId(stopId: string): Promise<[]> {
return Promise.resolve([]);
}
public async getRouteById(routeId: string): Promise<| null> {
return Promise.resolve(null);
}
public async getRoutesBySystemId(systemId: string): Promise<[]> {
return Promise.resolve([]);
}
public async getShuttleById(shuttleId: string): Promise<IShuttle | null> {
if (!this.cache.shuttleByShuttleId) return null;
let shuttle = this.cache.shuttleByShuttleId[shuttleId];
if (!shuttle) return null;
// Call getShuttlesBySystemId to update the data if not TTL
await this.updateShuttlesForSystemIfTTL(shuttle.systemId);
shuttle = this.cache.shuttleByShuttleId[shuttleId];
if (!shuttle) return null;
return shuttle;
}
public async getShuttlesByRouteId(routeId: string): Promise<[]> {
return Promise.resolve([]);
}
public async getShuttlesBySystemId(systemId: string): Promise<IShuttle[]> {
return Promise.resolve([]);
}
public async updateShuttlesForSystemIfTTL(systemId: string) {
// TODO: check if TTL
try {
// TODO: update shuttlesByRouteId
// Update shuttleByShuttleId, shuttlesBySystemId
const params = {
getBuses: "2"
};
const formDataJsonObject = {
"s0": systemId,
"sA": "1"
};
const formData = new FormData();
formData.set("json", JSON.stringify(formDataJsonObject));
const query = new URLSearchParams(params).toString();
const response = await fetch(`${baseUrl}?${query}`, {
method: "POST",
body: formData,
});
const json = await response.json();
if (json.buses && json.buses["-1"] === undefined) {
const jsonBuses = Object.values(json.buses).map((busesArr: any) => {
return busesArr[0];
});
// Store shuttles by system, with the additional side effect that
// shuttleByShuttleId is updated
const shuttles = await Promise.all(jsonBuses.map(async (jsonBus: any) => {
const constructedShuttle: IShuttle = {
name: jsonBus.bus,
coordinates: {
latitude: parseFloat(jsonBus.latitude),
longitude: parseFloat(jsonBus.longitude),
},
routeId: jsonBus.routeId,
systemId: systemId,
id: `${jsonBus.busId}`
}
if (this.cache.shuttleByShuttleId) {
this.cache.shuttleByShuttleId[jsonBus.busId] = constructedShuttle;
}
return constructedShuttle;
}));
if (this.cache.shuttlesBySystemId) {
this.cache.shuttlesBySystemId[systemId] = shuttles;
}
} else {
console.warn(`No shuttle data available for system ID ${systemId} and JSON output
${json}`);
}
} catch (e) {
console.error(e);
}
}
public async getStopById(stopId: string): Promise<IStop | null> {
if (!this.cache.stopByStopId) return null;
const oldStop = this.cache.stopByStopId[stopId];
if (!oldStop) return null;
await this.updateStopsForSystemIdIfTTL(oldStop.systemId);
const newStop = this.cache.stopByStopId[stopId];
if (!newStop) return null;
return newStop;
}
public async getStopsBySystemId(systemId: string): Promise<IStop[]> {
await this.updateStopsForSystemIdIfTTL(systemId);
if (!this.cache.stopsBySystemId || !this.cache.stopsBySystemId[systemId]) {
return [];
}
return this.cache.stopsBySystemId[systemId];
}
public async updateStopsForSystemIdIfTTL(systemId: string) {
// TODO: check if TTL
try {
const params = {
getStops: "2",
};
const formDataJsonObject = {
"s0": systemId,
"sA": 1
};
const formData = new FormData();
formData.set("json", JSON.stringify(formDataJsonObject));
const query = new URLSearchParams(params).toString();
const response = await fetch(`${baseUrl}?${query}`, {
method: "POST",
body: formData,
});
const json = await response.json();
// TODO: update polyline data
// TODO: update ordered stop data
if (json.stops) {
const jsonStops = Object.values(json.stops);
// TODO: restore normal cache behavior
this.cache.stopsBySystemId = {};
this.cache.stopByStopId = {};
await Promise.all(jsonStops.map(async (stop: any) => {
const constructedStop: IStop = {
name: stop.name,
id: stop.id,
systemId: systemId,
coordinates: {
latitude: parseFloat(stop.latitude),
longitude: parseFloat(stop.longitude),
},
};
if (!this.cache.stopsBySystemId) {
this.cache.stopsBySystemId = {};
}
if (!this.cache.stopsBySystemId[systemId]) {
this.cache.stopsBySystemId[systemId] = [];
}
this.cache.stopsBySystemId[systemId].push(constructedStop);
if (!this.cache.stopByStopId) {
this.cache.stopByStopId = {};
}
this.cache.stopByStopId[constructedStop.id] = constructedStop;
}));
}
} catch (e) {
console.error(e);
}
}
public async getSystemById(systemId: string): Promise<ISystem| null> {
return null;
}
public async getSystems(): Promise<[]> {
return Promise.resolve([]);
}
}