@transportme/load-ptv-gtfs 1.2.6 → 1.3.0

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.
@@ -3,8 +3,16 @@ import { STOP_UTILS } from '@transportme/transportvic-utils'
3
3
 
4
4
  const { processName, getPrimaryStopName, getSecondaryStopName } = STOP_UTILS
5
5
 
6
+ export const STOP_TYPE = {
7
+ 0: 'stop',
8
+ 1: 'station',
9
+ 2: 'entrance',
10
+ 3: 'generic',
11
+ 4: 'boarding',
12
+ }
13
+
6
14
  export class GTFSStop {
7
-
15
+
8
16
  stopGTFSID
9
17
  originalName
10
18
  rawStopName
@@ -13,12 +21,19 @@ export class GTFSStop {
13
21
  location
14
22
  suburb
15
23
 
24
+ location
25
+ parentStopGTFSID
26
+
16
27
  #isInterstate = false
17
28
  #suburbInFrontMatch
18
29
 
19
- constructor({ stopGTFSID, stopName, stopLat, stopLon }, suburbs) {
30
+ constructor({ stopGTFSID, stopName, stopLat, stopLon, locationType, parentStopGTFSID }, suburbs) {
20
31
  this.stopGTFSID = stopGTFSID
21
32
  this.originalName = stopName.replace(/ \(\w+\.\.\. #/, ' #').replace(/ +/g, ' ').trim()
33
+
34
+ this.locationType = locationType || '0'
35
+ this.parentStopGTFSID = parentStopGTFSID || null
36
+
22
37
  this.location = {
23
38
  type: 'Point',
24
39
  coordinates: [parseFloat(stopLon), parseFloat(stopLat)]
@@ -181,7 +196,8 @@ export class GTFSStop {
181
196
  mode,
182
197
  suburb: this.suburb,
183
198
  services: [],
184
- screenServices: []
199
+ screenServices: [],
200
+ stopType: STOP_TYPE[this.locationType]
185
201
  }
186
202
  }
187
203
 
@@ -228,7 +244,7 @@ export class GTFSRRBStop extends GTFSPlatformStop {
228
244
  }
229
245
 
230
246
  static canProcess(data) {
231
- return super.canProcess(data) && data.platform === 'R-Bus'
247
+ return super.canProcess(data) && data.platform.toLowerCase().includes('bus')
232
248
  }
233
249
 
234
250
  }
@@ -28,7 +28,9 @@ export default class GTFSStopsReader extends GTFSReader {
28
28
  stopName: data.stop_name,
29
29
  stopLat: data.stop_lat,
30
30
  stopLon: data.stop_lon,
31
- platform: data.platform_code
31
+ platform: data.platform_code,
32
+ locationType: data.location_type,
33
+ parentStopGTFSID: data.parent_station
32
34
  }
33
35
 
34
36
  return GTFSStop.create(stopData, this.#suburbData)
@@ -1,5 +1,5 @@
1
1
  import { STOP_UTILS } from '@transportme/transportvic-utils'
2
- import { GTFSStop } from '../gtfs-parser/GTFSStop.mjs'
2
+ import { GTFSStop, STOP_TYPE } from '../gtfs-parser/GTFSStop.mjs'
3
3
  import GTFSStopsReader from '../gtfs-parser/readers/GTFSStopsReader.mjs'
4
4
 
5
5
  const { getPrimaryStopName, isStreetStop, sanitiseName } = STOP_UTILS
@@ -10,6 +10,8 @@ export default class StopsLoader {
10
10
  #mode
11
11
  #stopsReader
12
12
 
13
+ #parentHolding = {}
14
+
13
15
  /**
14
16
  * Creates a new Stop Loader.
15
17
  *
@@ -42,6 +44,12 @@ export default class StopsLoader {
42
44
  })
43
45
  }
44
46
 
47
+ async findParentStop(stop) {
48
+ return await this.#stops.findDocument({
49
+ 'bays.stopGTFSID': stop.parentStopGTFSID
50
+ })
51
+ }
52
+
45
53
  generateDBStopData(stop, mergeName) {
46
54
  let cleanName = sanitiseName(stop.fullStopName)
47
55
 
@@ -68,6 +76,7 @@ export default class StopsLoader {
68
76
 
69
77
  updateStopName(stop) {
70
78
  stop.cleanNames = stop.bays
79
+ .filter(bay => bay.stopType === STOP_TYPE[0])
71
80
  .map(bay => sanitiseName(bay.fullStopName))
72
81
  .filter((e, i, a) => a.indexOf(e) === i)
73
82
 
@@ -84,10 +93,12 @@ export default class StopsLoader {
84
93
 
85
94
  updateStopSuburb(stop) {
86
95
  stop.cleanSuburbs = stop.bays
96
+ .filter(bay => bay.stopType === STOP_TYPE[0])
87
97
  .map(bay => sanitiseName(bay.suburb))
88
98
  .filter((e, i, a) => a.indexOf(e) === i)
89
99
 
90
100
  stop.suburb = stop.bays
101
+ .filter(bay => bay.stopType === STOP_TYPE[0])
91
102
  .map(bay => bay.suburb)
92
103
  .filter((e, i, a) => a.indexOf(e) === i)
93
104
  .sort()
@@ -129,6 +140,18 @@ export default class StopsLoader {
129
140
  async loadStop(stop, { processStop, getMergeName } = {}) {
130
141
  let processedData = processStop ? processStop(stop) : stop
131
142
 
143
+ if (processedData.parentStopGTFSID) {
144
+ let parentStop = await this.findParentStop(processedData)
145
+ if (!parentStop) {
146
+ if (!this.#parentHolding[processedData.parentStopGTFSID]) this.#parentHolding[processedData.parentStopGTFSID] = []
147
+ this.#parentHolding[processedData.parentStopGTFSID].push(processedData)
148
+ return
149
+ }
150
+
151
+ let stopData = this.generateDBStopData(processedData, parentStop.mergeName)
152
+ return await this.mergeStops(parentStop, stopData)
153
+ }
154
+
132
155
  let defaultMergeName = this.getMergeName(processedData)
133
156
  let mergeName = getMergeName ? (getMergeName(processedData) || defaultMergeName) : defaultMergeName
134
157
 
@@ -140,6 +163,14 @@ export default class StopsLoader {
140
163
  } else {
141
164
  await this.#stops.createDocument(stopData)
142
165
  }
166
+
167
+ if (this.#parentHolding[stop.stopGTFSID]) {
168
+ for (let childStop of this.#parentHolding[stop.stopGTFSID]) {
169
+ let childStopData = this.generateDBStopData(childStop, stopData.mergeName)
170
+ await this.mergeStops(stopData, childStopData)
171
+ }
172
+ delete this.#parentHolding[stop.stopGTFSID]
173
+ }
143
174
  }
144
175
 
145
176
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@transportme/load-ptv-gtfs",
3
- "version": "1.2.6",
3
+ "version": "1.3.0",
4
4
  "description": "",
5
5
  "main": "index.mjs",
6
6
  "scripts": {
@@ -26,6 +26,8 @@ const specialHeader = path.join(__dirname, 'sample-data', 'gtfs-splitting', 'spe
26
26
 
27
27
  const unionWithSpaces = path.join(__dirname, 'sample-data', 'gtfs-splitting', 'union_with_spaces.txt')
28
28
 
29
+ const parentStopsFile = path.join(__dirname, 'sample-data', 'parent-stop', 'stops.txt')
30
+
29
31
  describe('The GTFS Stops Loader', () => {
30
32
  it('Should process the stops and add them to the database', async () => {
31
33
  let database = new LokiDatabaseConnection('test-db')
@@ -320,4 +322,21 @@ describe('The GTFS Stops Loader', () => {
320
322
  expect(await stops.countDocuments({})).to.equal(1)
321
323
  expect((await stops.findDocument({ 'bays.stopGTFSID': '26535' })).bays.length).to.equal(4) // Union Station
322
324
  })
325
+
326
+ it('Should merge stops into their designated parent stops even if the names do not match', async () => {
327
+ let database = new LokiDatabaseConnection('test-db')
328
+ let stops = await database.createCollection('stops')
329
+
330
+ await (new StopsLoader(parentStopsFile, suburbs, TRANSIT_MODES.metroTrain, database)).loadStops()
331
+
332
+ expect(await stops.countDocuments({})).to.equal(1)
333
+ let stopData = await stops.findDocument({})
334
+ expect(stopData.bays.find(bay => bay.stopGTFSID === '14331').stopType).to.equal('stop')
335
+ expect(stopData.bays.find(bay => bay.stopGTFSID === 'vic:rail:CHL').stopType).to.equal('station')
336
+ expect(stopData.bays.find(bay => bay.stopGTFSID === 'vic:rail:CHL_DP3').stopType).to.equal('generic')
337
+ expect(stopData.bays.find(bay => bay.stopGTFSID === 'vic:rail:CHL_EN1').stopType).to.equal('entrance')
338
+
339
+ // TODO: Find out what the Connex stop is for
340
+ expect(stopData.cleanNames).to.equal(['clifton-hill-railway-station', 'connex'])
341
+ })
323
342
  })
@@ -9,6 +9,8 @@ const __dirname = path.dirname(__filename)
9
9
 
10
10
  const stopsFile = path.join(__dirname, 'sample-data', 'gtfs-splitting', 'line_reader_test.txt')
11
11
 
12
+ const parentStopsFile = path.join(__dirname, 'sample-data', 'parent-stop', 'stops.txt')
13
+
12
14
  let stopInput = {
13
15
  stop_id: '1000',
14
16
  stop_name: 'Dole Ave/Cheddar Rd (Reservoir)',
@@ -52,6 +54,16 @@ describe('The GTFSStopReader class', () => {
52
54
  expect(stopData.suburb).to.equal('Kings Park')
53
55
  expect(stopData.stopNumber).to.equal('51A')
54
56
  })
57
+
58
+ it('Should return the parent stop data if available', async () => {
59
+ let stopReader = new GTFSStopsReader(parentStopsFile, suburbs)
60
+ await stopReader.open()
61
+
62
+ let stopData = await stopReader.getNextEntity()
63
+ expect(stopData.rawStopName).to.equal('Clifton Hill Station')
64
+ expect(stopData.stopGTFSID).to.equal('14330')
65
+ expect(stopData.parentStopGTFSID).to.equal('vic:rail:CHL')
66
+ })
55
67
  })
56
68
 
57
69
  describe('The getNextEntity function', () => {
@@ -0,0 +1,15 @@
1
+ stop_id,stop_name,stop_lat,stop_lon,location_type,parent_station,wheelchair_boarding,level_id,platform_code
2
+ "14330","Clifton Hill Station","-37.78847865","144.99550102","","vic:rail:CHL","1","Level 0","1"
3
+ "14331","Clifton Hill Station","-37.78868312","144.99533652","","vic:rail:CHL","1","Level 0","2"
4
+ "26140","Clifton Hill Rail Replacement Bus Stop","-37.78899337","144.99503289","","vic:rail:CHL","1","Level 0","Replacement bus"
5
+ "vic:rail:CHL","Clifton Hill Railway Station","-37.78865745","144.99541670","1","","1","",""
6
+ "vic:rail:CHL_BR1","Bike & Ride","-37.78862432","144.99558793","3","vic:rail:CHL","","Level 0",""
7
+ "vic:rail:CHL_ConX","Connex","-37.78865745","144.99541670","","vic:rail:CHL","","Level 0",""
8
+ "vic:rail:CHL_DP1","Ramp","-37.78814003","144.99572593","3","vic:rail:CHL","","Level -1",""
9
+ "vic:rail:CHL_DP2","Underpass","-37.78810586","144.99530670","3","vic:rail:CHL","","Level -1",""
10
+ "vic:rail:CHL_DP3","Ramp","-37.78805406","144.99491065","3","vic:rail:CHL","","Level -1",""
11
+ "vic:rail:CHL_EN1","John St","-37.78849918","144.99564809","2","vic:rail:CHL","1","Level 0",""
12
+ "vic:rail:CHL_EN2","Hoddle St","-37.78860913","144.99522496","2","vic:rail:CHL","1","Level 0",""
13
+ "vic:rail:CHL_EN3","Hoddle St","-37.78877108","144.99520923","2","vic:rail:CHL","1","Level 0",""
14
+ "vic:rail:CHL_PR1","Park & Ride 1","-37.78928973","144.99550182","3","vic:rail:CHL","","Level 0",""
15
+ "vic:rail:CHL_PR2","Park & Ride 2","-37.78785120","144.99569967","3","vic:rail:CHL","","Level 0",""