@transportme/load-ptv-gtfs 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.mjs +26 -0
- package/lib/loader/RouteLoader.mjs +34 -17
- package/lib/loader/ShapeLoader.mjs +6 -0
- package/lib/loader/StopsLoader.mjs +9 -1
- package/lib/loader/TripLoader.mjs +53 -26
- package/package.json +2 -2
package/index.mjs
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import RouteLoader from './lib/loader/RouteLoader.mjs'
|
|
2
|
+
import ShapeLoader from './lib/loader/ShapeLoader.mjs'
|
|
3
|
+
import StopsLoader from './lib/loader/StopsLoader.mjs'
|
|
4
|
+
import TripLoader from './lib/loader/TripLoader.mjs'
|
|
5
|
+
|
|
6
|
+
import GTFSAgency from './lib/gtfs-parser/GTFSAgency.mjs'
|
|
7
|
+
import GTFSCalendar from './lib/gtfs-parser/GTFSCalendar.mjs'
|
|
8
|
+
import GTFSCalendarDate from './lib/gtfs-parser/GTFSCalendarDate.mjs'
|
|
9
|
+
import GTFSRoute from './lib/gtfs-parser/GTFSRoute.mjs'
|
|
10
|
+
import { GTFSShape, GTFSShapePoint } from './lib/gtfs-parser/GTFSShape.mjs'
|
|
11
|
+
import { GTFSStop, GTFSPlatformStop } from './lib/gtfs-parser/GTFSStop.mjs'
|
|
12
|
+
import { GTFSStopTime } from './lib/gtfs-parser/GTFSStopTime.mjs'
|
|
13
|
+
import GTFSTrip from './lib/gtfs-parser/GTFSTrip.mjs'
|
|
14
|
+
|
|
15
|
+
const GTFSTypes = {
|
|
16
|
+
GTFSAgency, GTFSCalendar, GTFSCalendarDate,
|
|
17
|
+
GTFSRoute, GTFSShape, GTFSShapePoint,
|
|
18
|
+
GTFSStop, GTFSPlatformStop,
|
|
19
|
+
GTFSStopTime, GTFSTrip
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
RouteLoader, ShapeLoader,
|
|
24
|
+
StopsLoader, TripLoader,
|
|
25
|
+
GTFSTypes
|
|
26
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import GTFSRouteReader from '../gtfs-parser/readers/GTFSRouteReader.mjs'
|
|
2
2
|
import GTFSAgencyReader from '../gtfs-parser/readers/GTFSAgencyReader.mjs'
|
|
3
3
|
import { STOP_UTILS } from '@transportme/transportvic-utils'
|
|
4
|
+
import GTFSRoute from '../gtfs-parser/GTFSRoute.mjs'
|
|
4
5
|
|
|
5
6
|
const { sanitiseName } = STOP_UTILS
|
|
6
7
|
|
|
@@ -14,6 +15,13 @@ export default class RouteLoader {
|
|
|
14
15
|
|
|
15
16
|
#routeIDMap = {}
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new Shape Loader.
|
|
20
|
+
*
|
|
21
|
+
* @param {string} routesFile The path for the routes.txt file
|
|
22
|
+
* @param {string} agencyFile The path for the agency.txt file
|
|
23
|
+
* @param {DatabaseConnection} database A database connection
|
|
24
|
+
*/
|
|
17
25
|
constructor(routesFile, agencyFile, mode, database) {
|
|
18
26
|
this.#routes = database.getCollection('routes')
|
|
19
27
|
this.#mode = mode
|
|
@@ -61,33 +69,42 @@ export default class RouteLoader {
|
|
|
61
69
|
}, matchingRoute)
|
|
62
70
|
}
|
|
63
71
|
|
|
72
|
+
/**
|
|
73
|
+
* Loads a route into the database
|
|
74
|
+
*
|
|
75
|
+
* @param {GTFSRoute} route The route being added
|
|
76
|
+
* @param {function} [processRoute] Used to modify the route data. Should return null to drop the route
|
|
77
|
+
*/
|
|
78
|
+
async loadRoute(route, processRoute) {
|
|
79
|
+
let originalRouteID = route.originalRouteGTFSID
|
|
80
|
+
let routeData = this.generateDBRouteData(route)
|
|
81
|
+
let processedData = processRoute ? await processRoute(routeData) : routeData
|
|
82
|
+
if (!processedData) return
|
|
83
|
+
|
|
84
|
+
this.#routeIDMap[originalRouteID] = processedData.routeGTFSID
|
|
85
|
+
|
|
86
|
+
let matchingRoute = await this.findMatchingRoute(processedData)
|
|
87
|
+
|
|
88
|
+
if (matchingRoute) {
|
|
89
|
+
await this.mergeRoutes(matchingRoute, processedData)
|
|
90
|
+
} else {
|
|
91
|
+
await this.#routes.createDocument(processedData)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
64
95
|
/**
|
|
65
96
|
* Loads the route data into the database.
|
|
66
97
|
*
|
|
67
98
|
* @param {Object} options An optional parameter to allow for custom route processing
|
|
68
|
-
* @param {function} options.processRoute A function to modify the route data. If a route should be dropped, it should return null.
|
|
99
|
+
* @param {function} [options.processRoute] A function to modify the route data. If a route should be dropped, it should return null.
|
|
69
100
|
*/
|
|
70
|
-
async loadRoutes({ processRoute } = {
|
|
101
|
+
async loadRoutes({ processRoute } = {}) {
|
|
71
102
|
await this.loadAgencies()
|
|
72
103
|
|
|
73
104
|
await this.#routesReader.open()
|
|
74
105
|
while (this.#routesReader.available()) {
|
|
75
106
|
let route = await this.#routesReader.getNextEntity()
|
|
76
|
-
|
|
77
|
-
let originalRouteID = route.originalRouteGTFSID
|
|
78
|
-
let routeData = this.generateDBRouteData(route)
|
|
79
|
-
let processedData = await processRoute(routeData)
|
|
80
|
-
if (!processedData) continue
|
|
81
|
-
|
|
82
|
-
this.#routeIDMap[originalRouteID] = processedData.routeGTFSID
|
|
83
|
-
|
|
84
|
-
let matchingRoute = await this.findMatchingRoute(processedData)
|
|
85
|
-
|
|
86
|
-
if (matchingRoute) {
|
|
87
|
-
await this.mergeRoutes(matchingRoute, processedData)
|
|
88
|
-
} else {
|
|
89
|
-
await this.#routes.createDocument(processedData)
|
|
90
|
-
}
|
|
107
|
+
await this.loadRoute(route, processRoute)
|
|
91
108
|
}
|
|
92
109
|
}
|
|
93
110
|
|
|
@@ -8,6 +8,12 @@ export default class ShapeLoader {
|
|
|
8
8
|
|
|
9
9
|
#routeCache = {}
|
|
10
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Creates a new Shape Loader.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} shapeFile The path for the shapes.txt file
|
|
15
|
+
* @param {DatabaseConnection} database A database connection
|
|
16
|
+
*/
|
|
11
17
|
constructor(shapeFile, database) {
|
|
12
18
|
this.#routes = database.getCollection('routes')
|
|
13
19
|
this.#shapeReader = new GTFSShapeReader(shapeFile)
|
|
@@ -10,6 +10,14 @@ export default class StopsLoader {
|
|
|
10
10
|
#mode
|
|
11
11
|
#stopsReader
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Creates a new Stop Loader.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} stopsFile The path for the stops.txt file
|
|
17
|
+
* @param {FeatureCollection} suburbs A GeoJSON FeatureCollection containing a list of all suburbs located within Victoria
|
|
18
|
+
* @param {string} mode The transit mode being loaded
|
|
19
|
+
* @param {DatabaseConnection} database A database connection
|
|
20
|
+
*/
|
|
13
21
|
constructor(stopsFile, suburbs, mode, database) {
|
|
14
22
|
this.#stops = database.getCollection('stops')
|
|
15
23
|
this.#mode = mode
|
|
@@ -106,7 +114,7 @@ export default class StopsLoader {
|
|
|
106
114
|
* @param {function} options.processStop Used to process as stop's data.
|
|
107
115
|
* @param {function} options.getMergeName Used to get a stop's merge name. Return null to use the default merge name.
|
|
108
116
|
*/
|
|
109
|
-
async loadStop(stop, {processStop, getMergeName} = {}) {
|
|
117
|
+
async loadStop(stop, { processStop, getMergeName } = {}) {
|
|
110
118
|
let processedData = processStop ? processStop(stop) : stop
|
|
111
119
|
|
|
112
120
|
let defaultMergeName = this.getMergeName(processedData)
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import DatabaseConnection from '@transportme/database/lib/DatabaseConnection.mjs'
|
|
1
2
|
import GTFSCalendarReader from '../gtfs-parser/readers/GTFSCalendarReader.mjs'
|
|
2
3
|
import GTFSStopTimesReader from '../gtfs-parser/readers/GTFSStopTimesReader.mjs'
|
|
3
4
|
import GTFSTripReader from '../gtfs-parser/readers/GTFSTripReader.mjs'
|
|
4
5
|
import async from 'async'
|
|
6
|
+
import { GTFSStopTime } from '../gtfs-parser/GTFSStopTime.mjs'
|
|
5
7
|
|
|
6
8
|
export default class TripLoader {
|
|
7
9
|
|
|
@@ -25,6 +27,19 @@ export default class TripLoader {
|
|
|
25
27
|
|
|
26
28
|
#shapeIDMap = {}
|
|
27
29
|
|
|
30
|
+
#tripsToLoad = []
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Creates a new Trip Loader.
|
|
34
|
+
*
|
|
35
|
+
* @param {Object} paths Required file paths for the TripLoader
|
|
36
|
+
* @param {string} paths.tripsFile The path for the trips.txt file
|
|
37
|
+
* @param {string} paths.stopTimesFile The path for the stop_times.txt file
|
|
38
|
+
* @param {string} paths.calendarFile The path for the calendar.txt file
|
|
39
|
+
* @param {string} paths.calendarDatesFile The path for the calendar_dates.txt file
|
|
40
|
+
* @param {string} mode The transit mode being loaded
|
|
41
|
+
* @param {DatabaseConnection} database A database connection
|
|
42
|
+
*/
|
|
28
43
|
constructor({ tripsFile, stopTimesFile, calendarFile, calendarDatesFile }, mode, database) {
|
|
29
44
|
this.#routes = database.getCollection('routes')
|
|
30
45
|
this.#stops = database.getCollection('stops')
|
|
@@ -132,12 +147,33 @@ export default class TripLoader {
|
|
|
132
147
|
return dbTrip
|
|
133
148
|
}
|
|
134
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Loads a trip into the database.
|
|
152
|
+
*
|
|
153
|
+
* @param {Object} tripData The trip data
|
|
154
|
+
* @param {string} tripData.tripID The trip ID
|
|
155
|
+
* @param {GTFSStopTime[]} tripData.stops The trip's stops
|
|
156
|
+
* @param {function} [processTrip] Used to process a trip.
|
|
157
|
+
*/
|
|
158
|
+
async loadTrip({ tripID, stops }, processTrip) {
|
|
159
|
+
let rawTripData = this.#tripDetails[tripID]
|
|
160
|
+
let tripData = await this.generateDBTripData(rawTripData, stops)
|
|
161
|
+
if (!tripData) return
|
|
162
|
+
|
|
163
|
+
let processedData = processTrip ? await processTrip(tripData) : tripData
|
|
164
|
+
if (!processedData) return
|
|
165
|
+
|
|
166
|
+
this.#shapeIDMap[tripData.shapeID] = tripData.routeGTFSID
|
|
167
|
+
|
|
168
|
+
this.#tripsToLoad.push(processedData)
|
|
169
|
+
}
|
|
170
|
+
|
|
135
171
|
/**
|
|
136
172
|
* Loads the trip data into the database.
|
|
137
173
|
*
|
|
138
174
|
* @param {object} options A list of options for the trip loader
|
|
139
175
|
* @param {object} options.routeIDMap A mapping of full route IDs to their simplified IDs.
|
|
140
|
-
* @param {function} options.processTrip A function to modify trip data on a per-trip basis. It should return null to discard the trip.
|
|
176
|
+
* @param {function} [options.processTrip] A function to modify trip data on a per-trip basis. It should return null to discard the trip.
|
|
141
177
|
*/
|
|
142
178
|
async loadTrips({ routeIDMap, processTrip }) {
|
|
143
179
|
this.#routeIDMap = routeIDMap
|
|
@@ -146,38 +182,29 @@ export default class TripLoader {
|
|
|
146
182
|
await this.loadTripsData()
|
|
147
183
|
|
|
148
184
|
let tripsLoaded = 0
|
|
149
|
-
let trips = []
|
|
150
185
|
|
|
151
186
|
await this.#stopTimesReader.open()
|
|
152
187
|
while (this.#stopTimesReader.available()) {
|
|
153
|
-
let
|
|
154
|
-
|
|
155
|
-
let rawTripData = this.#tripDetails[tripID]
|
|
156
|
-
let tripData = await this.generateDBTripData(rawTripData, stops)
|
|
157
|
-
if (!tripData) continue
|
|
158
|
-
|
|
159
|
-
let processedData = processTrip ? await processTrip(tripData) : tripData
|
|
160
|
-
if (!processedData) continue
|
|
161
|
-
|
|
162
|
-
this.#shapeIDMap[tripData.shapeID] = tripData.routeGTFSID
|
|
163
|
-
|
|
164
|
-
trips.push(processedData)
|
|
165
|
-
|
|
166
|
-
tripsLoaded += 1
|
|
188
|
+
let gtfsTrip = await this.#stopTimesReader.getNextEntity()
|
|
189
|
+
await this.loadTrip(gtfsTrip, processTrip)
|
|
167
190
|
|
|
168
|
-
if (
|
|
169
|
-
this.#
|
|
170
|
-
this
|
|
171
|
-
|
|
172
|
-
await this.#trips.createDocuments(trips)
|
|
173
|
-
trips = []
|
|
174
|
-
|
|
175
|
-
tripsLoaded = 0
|
|
191
|
+
if (this.#tripsToLoad.length === 5000) { // Flush the cache every 5000 trips
|
|
192
|
+
tripsLoaded += this.#tripsToLoad.length
|
|
193
|
+
await this.writeTrips()
|
|
176
194
|
}
|
|
177
195
|
}
|
|
178
196
|
|
|
179
|
-
|
|
180
|
-
|
|
197
|
+
tripsLoaded += this.#tripsToLoad.length
|
|
198
|
+
await this.writeTrips()
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async writeTrips() {
|
|
202
|
+
if (this.#tripsToLoad.length) {
|
|
203
|
+
this.#routeCache = {}
|
|
204
|
+
this.#stopCache = {}
|
|
205
|
+
|
|
206
|
+
await this.#trips.createDocuments(this.#tripsToLoad)
|
|
207
|
+
this.#tripsToLoad = []
|
|
181
208
|
}
|
|
182
209
|
}
|
|
183
210
|
|