restructure parking and shuttle repository loaders

This commit is contained in:
2025-04-11 17:13:39 -07:00
parent 0e3c12bebc
commit c9aa2c401f
11 changed files with 21 additions and 21 deletions

View File

@@ -0,0 +1,83 @@
import { ParkingRepositoryLoader } from "./ParkingRepositoryLoader";
import { ParkingGetterSetterRepository } from "../../repositories/ParkingGetterSetterRepository";
import { createHash } from "node:crypto";
import { ApiResponseError } from "../ApiResponseError";
import { IParkingStructure } from "../../entities/ParkingRepositoryEntities";
class ApiParseError extends Error {
constructor(message: string) {
super(message);
this.name = "ApiParseError";
}
}
export class ChapmanApiBasedParkingRepositoryLoader implements ParkingRepositoryLoader {
public static readonly id = "chapman-parking-loader";
private readonly fetchUrl = "https://webfarm.chapman.edu/ParkingService/ParkingService/counts";
constructor(
public repository: ParkingGetterSetterRepository
) {
this.fetchAndUpdateParkingStructures = this.fetchAndUpdateParkingStructures.bind(this);
}
async fetchAndUpdateAll() {
await this.fetchAndUpdateParkingStructures();
}
async fetchAndUpdateParkingStructures(): Promise<void> {
let json: any;
try {
const response = await fetch(this.fetchUrl);
json = await response.json();
} catch(e: any) {
throw new ApiResponseError(e.message);
}
try {
if (typeof json.Structures === "object") {
const parkingStructures: IParkingStructure[] = json.Structures.map(this.constructIParkingStructureFromJson);
await Promise.all(parkingStructures.map(async (structure: IParkingStructure) => {
await this.repository.addOrUpdateParkingStructure(structure);
}));
}
} catch(e: any) {
throw new ApiParseError(e.message);
}
}
private constructIParkingStructureFromJson(jsonStructure: any) {
const structureToReturn: IParkingStructure = {
capacity: jsonStructure.Capacity,
coordinates: {
latitude: jsonStructure.Latitude,
longitude: jsonStructure.Longitude,
},
id: ChapmanApiBasedParkingRepositoryLoader.generateId(jsonStructure.Address),
name: jsonStructure.Name,
spotsAvailable: jsonStructure.CurrentCount,
address: jsonStructure.Address
}
return structureToReturn;
}
private static normalizeAddress(address: string): string {
return address
.toLowerCase()
.split(/\s+/)
.filter(part => part.length > 0)
.join(' ');
}
public static generateId(address: string): string {
const normalized = this.normalizeAddress(address);
const hash = createHash('sha256')
.update(normalized)
.digest('hex');
return hash.substring(0, 32);
}
}

View File

@@ -0,0 +1,5 @@
import { RepositoryLoader } from "../RepositoryLoader";
export interface ParkingRepositoryLoader extends RepositoryLoader {
fetchAndUpdateParkingStructures(): Promise<void>;
}

View File

@@ -0,0 +1,15 @@
import { ParkingGetterSetterRepository } from "../../repositories/ParkingGetterSetterRepository";
import { ChapmanApiBasedParkingRepositoryLoader } from "./ChapmanApiBasedParkingRepositoryLoader";
interface ParkingRepositoryBuilderArguments {
id: string;
repository: ParkingGetterSetterRepository;
}
export function buildParkingRepositoryLoaderIfExists(args: ParkingRepositoryBuilderArguments) {
if (args.id === ChapmanApiBasedParkingRepositoryLoader.id) {
return new ChapmanApiBasedParkingRepositoryLoader(args.repository);
}
return null;
}