@transportme/load-ptv-gtfs 1.3.5 → 1.3.7

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.
@@ -27,7 +27,7 @@ export class GTFSStop {
27
27
  #isInterstate = false
28
28
  #suburbInFrontMatch
29
29
 
30
- constructor({ stopGTFSID, stopName, stopLat, stopLon, locationType, parentStopGTFSID }, suburbs) {
30
+ constructor({ stopGTFSID, stopName, stopLat, stopLon, locationType, parentStopGTFSID }, suburbs, suburbHook) {
31
31
  this.stopGTFSID = stopGTFSID
32
32
  this.originalName = stopName.replace(/ \(\w+\.\.\. #/, ' #').replace(/ +/g, ' ').trim()
33
33
 
@@ -39,7 +39,7 @@ export class GTFSStop {
39
39
  coordinates: [parseFloat(stopLon), parseFloat(stopLat)]
40
40
  }
41
41
 
42
- this.#setSuburb(suburbs)
42
+ this.#setSuburb(suburbs, suburbHook)
43
43
  this.#setStopNumber()
44
44
 
45
45
  this.fullStopName = this.getFullStopName()
@@ -105,8 +105,11 @@ export class GTFSStop {
105
105
  return this.#expandSuburb(this.originalName.slice(suburbIndex + 1, -1))
106
106
  }
107
107
 
108
- #setSuburb(suburbs) {
109
- if (this.requiresSuburb()) {
108
+ #setSuburb(suburbs, suburbHook) {
109
+ let output
110
+ if (suburbHook && (output = suburbHook(this))) {
111
+ this.suburb = output
112
+ } else if (this.requiresSuburb()) {
110
113
  this.suburb = this.getSuburbFromLocation(suburbs)
111
114
  } else {
112
115
  this.suburb = this.getSuburbFromName()
@@ -206,10 +209,10 @@ export class GTFSStop {
206
209
  return true
207
210
  }
208
211
 
209
- static create(data, suburbs) {
212
+ static create(data, suburbs, suburbHook) {
210
213
  let types = [ GTFSRRBStop, GTFSPlatformStop, GTFSStop ]
211
214
  for (let type of types) {
212
- if (type.canProcess(data)) return new type(data, suburbs)
215
+ if (type.canProcess(data)) return new type(data, suburbs, suburbHook)
213
216
  }
214
217
  }
215
218
  }
@@ -218,8 +221,8 @@ export class GTFSPlatformStop extends GTFSStop {
218
221
 
219
222
  platform
220
223
 
221
- constructor(data, suburbs) {
222
- super(data, suburbs)
224
+ constructor(data, suburbs, suburbHook) {
225
+ super(data, suburbs, suburbHook)
223
226
  this.platform = data.platform
224
227
  }
225
228
 
@@ -238,9 +241,9 @@ export class GTFSPlatformStop extends GTFSStop {
238
241
 
239
242
  export class GTFSRRBStop extends GTFSPlatformStop {
240
243
 
241
- constructor(data, suburbs) {
244
+ constructor(data, suburbs, suburbHook) {
242
245
  data.stopName = data.stopName.replace('Rail Replacement Bus Stop', 'Railway Station')
243
- super(data, suburbs)
246
+ super(data, suburbs, suburbHook)
244
247
  this.platform = 'RRB'
245
248
  }
246
249
 
@@ -4,10 +4,12 @@ import GTFSReader from './GTFSReader.mjs'
4
4
  export default class GTFSStopsReader extends GTFSReader {
5
5
 
6
6
  #suburbData
7
+ #suburbHook
7
8
 
8
- constructor(file, suburbData) {
9
+ constructor(file, suburbData, suburbHook) {
9
10
  super(file)
10
11
  this.#suburbData = suburbData
12
+ this.#suburbHook = suburbHook
11
13
  }
12
14
 
13
15
  /**
@@ -33,6 +35,6 @@ export default class GTFSStopsReader extends GTFSReader {
33
35
  parentStopGTFSID: data.parent_station
34
36
  }
35
37
 
36
- return GTFSStop.create(stopData, this.#suburbData)
38
+ return GTFSStop.create(stopData, this.#suburbData, this.#suburbHook)
37
39
  }
38
40
  }
@@ -19,11 +19,12 @@ export default class StopsLoader {
19
19
  * @param {FeatureCollection} suburbs A GeoJSON FeatureCollection containing a list of all suburbs located within Victoria
20
20
  * @param {string} mode The transit mode being loaded
21
21
  * @param {DatabaseConnection} database A database connection
22
+ * @param {function} [suburbHook] A hook that returns the stop's suburb, or null if unavailable. This function is called before processing from the stop's name or location
22
23
  */
23
- constructor(stopsFile, suburbs, mode, database) {
24
+ constructor(stopsFile, suburbs, mode, database, suburbHook) {
24
25
  this.#stops = database.getCollection('stops')
25
26
  this.#mode = mode
26
- this.#stopsReader = new GTFSStopsReader(stopsFile, suburbs)
27
+ this.#stopsReader = new GTFSStopsReader(stopsFile, suburbs, suburbHook)
27
28
  }
28
29
 
29
30
  getMergeName(stop) {
@@ -28,6 +28,7 @@ export default class TripLoader {
28
28
 
29
29
  #shapeIDMap = {}
30
30
  #directionIDMap = {}
31
+ #stopServicesMap = {}
31
32
 
32
33
  #tripsToLoad = []
33
34
 
@@ -172,9 +173,27 @@ export default class TripLoader {
172
173
  if (!this.#directionIDMap[tripData.routeGTFSID]) this.#directionIDMap[tripData.routeGTFSID] = {}
173
174
  this.#directionIDMap[tripData.routeGTFSID][rawTripData.getHeadsign()] = rawTripData.getGTFSDirection()
174
175
 
176
+ this.updateStopServices(processedData)
177
+
175
178
  this.#tripsToLoad.push(processedData)
176
179
  }
177
180
 
181
+ updateStopServices(trip) {
182
+ let { gtfsDirection, routeGTFSID, routeNumber } = trip
183
+ trip.stopTimings.forEach(stop => {
184
+ let { stopGTFSID } = stop
185
+ let serviceID = `${routeGTFSID}-${gtfsDirection}-${routeNumber}`
186
+ if (!this.#stopServicesMap[stopGTFSID]) this.#stopServicesMap[stopGTFSID] = { services: {}, screenServices: {} }
187
+ if (!this.#stopServicesMap[stopGTFSID].services[serviceID]) {
188
+ this.#stopServicesMap[stopGTFSID].services[serviceID] = { routeGTFSID, gtfsDirection, routeNumber }
189
+ }
190
+
191
+ if (stop.stopConditions.pickup === 0 && !this.#stopServicesMap[stopGTFSID].screenServices[serviceID]) {
192
+ this.#stopServicesMap[stopGTFSID].screenServices[serviceID] = { routeGTFSID, gtfsDirection, routeNumber }
193
+ }
194
+ })
195
+ }
196
+
178
197
  /**
179
198
  * Loads the trip data into the database.
180
199
  *
@@ -222,4 +241,16 @@ export default class TripLoader {
222
241
  getDirectionIDMap() {
223
242
  return this.#directionIDMap
224
243
  }
244
+
245
+ getStopServicesMap() {
246
+ let output = {}
247
+ for (let stopGTFSID of Object.keys(this.#stopServicesMap)) {
248
+ let stopServices = this.#stopServicesMap[stopGTFSID]
249
+ output[stopGTFSID] = {
250
+ services: Object.values(stopServices.services),
251
+ screenServices: Object.values(stopServices.screenServices)
252
+ }
253
+ }
254
+ return output
255
+ }
225
256
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transportme/load-ptv-gtfs",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "description": "",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
@@ -197,6 +197,22 @@ describe('The GTFS Stops Loader', () => {
197
197
  expect(gumRd.stopName).to.equal('Gum Road/Main Road West')
198
198
  })
199
199
 
200
+ it('Should allow for a custom suburb hook', async () => {
201
+ let database = new LokiDatabaseConnection('test-db')
202
+ let stops = await database.createCollection('stops')
203
+
204
+ let testSuburbs = ['A', 'B', 'C', null, 'D']
205
+
206
+ let loader = new StopsLoader(stopsFile, suburbs, TRANSIT_MODES.bus, database, () => testSuburbs.shift())
207
+ await loader.loadStops()
208
+
209
+ expect((await stops.findDocument({ 'bays.stopGTFSID': '1000' })).suburb[0]).to.equal('A')
210
+ expect((await stops.findDocument({ 'bays.stopGTFSID': '10001' })).suburb[0]).to.equal('B')
211
+ expect((await stops.findDocument({ 'bays.stopGTFSID': '10002' })).suburb[0]).to.equal('C')
212
+ expect((await stops.findDocument({ 'bays.stopGTFSID': '10009' })).suburb[0]).to.equal('Albanvale') // Null so not used
213
+ expect((await stops.findDocument({ 'bays.stopGTFSID': '1001' })).suburb[0]).to.equal('D')
214
+ })
215
+
200
216
  it('Should allow for individual stops to be loaded in', async () => {
201
217
  let database = new LokiDatabaseConnection('test-db')
202
218
  let stops = await database.createCollection('stops')
@@ -64,6 +64,15 @@ describe('The GTFSStopReader class', () => {
64
64
  expect(stopData.stopGTFSID).to.equal('14330')
65
65
  expect(stopData.parentStopGTFSID).to.equal('vic:rail:CHL')
66
66
  })
67
+
68
+ it('Should allow a custom stop suburb hook', async () => {
69
+ let stopReader = new GTFSStopsReader(parentStopsFile, suburbs, () => 'Test')
70
+ await stopReader.open()
71
+
72
+ let stopData = await stopReader.getNextEntity()
73
+ expect(stopData.rawStopName).to.equal('Clifton Hill Station')
74
+ expect(stopData.suburb).to.equal('Test')
75
+ })
67
76
  })
68
77
 
69
78
  describe('The getNextEntity function', () => {
@@ -139,4 +139,50 @@ describe('The TripLoader class', () => {
139
139
  '2-ALM': { 'Alamein': 0, 'Camberwell': 1 }
140
140
  })
141
141
  })
142
+
143
+ it('Should return a mapping stop services', async () => {
144
+ let database = new LokiDatabaseConnection('test-db')
145
+ let stops = await database.createCollection('stops')
146
+ let routes = await database.createCollection('routes')
147
+ let trips = await database.createCollection('gtfs timetables')
148
+
149
+ let stopLoader = new StopsLoader(stopsFile, suburbs, TRANSIT_MODES.metroTrain, database)
150
+ await stopLoader.loadStops()
151
+
152
+ let routeLoader = new RouteLoader(routesFile, agencyFile, TRANSIT_MODES.metroTrain, database)
153
+ await routeLoader.loadRoutes()
154
+
155
+ let routeIDMap = routeLoader.getRouteIDMap()
156
+
157
+ let tripLoader = new TripLoader({
158
+ tripsFile, stopTimesFile,
159
+ calendarFile, calendarDatesFile
160
+ }, TRANSIT_MODES.metroTrain, database)
161
+
162
+ await tripLoader.loadTrips({ routeIDMap })
163
+
164
+ let stopServicesMap = tripLoader.getStopServicesMap()
165
+
166
+ expect(stopServicesMap['vic:rail:ALM'].services).to.deep.equal([{
167
+ routeGTFSID: '2-ALM',
168
+ gtfsDirection: 1,
169
+ routeNumber: null
170
+ }, {
171
+ routeGTFSID: '2-ALM',
172
+ gtfsDirection: 0,
173
+ routeNumber: null
174
+ }])
175
+
176
+ expect(stopServicesMap['vic:rail:ALM'].screenServices).to.deep.equal([{
177
+ routeGTFSID: '2-ALM',
178
+ gtfsDirection: 1,
179
+ routeNumber: null
180
+ }])
181
+
182
+ expect(stopServicesMap['vic:rail:CAM'].screenServices).to.deep.equal([{
183
+ routeGTFSID: '2-ALM',
184
+ gtfsDirection: 0,
185
+ routeNumber: null
186
+ }])
187
+ })
142
188
  })