gtfs 4.5.1 → 4.7.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/@types/index.d.ts +40 -40
- package/CHANGELOG.md +23 -0
- package/README.md +33 -4
- package/lib/gtfs/stops.js +29 -6
- package/lib/gtfs-realtime/{stop-times-updates.js → stop-time-updates.js} +5 -5
- package/lib/gtfs.js +3 -3
- package/lib/import.js +54 -29
- package/lib/utils.js +41 -5
- package/models/gtfs-realtime/service-alert-targets.js +1 -1
- package/models/gtfs-realtime/service-alerts.js +1 -1
- package/models/gtfs-realtime/{stop-times-updates.js → stop-time-updates.js} +20 -2
- package/models/gtfs-realtime/trip-updates.js +26 -1
- package/models/gtfs-realtime/vehicle-positions.js +1 -1
- package/models/models.js +2 -2
- package/package.json +10 -9
- package/test/mocha/get-stops-as-geojson.js +20 -0
- package/test/mocha/get-stops.js +82 -8
package/@types/index.d.ts
CHANGED
|
@@ -152,7 +152,7 @@ export function getAgencies(
|
|
|
152
152
|
query?: SqlWhere,
|
|
153
153
|
fields?: SqlSelect,
|
|
154
154
|
sortBy?: SqlOrderBy,
|
|
155
|
-
options?: QueryOptions
|
|
155
|
+
options?: QueryOptions,
|
|
156
156
|
): SqlResults;
|
|
157
157
|
|
|
158
158
|
/**
|
|
@@ -162,7 +162,7 @@ export function getAreas(
|
|
|
162
162
|
query?: SqlWhere,
|
|
163
163
|
fields?: SqlSelect,
|
|
164
164
|
sortBy?: SqlOrderBy,
|
|
165
|
-
options?: QueryOptions
|
|
165
|
+
options?: QueryOptions,
|
|
166
166
|
): SqlResults;
|
|
167
167
|
|
|
168
168
|
/**
|
|
@@ -172,7 +172,7 @@ export function getAttributions(
|
|
|
172
172
|
query?: SqlWhere,
|
|
173
173
|
fields?: SqlSelect,
|
|
174
174
|
sortBy?: SqlOrderBy,
|
|
175
|
-
options?: QueryOptions
|
|
175
|
+
options?: QueryOptions,
|
|
176
176
|
): SqlResults;
|
|
177
177
|
|
|
178
178
|
/**
|
|
@@ -182,7 +182,7 @@ export function getRoutes(
|
|
|
182
182
|
query?: SqlWhere,
|
|
183
183
|
fields?: SqlSelect,
|
|
184
184
|
sortBy?: SqlOrderBy,
|
|
185
|
-
options?: QueryOptions
|
|
185
|
+
options?: QueryOptions,
|
|
186
186
|
): SqlResults;
|
|
187
187
|
|
|
188
188
|
/**
|
|
@@ -192,7 +192,7 @@ export function getStops(
|
|
|
192
192
|
query?: SqlWhere,
|
|
193
193
|
fields?: SqlSelect,
|
|
194
194
|
sortBy?: SqlOrderBy,
|
|
195
|
-
options?: QueryOptions
|
|
195
|
+
options?: QueryOptions,
|
|
196
196
|
): SqlResults;
|
|
197
197
|
|
|
198
198
|
/**
|
|
@@ -201,7 +201,7 @@ export function getStops(
|
|
|
201
201
|
*/
|
|
202
202
|
export function getStopsAsGeoJSON(
|
|
203
203
|
query?: SqlWhere,
|
|
204
|
-
options?: QueryOptions
|
|
204
|
+
options?: QueryOptions,
|
|
205
205
|
): Promise<FeatureCollection<Geometry, { [name: string]: any }>>;
|
|
206
206
|
|
|
207
207
|
/**
|
|
@@ -211,7 +211,7 @@ export function getStoptimes(
|
|
|
211
211
|
query?: SqlWhere,
|
|
212
212
|
fields?: SqlSelect,
|
|
213
213
|
sortBy?: SqlOrderBy,
|
|
214
|
-
options?: QueryOptions
|
|
214
|
+
options?: QueryOptions,
|
|
215
215
|
): SqlResults;
|
|
216
216
|
|
|
217
217
|
/**
|
|
@@ -221,7 +221,7 @@ export function getTrips(
|
|
|
221
221
|
query?: SqlWhere,
|
|
222
222
|
fields?: SqlSelect,
|
|
223
223
|
sortBy?: SqlOrderBy,
|
|
224
|
-
options?: QueryOptions
|
|
224
|
+
options?: QueryOptions,
|
|
225
225
|
): SqlResults;
|
|
226
226
|
|
|
227
227
|
/**
|
|
@@ -231,7 +231,7 @@ export function getShapes(
|
|
|
231
231
|
query?: SqlWhere,
|
|
232
232
|
fields?: SqlSelect,
|
|
233
233
|
sortBy?: SqlOrderBy,
|
|
234
|
-
options?: QueryOptions
|
|
234
|
+
options?: QueryOptions,
|
|
235
235
|
): SqlResults;
|
|
236
236
|
|
|
237
237
|
/**
|
|
@@ -240,7 +240,7 @@ export function getShapes(
|
|
|
240
240
|
*/
|
|
241
241
|
export function getShapesAsGeoJSON(
|
|
242
242
|
query?: SqlWhere,
|
|
243
|
-
options?: QueryOptions
|
|
243
|
+
options?: QueryOptions,
|
|
244
244
|
): FeatureCollection<Geometry, { [name: string]: any }>;
|
|
245
245
|
|
|
246
246
|
/**
|
|
@@ -250,7 +250,7 @@ export function getCalendars(
|
|
|
250
250
|
query?: SqlWhere,
|
|
251
251
|
fields?: SqlSelect,
|
|
252
252
|
sortBy?: SqlOrderBy,
|
|
253
|
-
options?: QueryOptions
|
|
253
|
+
options?: QueryOptions,
|
|
254
254
|
): SqlResults;
|
|
255
255
|
|
|
256
256
|
/**
|
|
@@ -260,7 +260,7 @@ export function getCalendarDates(
|
|
|
260
260
|
query?: SqlWhere,
|
|
261
261
|
fields?: SqlSelect,
|
|
262
262
|
sortBy?: SqlOrderBy,
|
|
263
|
-
options?: QueryOptions
|
|
263
|
+
options?: QueryOptions,
|
|
264
264
|
): SqlResults;
|
|
265
265
|
|
|
266
266
|
/**
|
|
@@ -270,7 +270,7 @@ export function getFareAttributes(
|
|
|
270
270
|
query?: SqlWhere,
|
|
271
271
|
fields?: SqlSelect,
|
|
272
272
|
sortBy?: SqlOrderBy,
|
|
273
|
-
options?: QueryOptions
|
|
273
|
+
options?: QueryOptions,
|
|
274
274
|
): SqlResults;
|
|
275
275
|
|
|
276
276
|
/**
|
|
@@ -280,7 +280,7 @@ export function getFareLegRules(
|
|
|
280
280
|
query?: SqlWhere,
|
|
281
281
|
fields?: SqlSelect,
|
|
282
282
|
sortBy?: SqlOrderBy,
|
|
283
|
-
options?: QueryOptions
|
|
283
|
+
options?: QueryOptions,
|
|
284
284
|
): SqlResults;
|
|
285
285
|
|
|
286
286
|
/**
|
|
@@ -290,7 +290,7 @@ export function getFareProducts(
|
|
|
290
290
|
query?: SqlWhere,
|
|
291
291
|
fields?: SqlSelect,
|
|
292
292
|
sortBy?: SqlOrderBy,
|
|
293
|
-
options?: QueryOptions
|
|
293
|
+
options?: QueryOptions,
|
|
294
294
|
): SqlResults;
|
|
295
295
|
|
|
296
296
|
/**
|
|
@@ -300,7 +300,7 @@ export function getFareRules(
|
|
|
300
300
|
query?: SqlWhere,
|
|
301
301
|
fields?: SqlSelect,
|
|
302
302
|
sortBy?: SqlOrderBy,
|
|
303
|
-
options?: QueryOptions
|
|
303
|
+
options?: QueryOptions,
|
|
304
304
|
): SqlResults;
|
|
305
305
|
|
|
306
306
|
/**
|
|
@@ -310,7 +310,7 @@ export function getFareTransferRules(
|
|
|
310
310
|
query?: SqlWhere,
|
|
311
311
|
fields?: SqlSelect,
|
|
312
312
|
sortBy?: SqlOrderBy,
|
|
313
|
-
options?: QueryOptions
|
|
313
|
+
options?: QueryOptions,
|
|
314
314
|
): SqlResults;
|
|
315
315
|
|
|
316
316
|
/**
|
|
@@ -320,7 +320,7 @@ export function getFeedInfo(
|
|
|
320
320
|
query?: SqlWhere,
|
|
321
321
|
fields?: SqlSelect,
|
|
322
322
|
sortBy?: SqlOrderBy,
|
|
323
|
-
options?: QueryOptions
|
|
323
|
+
options?: QueryOptions,
|
|
324
324
|
): SqlResults;
|
|
325
325
|
|
|
326
326
|
/**
|
|
@@ -330,7 +330,7 @@ export function getFrequencies(
|
|
|
330
330
|
query?: SqlWhere,
|
|
331
331
|
fields?: SqlSelect,
|
|
332
332
|
sortBy?: SqlOrderBy,
|
|
333
|
-
options?: QueryOptions
|
|
333
|
+
options?: QueryOptions,
|
|
334
334
|
): SqlResults;
|
|
335
335
|
|
|
336
336
|
/**
|
|
@@ -340,7 +340,7 @@ export function getLevels(
|
|
|
340
340
|
query?: SqlWhere,
|
|
341
341
|
fields?: SqlSelect,
|
|
342
342
|
sortBy?: SqlOrderBy,
|
|
343
|
-
options?: QueryOptions
|
|
343
|
+
options?: QueryOptions,
|
|
344
344
|
): SqlResults;
|
|
345
345
|
|
|
346
346
|
/**
|
|
@@ -350,7 +350,7 @@ export function getPathways(
|
|
|
350
350
|
query?: SqlWhere,
|
|
351
351
|
fields?: SqlSelect,
|
|
352
352
|
sortBy?: SqlOrderBy,
|
|
353
|
-
options?: QueryOptions
|
|
353
|
+
options?: QueryOptions,
|
|
354
354
|
): SqlResults;
|
|
355
355
|
|
|
356
356
|
/**
|
|
@@ -360,7 +360,7 @@ export function getTransfers(
|
|
|
360
360
|
query?: SqlWhere,
|
|
361
361
|
fields?: SqlSelect,
|
|
362
362
|
sortBy?: SqlOrderBy,
|
|
363
|
-
options?: QueryOptions
|
|
363
|
+
options?: QueryOptions,
|
|
364
364
|
): SqlResults;
|
|
365
365
|
|
|
366
366
|
/**
|
|
@@ -370,7 +370,7 @@ export function getTranslations(
|
|
|
370
370
|
query?: SqlWhere,
|
|
371
371
|
fields?: SqlSelect,
|
|
372
372
|
sortBy?: SqlOrderBy,
|
|
373
|
-
options?: QueryOptions
|
|
373
|
+
options?: QueryOptions,
|
|
374
374
|
): SqlResults;
|
|
375
375
|
|
|
376
376
|
/**
|
|
@@ -380,7 +380,7 @@ export function getStopAreas(
|
|
|
380
380
|
query?: SqlWhere,
|
|
381
381
|
fields?: SqlSelect,
|
|
382
382
|
sortBy?: SqlOrderBy,
|
|
383
|
-
options?: QueryOptions
|
|
383
|
+
options?: QueryOptions,
|
|
384
384
|
): SqlResults;
|
|
385
385
|
|
|
386
386
|
/**
|
|
@@ -391,7 +391,7 @@ export function getCalendarAttributes(
|
|
|
391
391
|
query?: SqlWhere,
|
|
392
392
|
fields?: SqlSelect,
|
|
393
393
|
sortBy?: SqlOrderBy,
|
|
394
|
-
options?: QueryOptions
|
|
394
|
+
options?: QueryOptions,
|
|
395
395
|
): SqlResults;
|
|
396
396
|
|
|
397
397
|
/**
|
|
@@ -402,7 +402,7 @@ export function getDirections(
|
|
|
402
402
|
query?: SqlWhere,
|
|
403
403
|
fields?: SqlSelect,
|
|
404
404
|
sortBy?: SqlOrderBy,
|
|
405
|
-
options?: QueryOptions
|
|
405
|
+
options?: QueryOptions,
|
|
406
406
|
): SqlResults;
|
|
407
407
|
|
|
408
408
|
/**
|
|
@@ -413,7 +413,7 @@ export function getRouteAttributes(
|
|
|
413
413
|
query?: SqlWhere,
|
|
414
414
|
fields?: SqlSelect,
|
|
415
415
|
sortBy?: SqlOrderBy,
|
|
416
|
-
options?: QueryOptions
|
|
416
|
+
options?: QueryOptions,
|
|
417
417
|
): SqlResults;
|
|
418
418
|
|
|
419
419
|
/**
|
|
@@ -424,7 +424,7 @@ export function getStopAttributes(
|
|
|
424
424
|
query?: SqlWhere,
|
|
425
425
|
fields?: SqlSelect,
|
|
426
426
|
sortBy?: SqlOrderBy,
|
|
427
|
-
options?: QueryOptions
|
|
427
|
+
options?: QueryOptions,
|
|
428
428
|
): SqlResults;
|
|
429
429
|
|
|
430
430
|
/**
|
|
@@ -435,7 +435,7 @@ export function getTimetables(
|
|
|
435
435
|
query?: SqlWhere,
|
|
436
436
|
fields?: SqlSelect,
|
|
437
437
|
sortBy?: SqlOrderBy,
|
|
438
|
-
options?: QueryOptions
|
|
438
|
+
options?: QueryOptions,
|
|
439
439
|
): SqlResults;
|
|
440
440
|
|
|
441
441
|
/**
|
|
@@ -446,7 +446,7 @@ export function getTimetableStopOrders(
|
|
|
446
446
|
query?: SqlWhere,
|
|
447
447
|
fields?: SqlSelect,
|
|
448
448
|
sortBy?: SqlOrderBy,
|
|
449
|
-
options?: QueryOptions
|
|
449
|
+
options?: QueryOptions,
|
|
450
450
|
): SqlResults;
|
|
451
451
|
|
|
452
452
|
/**
|
|
@@ -457,7 +457,7 @@ export function getTimetablePages(
|
|
|
457
457
|
query?: SqlWhere,
|
|
458
458
|
fields?: SqlSelect,
|
|
459
459
|
sortBy?: SqlOrderBy,
|
|
460
|
-
options?: QueryOptions
|
|
460
|
+
options?: QueryOptions,
|
|
461
461
|
): SqlResults;
|
|
462
462
|
|
|
463
463
|
/**
|
|
@@ -468,7 +468,7 @@ export function getTimetableNotes(
|
|
|
468
468
|
query?: SqlWhere,
|
|
469
469
|
fields?: SqlSelect,
|
|
470
470
|
sortBy?: SqlOrderBy,
|
|
471
|
-
options?: QueryOptions
|
|
471
|
+
options?: QueryOptions,
|
|
472
472
|
): SqlResults;
|
|
473
473
|
|
|
474
474
|
/**
|
|
@@ -479,7 +479,7 @@ export function getTimetableNotesReferences(
|
|
|
479
479
|
query?: SqlWhere,
|
|
480
480
|
fields?: SqlSelect,
|
|
481
481
|
sortBy?: SqlOrderBy,
|
|
482
|
-
options?: QueryOptions
|
|
482
|
+
options?: QueryOptions,
|
|
483
483
|
): SqlResults;
|
|
484
484
|
|
|
485
485
|
/**
|
|
@@ -490,7 +490,7 @@ export function getTripsDatedVehicleJourneys(
|
|
|
490
490
|
query?: SqlWhere,
|
|
491
491
|
fields?: SqlSelect,
|
|
492
492
|
sortBy?: SqlOrderBy,
|
|
493
|
-
options?: QueryOptions
|
|
493
|
+
options?: QueryOptions,
|
|
494
494
|
): SqlResults;
|
|
495
495
|
|
|
496
496
|
/**
|
|
@@ -501,7 +501,7 @@ export function getServiceAlerts(
|
|
|
501
501
|
query?: SqlWhere,
|
|
502
502
|
fields?: SqlSelect,
|
|
503
503
|
sortBy?: SqlOrderBy,
|
|
504
|
-
options?: QueryOptions
|
|
504
|
+
options?: QueryOptions,
|
|
505
505
|
): SqlResults;
|
|
506
506
|
|
|
507
507
|
/**
|
|
@@ -512,18 +512,18 @@ export function getTripUpdates(
|
|
|
512
512
|
query?: SqlWhere,
|
|
513
513
|
fields?: SqlSelect,
|
|
514
514
|
sortBy?: SqlOrderBy,
|
|
515
|
-
options?: QueryOptions
|
|
515
|
+
options?: QueryOptions,
|
|
516
516
|
): SqlResults;
|
|
517
517
|
|
|
518
518
|
/**
|
|
519
519
|
* Returns an array of GTFS Realtime stop time updates that match query parameters.
|
|
520
520
|
* This only works if you configure GTFS Realtime import in node-gtfs.
|
|
521
521
|
*/
|
|
522
|
-
export function
|
|
522
|
+
export function getStopTimeUpdates(
|
|
523
523
|
query?: SqlWhere,
|
|
524
524
|
fields?: SqlSelect,
|
|
525
525
|
sortBy?: SqlOrderBy,
|
|
526
|
-
options?: QueryOptions
|
|
526
|
+
options?: QueryOptions,
|
|
527
527
|
): SqlResults;
|
|
528
528
|
|
|
529
529
|
/**
|
|
@@ -534,7 +534,7 @@ export function getVehiclePositions(
|
|
|
534
534
|
query?: SqlWhere,
|
|
535
535
|
fields?: SqlSelect,
|
|
536
536
|
sortBy?: SqlOrderBy,
|
|
537
|
-
options?: QueryOptions
|
|
537
|
+
options?: QueryOptions,
|
|
538
538
|
): SqlResults;
|
|
539
539
|
|
|
540
540
|
/**
|
|
@@ -542,5 +542,5 @@ export function getVehiclePositions(
|
|
|
542
542
|
*/
|
|
543
543
|
export function advancedQuery(
|
|
544
544
|
table?: SqlTableName,
|
|
545
|
-
advancedQueryOptions?: AdvancedQueryOptions
|
|
545
|
+
advancedQueryOptions?: AdvancedQueryOptions,
|
|
546
546
|
): SqlResults;
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.7.0] - 2024-02-09
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Added `bounding_box_side_m` option to `getStops` and `getStopsAsGeoJSON` to find all stops within a bounding box.
|
|
13
|
+
|
|
14
|
+
### Updated
|
|
15
|
+
|
|
16
|
+
- Dependency updates
|
|
17
|
+
|
|
18
|
+
## [4.6.0] - 2024-01-17
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- Renamed `getStopTimesUpdates` to `getStopTimeUpdates`.
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
- Added `schedule_relationship`, `trip_start_time`, `direction_id` and `route_id` fields to stop_time_updates and trip_updates tables.
|
|
26
|
+
|
|
27
|
+
### Updated
|
|
28
|
+
|
|
29
|
+
- Dependency updates
|
|
30
|
+
|
|
8
31
|
## [4.5.1] - 2023-11-09
|
|
9
32
|
|
|
10
33
|
### Updated
|
package/README.md
CHANGED
|
@@ -737,6 +737,24 @@ const stops = getStops({
|
|
|
737
737
|
const stops = getStops({
|
|
738
738
|
shape_id: 'cal_sf_tam',
|
|
739
739
|
});
|
|
740
|
+
|
|
741
|
+
/*
|
|
742
|
+
* `getStops` allows passing a `bounding_box_side_m` value in the options
|
|
743
|
+
* parameter object. If included, it will return all stops within a square
|
|
744
|
+
* bounding box around the `stop_lat` and `stop_lon` parameters passed to
|
|
745
|
+
* the query using the size in meters specified.
|
|
746
|
+
*/
|
|
747
|
+
const stops = getStops(
|
|
748
|
+
{
|
|
749
|
+
stop_lat: 37.58764,
|
|
750
|
+
stop_lon: -122.36265
|
|
751
|
+
},
|
|
752
|
+
[],
|
|
753
|
+
[],
|
|
754
|
+
{
|
|
755
|
+
bounding_box_side_m: 1000
|
|
756
|
+
}
|
|
757
|
+
);
|
|
740
758
|
```
|
|
741
759
|
|
|
742
760
|
#### getStopsAsGeoJSON(query, options)
|
|
@@ -753,6 +771,17 @@ const stopsGeojson = getStopsAsGeoJSON();
|
|
|
753
771
|
const stopsGeojson = getStopsAsGeoJSON({
|
|
754
772
|
route_id: 'Lo-16APR',
|
|
755
773
|
});
|
|
774
|
+
|
|
775
|
+
// Get all stops within a 1000m bounding box as geoJSON
|
|
776
|
+
const stopsGeojson = getStopsAsGeoJSON(
|
|
777
|
+
{
|
|
778
|
+
stop_lat: 37.58764,
|
|
779
|
+
stop_lon: -122.36265
|
|
780
|
+
},
|
|
781
|
+
{
|
|
782
|
+
bounding_box_side_m: 1000
|
|
783
|
+
}
|
|
784
|
+
);
|
|
756
785
|
```
|
|
757
786
|
|
|
758
787
|
#### getStoptimes(query, fields, sortBy, options)
|
|
@@ -1189,15 +1218,15 @@ import { getTripUpdates } from 'gtfs';
|
|
|
1189
1218
|
const tripUpdates = getTripUpdates();
|
|
1190
1219
|
```
|
|
1191
1220
|
|
|
1192
|
-
####
|
|
1221
|
+
#### getStopTimeUpdates(query, fields, sortBy, options)
|
|
1193
1222
|
|
|
1194
1223
|
Returns an array of GTFS Realtime stop time updates that match query parameters. [Details on Stop Time Updates](https://gtfs.org/realtime/feed-entities/trip-updates/#stoptimeupdate)
|
|
1195
1224
|
|
|
1196
1225
|
```js
|
|
1197
|
-
import {
|
|
1226
|
+
import { getStopTimeUpdates } from 'gtfs';
|
|
1198
1227
|
|
|
1199
|
-
// Get all stop
|
|
1200
|
-
const
|
|
1228
|
+
// Get all stop time updates
|
|
1229
|
+
const stopTimeUpdates = getStopTimeUpdates();
|
|
1201
1230
|
```
|
|
1202
1231
|
|
|
1203
1232
|
#### getVehiclePositions(query, fields, sortBy, options)
|
package/lib/gtfs/stops.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
formatOrderByClause,
|
|
8
8
|
formatSelectClause,
|
|
9
9
|
formatWhereClause,
|
|
10
|
+
formatWhereClauseBoundingBox,
|
|
10
11
|
formatWhereClauses,
|
|
11
12
|
} from '../utils.js';
|
|
12
13
|
import { stopsToGeoJSON } from '../geojson-utils.js';
|
|
@@ -21,7 +22,7 @@ function buildTripSubquery(query) {
|
|
|
21
22
|
|
|
22
23
|
function buildStoptimeSubquery(query) {
|
|
23
24
|
return `SELECT DISTINCT stop_id FROM stop_times WHERE trip_id IN (${buildTripSubquery(
|
|
24
|
-
query
|
|
25
|
+
query,
|
|
25
26
|
)})`;
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -39,13 +40,21 @@ export function getStops(query = {}, fields = [], orderBy = [], options = {}) {
|
|
|
39
40
|
let whereClause = '';
|
|
40
41
|
const orderByClause = formatOrderByClause(orderBy);
|
|
41
42
|
|
|
42
|
-
const
|
|
43
|
+
const stopQueryOmitKeys = [
|
|
43
44
|
'route_id',
|
|
44
45
|
'trip_id',
|
|
45
46
|
'service_id',
|
|
46
47
|
'direction_id',
|
|
47
48
|
'shape_id',
|
|
48
|
-
]
|
|
49
|
+
];
|
|
50
|
+
|
|
51
|
+
// If bounding_box_side_m is defined, search for stops inside a bounding box so omit `stop_lat` and `stop_lon`.
|
|
52
|
+
if (options.bounding_box_side_m !== undefined) {
|
|
53
|
+
stopQueryOmitKeys.push('stop_lat', 'stop_lon');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
let stopQuery = omit(query, stopQueryOmitKeys);
|
|
57
|
+
|
|
49
58
|
const tripQuery = pick(query, [
|
|
50
59
|
'route_id',
|
|
51
60
|
'trip_id',
|
|
@@ -55,9 +64,23 @@ export function getStops(query = {}, fields = [], orderBy = [], options = {}) {
|
|
|
55
64
|
]);
|
|
56
65
|
|
|
57
66
|
const whereClauses = Object.entries(stopQuery).map(([key, value]) =>
|
|
58
|
-
formatWhereClause(key, value)
|
|
67
|
+
formatWhereClause(key, value),
|
|
59
68
|
);
|
|
60
69
|
|
|
70
|
+
if (
|
|
71
|
+
options.bounding_box_side_m !== undefined &&
|
|
72
|
+
query.stop_lat !== undefined &&
|
|
73
|
+
query.stop_lon !== undefined
|
|
74
|
+
) {
|
|
75
|
+
whereClauses.push(
|
|
76
|
+
formatWhereClauseBoundingBox(
|
|
77
|
+
query.stop_lat,
|
|
78
|
+
query.stop_lon,
|
|
79
|
+
options.bounding_box_side_m,
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
61
84
|
if (Object.values(tripQuery).length > 0) {
|
|
62
85
|
whereClauses.push(`stop_id IN (${buildStoptimeSubquery(tripQuery)})`);
|
|
63
86
|
}
|
|
@@ -68,7 +91,7 @@ export function getStops(query = {}, fields = [], orderBy = [], options = {}) {
|
|
|
68
91
|
|
|
69
92
|
return db
|
|
70
93
|
.prepare(
|
|
71
|
-
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause}
|
|
94
|
+
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,
|
|
72
95
|
)
|
|
73
96
|
.all();
|
|
74
97
|
}
|
|
@@ -96,7 +119,7 @@ export function getStopsAsGeoJSON(query = {}, options = {}) {
|
|
|
96
119
|
const stopAttributes = getStopAttributes({ stop_id: stop.stop_id });
|
|
97
120
|
|
|
98
121
|
stop.routes = orderBy(routes, (route) =>
|
|
99
|
-
Number.parseInt(route.route_short_name, 10)
|
|
122
|
+
Number.parseInt(route.route_short_name, 10),
|
|
100
123
|
);
|
|
101
124
|
stop.agency_name = agencies[0].agency_name;
|
|
102
125
|
|
|
@@ -7,16 +7,16 @@ import {
|
|
|
7
7
|
formatSelectClause,
|
|
8
8
|
formatWhereClauses,
|
|
9
9
|
} from '../utils.js';
|
|
10
|
-
import stopTimeUpdates from '../../models/gtfs-realtime/stop-
|
|
10
|
+
import stopTimeUpdates from '../../models/gtfs-realtime/stop-time-updates.js';
|
|
11
11
|
|
|
12
12
|
/*
|
|
13
|
-
* Returns an array of all stop
|
|
13
|
+
* Returns an array of all stop time updates that match the query parameters.
|
|
14
14
|
*/
|
|
15
|
-
export function
|
|
15
|
+
export function getStopTimeUpdates(
|
|
16
16
|
query = {},
|
|
17
17
|
fields = [],
|
|
18
18
|
orderBy = [],
|
|
19
|
-
options = {}
|
|
19
|
+
options = {},
|
|
20
20
|
) {
|
|
21
21
|
const db = options.db ?? openDb();
|
|
22
22
|
const tableName = sqlString.escapeId(stopTimeUpdates.filenameBase);
|
|
@@ -26,7 +26,7 @@ export function getStopTimesUpdates(
|
|
|
26
26
|
|
|
27
27
|
return db
|
|
28
28
|
.prepare(
|
|
29
|
-
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause}
|
|
29
|
+
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`,
|
|
30
30
|
)
|
|
31
31
|
.all();
|
|
32
32
|
}
|
package/lib/gtfs.js
CHANGED
|
@@ -50,7 +50,7 @@ import { getRiderships } from './gtfs-ride/riderships.js';
|
|
|
50
50
|
import { getTripCapacities } from './gtfs-ride/trip-capacities.js';
|
|
51
51
|
|
|
52
52
|
// GTFS-Realtime Filenames
|
|
53
|
-
import {
|
|
53
|
+
import { getStopTimeUpdates } from './gtfs-realtime/stop-time-updates.js';
|
|
54
54
|
import { getTripUpdates } from './gtfs-realtime/trip-updates.js';
|
|
55
55
|
import { getVehiclePositions } from './gtfs-realtime/vehicle-positions.js';
|
|
56
56
|
import { getServiceAlerts } from './gtfs-realtime/service-alerts.js';
|
|
@@ -191,8 +191,8 @@ export { _getTripCapacities as getTripCapacities };
|
|
|
191
191
|
const _updateGtfsRealtime = updateGtfsRealtime;
|
|
192
192
|
export { _updateGtfsRealtime as updateGtfsRealtime };
|
|
193
193
|
|
|
194
|
-
const
|
|
195
|
-
export {
|
|
194
|
+
const _getStopTimeUpdates = getStopTimeUpdates;
|
|
195
|
+
export { _getStopTimeUpdates as getStopTimeUpdates };
|
|
196
196
|
|
|
197
197
|
const _getTripUpdates = getTripUpdates;
|
|
198
198
|
export { _getTripUpdates as getTripUpdates };
|
package/lib/import.js
CHANGED
|
@@ -9,7 +9,7 @@ import stripBomStream from 'strip-bom-stream';
|
|
|
9
9
|
import { dir } from 'tmp-promise';
|
|
10
10
|
import untildify from 'untildify';
|
|
11
11
|
import mapSeries from 'promise-map-series';
|
|
12
|
-
import
|
|
12
|
+
import GtfsRealtimeBindings from 'gtfs-realtime-bindings';
|
|
13
13
|
import sqlString from 'sqlstring-sqlite';
|
|
14
14
|
|
|
15
15
|
import models from '../models/models.js';
|
|
@@ -59,7 +59,18 @@ const downloadGtfsRealtimeData = async (url, headers) => {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const buffer = await response.arrayBuffer();
|
|
62
|
-
|
|
62
|
+
const message = GtfsRealtimeBindings.transit_realtime.FeedMessage.decode(
|
|
63
|
+
new Uint8Array(buffer),
|
|
64
|
+
);
|
|
65
|
+
return GtfsRealtimeBindings.transit_realtime.FeedMessage.toObject(message, {
|
|
66
|
+
enums: String,
|
|
67
|
+
longs: String,
|
|
68
|
+
bytes: String,
|
|
69
|
+
defaults: true,
|
|
70
|
+
arrays: true,
|
|
71
|
+
objects: true,
|
|
72
|
+
oneofs: true,
|
|
73
|
+
});
|
|
63
74
|
};
|
|
64
75
|
|
|
65
76
|
function getDescendantProp(obj, desc, defaultvalue) {
|
|
@@ -69,11 +80,19 @@ function getDescendantProp(obj, desc, defaultvalue) {
|
|
|
69
80
|
const nextKey = arr.shift();
|
|
70
81
|
if (nextKey.includes('[')) {
|
|
71
82
|
const arrayKey = nextKey.match(/(\w*)\[(\d+)\]/);
|
|
72
|
-
if (
|
|
73
|
-
|
|
83
|
+
if (obj[arrayKey[1]] === undefined) {
|
|
84
|
+
return defaultvalue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (obj[arrayKey[1]][arrayKey[2]] === undefined) {
|
|
88
|
+
return defaultvalue;
|
|
89
|
+
}
|
|
90
|
+
|
|
74
91
|
obj = obj[arrayKey[1]][arrayKey[2]];
|
|
75
92
|
} else {
|
|
76
|
-
if (
|
|
93
|
+
if (obj[nextKey] === undefined) {
|
|
94
|
+
return defaultvalue;
|
|
95
|
+
}
|
|
77
96
|
obj = obj[nextKey];
|
|
78
97
|
}
|
|
79
98
|
}
|
|
@@ -87,11 +106,11 @@ const markRealtimeDataStale = (config, log) => {
|
|
|
87
106
|
const db = openDb(config);
|
|
88
107
|
|
|
89
108
|
log(`Marking GTFS-Realtime data as stale..`);
|
|
90
|
-
db.prepare(`UPDATE vehicle_positions SET
|
|
91
|
-
db.prepare(`UPDATE trip_updates SET
|
|
92
|
-
db.prepare(`UPDATE
|
|
93
|
-
db.prepare(`UPDATE service_alerts SET
|
|
94
|
-
db.prepare(`UPDATE service_alert_targets SET
|
|
109
|
+
db.prepare(`UPDATE vehicle_positions SET is_updated=0`).run();
|
|
110
|
+
db.prepare(`UPDATE trip_updates SET is_updated=0`).run();
|
|
111
|
+
db.prepare(`UPDATE stop_time_updates SET is_updated=0`).run();
|
|
112
|
+
db.prepare(`UPDATE service_alerts SET is_updated=0`).run();
|
|
113
|
+
db.prepare(`UPDATE service_alert_targets SET is_updated=0`).run();
|
|
95
114
|
log(`Marked GTFS-Realtime data as stale\r`, true);
|
|
96
115
|
};
|
|
97
116
|
|
|
@@ -99,11 +118,11 @@ const cleanStaleRealtimeData = (config, log) => {
|
|
|
99
118
|
const db = openDb(config);
|
|
100
119
|
|
|
101
120
|
log(`Cleaning stale GTFS-RT data..`);
|
|
102
|
-
db.prepare(`DELETE FROM vehicle_positions WHERE
|
|
103
|
-
db.prepare(`DELETE FROM trip_updates WHERE
|
|
104
|
-
db.prepare(`DELETE FROM
|
|
105
|
-
db.prepare(`DELETE FROM service_alerts WHERE
|
|
106
|
-
db.prepare(`DELETE FROM service_alert_targets WHERE
|
|
121
|
+
db.prepare(`DELETE FROM vehicle_positions WHERE is_updated=0`).run();
|
|
122
|
+
db.prepare(`DELETE FROM trip_updates WHERE is_updated=0`).run();
|
|
123
|
+
db.prepare(`DELETE FROM stop_time_updates WHERE is_updated=0`).run();
|
|
124
|
+
db.prepare(`DELETE FROM service_alerts WHERE is_updated=0`).run();
|
|
125
|
+
db.prepare(`DELETE FROM service_alert_targets WHERE is_updated=0`).run();
|
|
107
126
|
log(`Cleaned stale GTFS-Realtime data\r`, true);
|
|
108
127
|
};
|
|
109
128
|
|
|
@@ -115,8 +134,8 @@ const updateRealtimeData = async (task) => {
|
|
|
115
134
|
(x) => x.filenameBase === 'vehicle_positions',
|
|
116
135
|
),
|
|
117
136
|
trip_updates: models.find((x) => x.filenameBase === 'trip_updates'),
|
|
118
|
-
|
|
119
|
-
(x) => x.filenameBase === '
|
|
137
|
+
stop_time_updates: models.find(
|
|
138
|
+
(x) => x.filenameBase === 'stop_time_updates',
|
|
120
139
|
),
|
|
121
140
|
service_alerts: models.find((x) => x.filenameBase === 'service_alerts'),
|
|
122
141
|
service_alert_targets: models.find(
|
|
@@ -131,7 +150,7 @@ const updateRealtimeData = async (task) => {
|
|
|
131
150
|
trip_updates: model.trip_updates.schema
|
|
132
151
|
.map((column) => column.name)
|
|
133
152
|
.join(', '),
|
|
134
|
-
|
|
153
|
+
stop_time_updates: model.stop_time_updates.schema
|
|
135
154
|
.map((column) => column.name)
|
|
136
155
|
.join(', '),
|
|
137
156
|
service_alerts: model.service_alerts.schema
|
|
@@ -149,14 +168,20 @@ const updateRealtimeData = async (task) => {
|
|
|
149
168
|
for (const realtimeUrl of task.realtime_urls) {
|
|
150
169
|
task.log(`Downloading GTFS-Realtime from ${realtimeUrl}`);
|
|
151
170
|
// eslint-disable-next-line no-await-in-loop
|
|
152
|
-
const
|
|
171
|
+
const gtfsRealtimeData = await downloadGtfsRealtimeData(
|
|
153
172
|
realtimeUrl,
|
|
154
173
|
task.realtime_headers,
|
|
155
174
|
);
|
|
175
|
+
|
|
156
176
|
task.log(`Download successful`);
|
|
157
177
|
|
|
178
|
+
if (!gtfsRealtimeData.entity) {
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
|
|
158
182
|
let totalLineCount = 0;
|
|
159
|
-
|
|
183
|
+
|
|
184
|
+
for (const entity of gtfsRealtimeData.entity) {
|
|
160
185
|
// Determine the type of GTFS-Realtime
|
|
161
186
|
let gtfsRealtimeType = null;
|
|
162
187
|
if (entity.vehicle) {
|
|
@@ -194,23 +219,23 @@ const updateRealtimeData = async (task) => {
|
|
|
194
219
|
|
|
195
220
|
// Special processing for tripUpdates
|
|
196
221
|
if (entity.tripUpdate) {
|
|
197
|
-
const
|
|
198
|
-
for (const
|
|
199
|
-
|
|
200
|
-
const subValues = model.
|
|
222
|
+
const stopTimeUpdateArray = [];
|
|
223
|
+
for (const stopTimeUpdate of entity.tripUpdate.stopTimeUpdate) {
|
|
224
|
+
stopTimeUpdate.parent = entity;
|
|
225
|
+
const subValues = model.stop_time_updates.schema.map((column) =>
|
|
201
226
|
sqlString.escape(
|
|
202
|
-
getDescendantProp(
|
|
227
|
+
getDescendantProp(stopTimeUpdate, column.source, column.default),
|
|
203
228
|
),
|
|
204
229
|
);
|
|
205
|
-
|
|
230
|
+
stopTimeUpdateArray.push(`(${subValues.join(', ')})`);
|
|
206
231
|
totalLineCount++;
|
|
207
232
|
}
|
|
208
233
|
|
|
209
234
|
try {
|
|
210
235
|
db.prepare(
|
|
211
|
-
`REPLACE INTO ${model.
|
|
212
|
-
fields.
|
|
213
|
-
}) VALUES ${
|
|
236
|
+
`REPLACE INTO ${model.stop_time_updates.filenameBase} (${
|
|
237
|
+
fields.stop_time_updates
|
|
238
|
+
}) VALUES ${stopTimeUpdateArray.join(', ')}`,
|
|
214
239
|
).run();
|
|
215
240
|
} catch (error) {
|
|
216
241
|
task.warn('Import error: ' + error.message);
|
package/lib/utils.js
CHANGED
|
@@ -12,7 +12,7 @@ export function validateConfigForImport(config) {
|
|
|
12
12
|
for (const [index, agency] of config.agencies.entries()) {
|
|
13
13
|
if (!agency.path && !agency.url) {
|
|
14
14
|
throw new Error(
|
|
15
|
-
`No Agency \`url\` or \`path\` specified in config for agency index ${index}
|
|
15
|
+
`No Agency \`url\` or \`path\` specified in config for agency index ${index}.`,
|
|
16
16
|
);
|
|
17
17
|
}
|
|
18
18
|
}
|
|
@@ -75,7 +75,7 @@ export function formatSelectClause(fields) {
|
|
|
75
75
|
|
|
76
76
|
const selectItem = Object.entries(fields)
|
|
77
77
|
.map(
|
|
78
|
-
(key) => `${sqlString.escapeId(key[0])} AS ${sqlString.escapeId(key[1])}
|
|
78
|
+
(key) => `${sqlString.escapeId(key[0])} AS ${sqlString.escapeId(key[1])}`,
|
|
79
79
|
)
|
|
80
80
|
.join(', ');
|
|
81
81
|
return `SELECT ${selectItem}`;
|
|
@@ -86,12 +86,48 @@ export function formatJoinClause(joinObject) {
|
|
|
86
86
|
.map(
|
|
87
87
|
(data) =>
|
|
88
88
|
`${data.type ? data.type + ' JOIN' : 'INNER JOIN'} ${sqlString.escapeId(
|
|
89
|
-
data.table
|
|
90
|
-
)} ON ${data.on}
|
|
89
|
+
data.table,
|
|
90
|
+
)} ON ${data.on}`,
|
|
91
91
|
)
|
|
92
92
|
.join(' ');
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
function degree2radian(angle) {
|
|
96
|
+
return (angle * Math.PI) / 180;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function radian2degree(angle) {
|
|
100
|
+
return (angle / Math.PI) * 180;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/*
|
|
104
|
+
* Search inside GPS coordinates boundary box
|
|
105
|
+
* Distance unit: meters
|
|
106
|
+
* */
|
|
107
|
+
export function formatWhereClauseBoundingBox(
|
|
108
|
+
latitudeDegree,
|
|
109
|
+
longitudeDegree,
|
|
110
|
+
boundingBoxSideMeters,
|
|
111
|
+
) {
|
|
112
|
+
const earthRadius = 6371000;
|
|
113
|
+
latitudeDegree = parseFloat(latitudeDegree);
|
|
114
|
+
longitudeDegree = parseFloat(longitudeDegree);
|
|
115
|
+
|
|
116
|
+
const latitudeRadian = degree2radian(latitudeDegree);
|
|
117
|
+
const radiusFromLatitude = Math.cos(latitudeRadian) * earthRadius;
|
|
118
|
+
|
|
119
|
+
// `boundingBoxSideMeters` is divided by 2 we are centering the coordinates in the middle of this square
|
|
120
|
+
const deltaLatitude = radian2degree(boundingBoxSideMeters / 2 / earthRadius);
|
|
121
|
+
const deltaLongitude = radian2degree(
|
|
122
|
+
boundingBoxSideMeters / 2 / radiusFromLatitude,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
let query = `stop_lat BETWEEN ${latitudeDegree - deltaLatitude} AND ${latitudeDegree + deltaLatitude}`;
|
|
126
|
+
query += ` AND stop_lon BETWEEN ${longitudeDegree - deltaLongitude} AND ${longitudeDegree + deltaLongitude}`;
|
|
127
|
+
|
|
128
|
+
return query;
|
|
129
|
+
}
|
|
130
|
+
|
|
95
131
|
export function formatWhereClause(key, value) {
|
|
96
132
|
if (Array.isArray(value)) {
|
|
97
133
|
let whereClause = `${sqlString.escapeId(key)} IN (${value
|
|
@@ -119,7 +155,7 @@ export function formatWhereClauses(query) {
|
|
|
119
155
|
}
|
|
120
156
|
|
|
121
157
|
const whereClauses = Object.entries(query).map(([key, value]) =>
|
|
122
|
-
formatWhereClause(key, value)
|
|
158
|
+
formatWhereClause(key, value),
|
|
123
159
|
);
|
|
124
160
|
return `WHERE ${whereClauses.join(' AND ')}`;
|
|
125
161
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const model = {
|
|
2
|
-
filenameBase: '
|
|
2
|
+
filenameBase: 'stop_time_updates',
|
|
3
3
|
extension: 'gtfs-realtime',
|
|
4
4
|
schema: [
|
|
5
5
|
{
|
|
@@ -9,6 +9,18 @@ const model = {
|
|
|
9
9
|
source: 'parent.tripUpdate.trip.tripId',
|
|
10
10
|
default: null,
|
|
11
11
|
},
|
|
12
|
+
{
|
|
13
|
+
name: 'trip_start_time',
|
|
14
|
+
type: 'varchar(255)',
|
|
15
|
+
source: 'parent.tripUpdate.trip.startTime',
|
|
16
|
+
default: null,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'direction_id',
|
|
20
|
+
type: 'integer',
|
|
21
|
+
source: 'parent.tripUpdate.trip.directionId',
|
|
22
|
+
default: null,
|
|
23
|
+
},
|
|
12
24
|
{
|
|
13
25
|
name: 'route_id',
|
|
14
26
|
type: 'varchar(255)',
|
|
@@ -54,7 +66,13 @@ const model = {
|
|
|
54
66
|
default: null,
|
|
55
67
|
},
|
|
56
68
|
{
|
|
57
|
-
name: '
|
|
69
|
+
name: 'schedule_relationship',
|
|
70
|
+
type: 'varchar(255)',
|
|
71
|
+
source: 'scheduleRelationship',
|
|
72
|
+
default: null,
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'is_updated',
|
|
58
76
|
type: 'integer',
|
|
59
77
|
required: true,
|
|
60
78
|
min: 0,
|
|
@@ -24,6 +24,25 @@ const model = {
|
|
|
24
24
|
source: 'tripUpdate.trip.tripId',
|
|
25
25
|
default: null,
|
|
26
26
|
},
|
|
27
|
+
{
|
|
28
|
+
name: 'trip_start_time',
|
|
29
|
+
type: 'varchar(255)',
|
|
30
|
+
source: 'tripUpdate.trip.startTime',
|
|
31
|
+
default: null,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'direction_id',
|
|
35
|
+
type: 'integer',
|
|
36
|
+
source: 'tripUpdate.trip.directionId',
|
|
37
|
+
default: null,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'route_id',
|
|
41
|
+
type: 'varchar(255)',
|
|
42
|
+
index: true,
|
|
43
|
+
source: 'tripUpdate.trip.routeId',
|
|
44
|
+
default: null,
|
|
45
|
+
},
|
|
27
46
|
{
|
|
28
47
|
name: 'start_date',
|
|
29
48
|
type: 'varchar(255)',
|
|
@@ -37,7 +56,13 @@ const model = {
|
|
|
37
56
|
default: null,
|
|
38
57
|
},
|
|
39
58
|
{
|
|
40
|
-
name: '
|
|
59
|
+
name: 'schedule_relationship',
|
|
60
|
+
type: 'varchar(255)',
|
|
61
|
+
source: 'tripUpdate.trip.scheduleRelationship',
|
|
62
|
+
default: null,
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'is_updated',
|
|
41
66
|
type: 'integer',
|
|
42
67
|
required: true,
|
|
43
68
|
min: 0,
|
package/models/models.js
CHANGED
|
@@ -40,7 +40,7 @@ import tripCapacity from '../models/gtfs-ride/trip-capacity.js';
|
|
|
40
40
|
import rideFeedInfo from './gtfs-ride/ride-feed-info.js';
|
|
41
41
|
|
|
42
42
|
import tripUpdates from './gtfs-realtime/trip-updates.js';
|
|
43
|
-
import
|
|
43
|
+
import stopTimeUpdates from './gtfs-realtime/stop-time-updates.js';
|
|
44
44
|
import vehiclePositions from './gtfs-realtime/vehicle-positions.js';
|
|
45
45
|
import serviceAlerts from './gtfs-realtime/service-alerts.js';
|
|
46
46
|
import serviceAlertTargets from './gtfs-realtime/service-alert-targets.js';
|
|
@@ -90,7 +90,7 @@ const models = [
|
|
|
90
90
|
ridership,
|
|
91
91
|
tripCapacity,
|
|
92
92
|
tripUpdates,
|
|
93
|
-
|
|
93
|
+
stopTimeUpdates,
|
|
94
94
|
vehiclePositions,
|
|
95
95
|
serviceAlerts,
|
|
96
96
|
serviceAlertTargets,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gtfs",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.7.0",
|
|
4
4
|
"description": "Import GTFS transit data into SQLite and query routes, stops, times, fares and more",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"transit",
|
|
@@ -58,7 +58,8 @@
|
|
|
58
58
|
"Daniel Sörlöv",
|
|
59
59
|
"Ali Zarghami <alizarghami@gmail.com>",
|
|
60
60
|
"David Abell",
|
|
61
|
-
"Matthias Feist <matze@matf.de>"
|
|
61
|
+
"Matthias Feist <matze@matf.de>",
|
|
62
|
+
"Oliv4945"
|
|
62
63
|
],
|
|
63
64
|
"type": "module",
|
|
64
65
|
"main": "index.js",
|
|
@@ -73,9 +74,9 @@
|
|
|
73
74
|
},
|
|
74
75
|
"dependencies": {
|
|
75
76
|
"@turf/helpers": "^6.5.0",
|
|
76
|
-
"better-sqlite3": "^9.
|
|
77
|
-
"csv-parse": "^5.5.
|
|
78
|
-
"csv-stringify": "^6.4.
|
|
77
|
+
"better-sqlite3": "^9.4.0",
|
|
78
|
+
"csv-parse": "^5.5.3",
|
|
79
|
+
"csv-stringify": "^6.4.5",
|
|
79
80
|
"gtfs-realtime-bindings": "^1.1.1",
|
|
80
81
|
"lodash-es": "^4.17.21",
|
|
81
82
|
"long": "^5.2.3",
|
|
@@ -94,10 +95,10 @@
|
|
|
94
95
|
"yoctocolors": "^1.0.0"
|
|
95
96
|
},
|
|
96
97
|
"devDependencies": {
|
|
97
|
-
"husky": "^
|
|
98
|
-
"lint-staged": "^15.
|
|
99
|
-
"mocha": "^10.
|
|
100
|
-
"prettier": "^3.
|
|
98
|
+
"husky": "^9.0.10",
|
|
99
|
+
"lint-staged": "^15.2.2",
|
|
100
|
+
"mocha": "^10.3.0",
|
|
101
|
+
"prettier": "^3.2.5",
|
|
101
102
|
"should": "^13.2.3"
|
|
102
103
|
},
|
|
103
104
|
"engines": {
|
|
@@ -64,4 +64,24 @@ describe('getStopsAsGeoJSON(): ', () => {
|
|
|
64
64
|
should.exist(geojson.features[0].geometry.coordinates);
|
|
65
65
|
geojson.features[0].geometry.coordinates.length.should.equal(2);
|
|
66
66
|
});
|
|
67
|
+
|
|
68
|
+
it('should return geojson with specific stops for bounding box query', () => {
|
|
69
|
+
const distance = 100;
|
|
70
|
+
const stopLatitude = 37.709538;
|
|
71
|
+
const stopLongitude = -122.401586;
|
|
72
|
+
|
|
73
|
+
const geojson = getStopsAsGeoJSON(
|
|
74
|
+
{
|
|
75
|
+
stop_lat: stopLatitude,
|
|
76
|
+
stop_lon: stopLongitude,
|
|
77
|
+
},
|
|
78
|
+
{ bounding_box_side_m: distance },
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
should.exist(geojson);
|
|
82
|
+
geojson.type.should.equal('FeatureCollection');
|
|
83
|
+
geojson.features.length.should.equal(2);
|
|
84
|
+
should.exist(geojson.features[0].geometry.coordinates);
|
|
85
|
+
geojson.features[0].geometry.coordinates.length.should.equal(2);
|
|
86
|
+
});
|
|
67
87
|
});
|
package/test/mocha/get-stops.js
CHANGED
|
@@ -92,7 +92,7 @@ describe('getStops():', () => {
|
|
|
92
92
|
route_id: routeId,
|
|
93
93
|
},
|
|
94
94
|
[],
|
|
95
|
-
[['stop_id', 'ASC']]
|
|
95
|
+
[['stop_id', 'ASC']],
|
|
96
96
|
);
|
|
97
97
|
|
|
98
98
|
const expectedStopIds = [
|
|
@@ -127,7 +127,7 @@ describe('getStops():', () => {
|
|
|
127
127
|
for (const [idx, stop] of results.entries()) {
|
|
128
128
|
expectedStopIds[idx].should.equal(
|
|
129
129
|
stop.stop_id,
|
|
130
|
-
'The order of stops are expected to be the same'
|
|
130
|
+
'The order of stops are expected to be the same',
|
|
131
131
|
);
|
|
132
132
|
}
|
|
133
133
|
});
|
|
@@ -142,7 +142,7 @@ describe('getStops():', () => {
|
|
|
142
142
|
direction_id: directionId,
|
|
143
143
|
},
|
|
144
144
|
[],
|
|
145
|
-
[['stop_id', 'ASC']]
|
|
145
|
+
[['stop_id', 'ASC']],
|
|
146
146
|
);
|
|
147
147
|
|
|
148
148
|
const expectedStopIds = [
|
|
@@ -165,7 +165,7 @@ describe('getStops():', () => {
|
|
|
165
165
|
for (const [idx, stop] of results.entries()) {
|
|
166
166
|
expectedStopIds[idx].should.equal(
|
|
167
167
|
stop.stop_id,
|
|
168
|
-
'The order of stops are expected to be the same'
|
|
168
|
+
'The order of stops are expected to be the same',
|
|
169
169
|
);
|
|
170
170
|
}
|
|
171
171
|
});
|
|
@@ -178,7 +178,7 @@ describe('getStops():', () => {
|
|
|
178
178
|
trip_id: tripId,
|
|
179
179
|
},
|
|
180
180
|
[],
|
|
181
|
-
[['stop_id', 'ASC']]
|
|
181
|
+
[['stop_id', 'ASC']],
|
|
182
182
|
);
|
|
183
183
|
|
|
184
184
|
const expectedStopIds = [
|
|
@@ -213,7 +213,7 @@ describe('getStops():', () => {
|
|
|
213
213
|
for (const [idx, stop] of results.entries()) {
|
|
214
214
|
expectedStopIds[idx].should.equal(
|
|
215
215
|
stop.stop_id,
|
|
216
|
-
'The order of stops are expected to be the same'
|
|
216
|
+
'The order of stops are expected to be the same',
|
|
217
217
|
);
|
|
218
218
|
}
|
|
219
219
|
});
|
|
@@ -226,7 +226,7 @@ describe('getStops():', () => {
|
|
|
226
226
|
shape_id: shapeId,
|
|
227
227
|
},
|
|
228
228
|
[],
|
|
229
|
-
[['stop_id', 'ASC']]
|
|
229
|
+
[['stop_id', 'ASC']],
|
|
230
230
|
);
|
|
231
231
|
|
|
232
232
|
const expectedStopIds = [
|
|
@@ -262,8 +262,82 @@ describe('getStops():', () => {
|
|
|
262
262
|
for (const [idx, stop] of results.entries()) {
|
|
263
263
|
expectedStopIds[idx].should.equal(
|
|
264
264
|
stop.stop_id,
|
|
265
|
-
'The order of stops are expected to be the same'
|
|
265
|
+
'The order of stops are expected to be the same',
|
|
266
266
|
);
|
|
267
267
|
}
|
|
268
268
|
});
|
|
269
|
+
|
|
270
|
+
it('should return array of stops for bounding box query', () => {
|
|
271
|
+
const distance = 100;
|
|
272
|
+
const stopLatitude = 37.709538;
|
|
273
|
+
const stopLongitude = -122.401586;
|
|
274
|
+
|
|
275
|
+
const results = getStops(
|
|
276
|
+
{
|
|
277
|
+
stop_lat: stopLatitude,
|
|
278
|
+
stop_lon: stopLongitude,
|
|
279
|
+
},
|
|
280
|
+
[],
|
|
281
|
+
[],
|
|
282
|
+
{ bounding_box_side_m: distance },
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
const expectedResult = [
|
|
286
|
+
{
|
|
287
|
+
stop_id: 'ctba',
|
|
288
|
+
stop_code: null,
|
|
289
|
+
stop_name: 'Bayshore Caltrain',
|
|
290
|
+
tts_stop_name: null,
|
|
291
|
+
stop_desc: null,
|
|
292
|
+
stop_lat: 37.709544,
|
|
293
|
+
stop_lon: -122.401318,
|
|
294
|
+
zone_id: null,
|
|
295
|
+
stop_url: 'http://www.caltrain.com/stations/bayshorestation.html',
|
|
296
|
+
location_type: 1,
|
|
297
|
+
parent_station: null,
|
|
298
|
+
stop_timezone: null,
|
|
299
|
+
wheelchair_boarding: 1,
|
|
300
|
+
level_id: null,
|
|
301
|
+
platform_code: null,
|
|
302
|
+
},
|
|
303
|
+
{
|
|
304
|
+
stop_id: '70032',
|
|
305
|
+
stop_code: '70032',
|
|
306
|
+
stop_name: 'Bayshore Caltrain',
|
|
307
|
+
tts_stop_name: null,
|
|
308
|
+
stop_desc: null,
|
|
309
|
+
stop_lat: 37.709544,
|
|
310
|
+
stop_lon: -122.40198,
|
|
311
|
+
zone_id: '1',
|
|
312
|
+
stop_url: 'http://www.caltrain.com/stations/bayshorestation.html',
|
|
313
|
+
location_type: 0,
|
|
314
|
+
parent_station: 'ctba',
|
|
315
|
+
stop_timezone: null,
|
|
316
|
+
wheelchair_boarding: 1,
|
|
317
|
+
level_id: null,
|
|
318
|
+
platform_code: 'SB',
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
stop_id: '70031',
|
|
322
|
+
stop_code: '70031',
|
|
323
|
+
stop_name: 'Bayshore Caltrain',
|
|
324
|
+
tts_stop_name: null,
|
|
325
|
+
stop_desc: null,
|
|
326
|
+
stop_lat: 37.709537,
|
|
327
|
+
stop_lon: -122.401586,
|
|
328
|
+
zone_id: '1',
|
|
329
|
+
stop_url: 'http://www.caltrain.com/stations/bayshorestation.html',
|
|
330
|
+
location_type: 0,
|
|
331
|
+
parent_station: 'ctba',
|
|
332
|
+
stop_timezone: null,
|
|
333
|
+
wheelchair_boarding: 1,
|
|
334
|
+
level_id: null,
|
|
335
|
+
platform_code: 'NB',
|
|
336
|
+
},
|
|
337
|
+
];
|
|
338
|
+
|
|
339
|
+
should.exist(results);
|
|
340
|
+
results.length.should.equal(3);
|
|
341
|
+
results.should.match(expectedResult);
|
|
342
|
+
});
|
|
269
343
|
});
|