@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.
- package/lib/gtfs-parser/GTFSStop.mjs +20 -4
- package/lib/gtfs-parser/readers/GTFSStopsReader.mjs +3 -1
- package/lib/loader/StopsLoader.mjs +32 -1
- package/package.json +1 -1
- package/test/gtfs-stop-loader.test.mjs +19 -0
- package/test/gtfs-stops.test.mjs +12 -0
- package/test/sample-data/parent-stop/stops.txt +15 -0
|
@@ -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
|
|
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
|
@@ -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
|
})
|
package/test/gtfs-stops.test.mjs
CHANGED
|
@@ -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",""
|