From a7a7abd90155687a1e7d165540422b1fc1e81b89 Mon Sep 17 00:00:00 2001 From: Pagwin Date: Thu, 24 Apr 2025 16:32:53 -0400 Subject: [PATCH] code for adding edges added in but not quite done to avoid duplicate edge creation yet and completely untested --- src/server/graph.ts | 87 +++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 81 insertions(+), 6 deletions(-) diff --git a/src/server/graph.ts b/src/server/graph.ts index 066ae5e..f07f73e 100644 --- a/src/server/graph.ts +++ b/src/server/graph.ts @@ -20,6 +20,13 @@ interface GTFSStop { stop_url?: string; [key: string]: string | undefined; // Allow for additional fields } +interface GTFSStopTime { + trip_id: string; + arrival_time: string; + departure_time: string; + stop_id: string; + stop_sequence: number; +} /** * Sets up a Neo4j graph database with location nodes from JSON and GTFS stop data @@ -31,6 +38,7 @@ export async function graph_setup( driver: Neo4j.Driver, OCCT_stops_json: string = "./data/OCCT/stops.json", BCT_GTFS_stops_txt: string = "./data/BCT/stops.txt", + BCT_GTFS_stops_times_txt: string = "./data/BCT/stop_times.txt", ): Promise { const session = driver.session(); @@ -45,6 +53,10 @@ export async function graph_setup( await stops_gtfs_node_import(session, BCT_stops, { provider: "BCT" }); + const BCTStopTimesData = await Deno.readTextFile(BCT_GTFS_stops_times_txt); + const BCT_stop_times = await parse_gtfs_stop_times(BCTStopTimesData); + await gtfs_edge_import(session, BCT_stop_times); + await session.close(); } @@ -102,23 +114,20 @@ async function stops_gtfs_node_import( s.name = $name, s.latitude = $lat, s.longitude = $lng, - s.locationType = $locationType, - s.parentStation = $parentStation, - s.zoneId = $zoneId, s.url = $url, + s.originalId = $originalId, s.source = '${provider}' ON MATCH SET s.name = $name, s.latitude = $lat, s.longitude = $lng, - s.locationType = $locationType, - s.parentStation = $parentStation, - s.zoneId = $zoneId, s.url = $url, + s.originalId = $originalId, s.source = '${provider}' `, { id: `${provider}_` + stop.stop_id, + originalId: stop.stop_id, name: stop.stop_name, lat: parseFloat(stop.stop_lat), lng: parseFloat(stop.stop_lon), @@ -172,3 +181,69 @@ async function parse_gtfs_stops(txt: string): Promise { return validStops; } + +async function parse_gtfs_stop_times( + fileContents: string, +): Promise { + const records = await parseCSV(fileContents, { + skipFirstRow: true, + columns: true, + }); + + const stopTimes: GTFSStopTime[] = []; + + for (const row of records as Record[]) { + stopTimes.push({ + trip_id: row.trip_id, + arrival_time: row.arrival_time, + departure_time: row.departure_time, + stop_id: row.stop_id, + stop_sequence: parseInt(row.stop_sequence, 10), + }); + } + + return stopTimes; +} + +async function gtfs_edge_import( + session: neo4j.Session, + stop_times: GTFSStopTime[], +): Promise { + const groupedByTrip = new Map(); + + // Group by trip_id + for (const stopTime of stop_times) { + if (!groupedByTrip.has(stopTime.trip_id)) { + groupedByTrip.set(stopTime.trip_id, []); + } + groupedByTrip.get(stopTime.trip_id)!.push(stopTime); + } + + for (const [tripId, stops] of groupedByTrip.entries()) { + // Sort by stop_sequence + stops.sort((a, b) => a.stop_sequence - b.stop_sequence); + + for (let i = 0; i < stops.length - 1; i++) { + const from = stops[i]; + const to = stops[i + 1]; + + await session.run( + ` + MATCH (from:TransportNode {originalId: $fromId}), (to:TransportNode {originalId: $toId}) + MERGE (from)-[:DEPARTS_TO { + tripId: $tripId, + departureTime: $departureTime, + arrivalTime: $arrivalTime + }]->(to) + `, + { + fromId: from.stop_id, + toId: to.stop_id, + tripId, + departureTime: from.departure_time, + arrivalTime: to.arrival_time, + }, + ); + } + } +}