@transportme/load-ptv-gtfs 1.2.6 → 1.3.1

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,9 @@ export class GTFSStop {
181
196
  mode,
182
197
  suburb: this.suburb,
183
198
  services: [],
184
- screenServices: []
199
+ screenServices: [],
200
+ stopType: STOP_TYPE[this.locationType],
201
+ parentStopGTFSID: this.parentStopGTFSID
185
202
  }
186
203
  }
187
204
 
@@ -228,7 +245,7 @@ export class GTFSRRBStop extends GTFSPlatformStop {
228
245
  }
229
246
 
230
247
  static canProcess(data) {
231
- return super.canProcess(data) && data.platform === 'R-Bus'
248
+ return super.canProcess(data) && data.platform.toLowerCase().includes('bus')
232
249
  }
233
250
 
234
251
  }
@@ -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.1",
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,24 @@ 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
+ expect(stopData.bays.find(bay => bay.stopGTFSID === '14331').parentStopGTFSID).to.equal('vic:rail:CHL')
340
+ expect(stopData.bays.find(bay => bay.stopGTFSID === 'vic:rail:CHL').parentStopGTFSID).to.be.null
341
+
342
+ // TODO: Find out what the Connex stop is for
343
+ expect(stopData.cleanNames).to.deep.equal(['clifton-hill-railway-station', 'connex'])
344
+ })
323
345
  })
@@ -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",""