gtfs 4.0.0 → 4.0.2

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 CHANGED
@@ -1,5 +1,7 @@
1
1
  import CsvParse = require('csv-parse');
2
2
 
3
+ import Database = require('better-sqlite3');
4
+
3
5
  import { FeatureCollection, Geometry } from '@turf/helpers';
4
6
 
5
7
  export {}; // disable implicit exporting of types
@@ -19,7 +21,7 @@ export type SqlSelect = string[];
19
21
 
20
22
  export type SqlOrderBy = Array<[string, 'ASC' | 'DESC']>;
21
23
 
22
- export type JoinTables = Array<JoinOptions>;
24
+ export type JoinTables = JoinOptions[];
23
25
 
24
26
  export type SqlResults = Array<Record<string, any>>;
25
27
 
@@ -29,25 +31,26 @@ export type SqlTableName = string;
29
31
 
30
32
  export type Config = ExportConfig & ImportConfig;
31
33
 
32
- export type AdvancedQueryOptions = {
34
+ export interface AdvancedQueryOptions {
33
35
  /**
34
- * An advanced query
36
+ * Queries the database with support for table joins and custom tables and returns an array of data.
35
37
  */
36
38
  query?: SqlWhere;
37
39
  fields?: SqlSelect;
38
40
  orderBy?: SqlOrderBy;
39
- join?: Array<JoinOptions>;
41
+ join?: JoinOptions[];
40
42
  options?: QueryOptions;
41
- };
43
+ }
42
44
 
43
- export type JoinOptions = {
45
+ export interface JoinOptions {
44
46
  /**
45
47
  * Options for joining, type
46
48
  */
47
49
  type?: 'LEFT OUTER' | 'INNER';
48
50
  table: string;
49
51
  on: string;
50
- };
52
+ }
53
+
51
54
  interface VerboseConfig {
52
55
  /**
53
56
  * Whether or not to print output to the console. Defaults to true.
@@ -57,7 +60,7 @@ interface VerboseConfig {
57
60
 
58
61
  export interface DbConfig {
59
62
  /**
60
- * A path to an SQLite database. Defaults to using an in-memory database.
63
+ * A path to a SQLite database. Defaults to using an in-memory database.
61
64
  */
62
65
  sqlitePath?: string;
63
66
  }
@@ -71,7 +74,7 @@ export interface ExportConfig extends DbConfig, VerboseConfig {
71
74
 
72
75
  export interface ImportConfig extends DbConfig, VerboseConfig {
73
76
  /**
74
- * An array of GTFS files to be imported.
77
+ * An array of agencies with GTFS files to be imported.
75
78
  */
76
79
  agencies: Array<{
77
80
  /**
@@ -114,11 +117,11 @@ export interface ImportConfig extends DbConfig, VerboseConfig {
114
117
  }
115
118
 
116
119
  export interface QueryOptions {
117
- db?: SqlDatabase;
120
+ db?: Database.Database;
118
121
  }
119
122
 
120
123
  /**
121
- * Use exportGtfs() in your code to run an export of a GTFS file specified in a config.json file.
124
+ * Use exportGtfs() in your code to run an export of a GTFS from SQLite specified in a config.json file.
122
125
  */
123
126
  export function exportGtfs(config: ExportConfig): Promise<void>;
124
127
 
@@ -133,17 +136,17 @@ export function importGtfs(config: ImportConfig): Promise<void>;
133
136
  export function updateGtfsRealtime(config: ImportConfig): Promise<void>;
134
137
 
135
138
  /**
136
- * Open database before making any queries.
139
+ * Opens the database specified in the config object.
137
140
  */
138
- export function openDb(config: DbConfig): Promise<SqlDatabase>;
141
+ export function openDb(config: DbConfig): Database.Database;
139
142
 
140
143
  /**
141
- * Closes open database.
144
+ * Closes the specified database.
142
145
  */
143
- export function closeDb(db?: SqlDatabase): Promise<void>;
146
+ export function closeDb(db?: Database.Database): void;
144
147
 
145
148
  /**
146
- * Queries agencies and returns a promise for an array of agencies.
149
+ * Returns an array of agencies that match query parameters.
147
150
  */
148
151
  export function getAgencies(
149
152
  query?: SqlWhere,
@@ -153,7 +156,17 @@ export function getAgencies(
153
156
  ): SqlResults;
154
157
 
155
158
  /**
156
- * Queries attributions and returns a promise for an array of attributions.
159
+ * Returns an array of areas that match query parameters.
160
+ */
161
+ export function getAreas(
162
+ query?: SqlWhere,
163
+ fields?: SqlSelect,
164
+ sortBy?: SqlOrderBy,
165
+ options?: QueryOptions
166
+ ): SqlResults;
167
+
168
+ /**
169
+ * Returns an array of attributions that match query parameters.
157
170
  */
158
171
  export function getAttributions(
159
172
  query?: SqlWhere,
@@ -163,7 +176,7 @@ export function getAttributions(
163
176
  ): SqlResults;
164
177
 
165
178
  /**
166
- * Queries routes and returns a promise for an array of routes.
179
+ * Returns an array of routes that match query parameters.
167
180
  */
168
181
  export function getRoutes(
169
182
  query?: SqlWhere,
@@ -173,7 +186,7 @@ export function getRoutes(
173
186
  ): SqlResults;
174
187
 
175
188
  /**
176
- * Queries stops and returns a promise for an array of stops.
189
+ * Returns an array of stops that match query parameters.
177
190
  */
178
191
  export function getStops(
179
192
  query?: SqlWhere,
@@ -183,7 +196,7 @@ export function getStops(
183
196
  ): SqlResults;
184
197
 
185
198
  /**
186
- * Queries stops and returns a promise for an geoJSON object of stops.
199
+ * Returns geoJSON object of stops that match query parameters.
187
200
  * All valid queries for `getStops()` work for `getStopsAsGeoJSON()`.
188
201
  */
189
202
  export function getStopsAsGeoJSON(
@@ -192,7 +205,7 @@ export function getStopsAsGeoJSON(
192
205
  ): Promise<FeatureCollection<Geometry, { [name: string]: any }>>;
193
206
 
194
207
  /**
195
- * Queries `stop_times` and returns a promise for an array of stop_times.
208
+ * Returns an array of stop_times that match query parameters.
196
209
  */
197
210
  export function getStoptimes(
198
211
  query?: SqlWhere,
@@ -202,7 +215,7 @@ export function getStoptimes(
202
215
  ): SqlResults;
203
216
 
204
217
  /**
205
- * Queries trips and returns a promise for an array of trips.
218
+ * Returns an array of trips that match query parameters.
206
219
  */
207
220
  export function getTrips(
208
221
  query?: SqlWhere,
@@ -212,7 +225,7 @@ export function getTrips(
212
225
  ): SqlResults;
213
226
 
214
227
  /**
215
- * Queries shapes and returns a promise for an array of shapes.
228
+ * Returns an array of shapes that match query parameters.
216
229
  */
217
230
  export function getShapes(
218
231
  query?: SqlWhere,
@@ -222,16 +235,16 @@ export function getShapes(
222
235
  ): SqlResults;
223
236
 
224
237
  /**
225
- * Queries shapes and returns a promise for an geoJSON object of shapes.
238
+ * Returns a geoJSON object of shapes that match query parameters.
226
239
  * All valid queries for `getShapes()` work for `getShapesAsGeoJSON()`.
227
240
  */
228
241
  export function getShapesAsGeoJSON(
229
242
  query?: SqlWhere,
230
243
  options?: QueryOptions
231
- ): Promise<FeatureCollection<Geometry, { [name: string]: any }>>;
244
+ ): FeatureCollection<Geometry, { [name: string]: any }>;
232
245
 
233
246
  /**
234
- * Queries calendars and returns a promise for an array of calendars.
247
+ * Returns an array of calendars that match query parameters.
235
248
  */
236
249
  export function getCalendars(
237
250
  query?: SqlWhere,
@@ -241,7 +254,7 @@ export function getCalendars(
241
254
  ): SqlResults;
242
255
 
243
256
  /**
244
- * Queries calendar_dates and returns a promise for an array of calendar_dates.
257
+ * Returns an array of calendar_dates that match query parameters.
245
258
  */
246
259
  export function getCalendarDates(
247
260
  query?: SqlWhere,
@@ -251,7 +264,7 @@ export function getCalendarDates(
251
264
  ): SqlResults;
252
265
 
253
266
  /**
254
- * Queries fare_attributes and returns a promise for an array of fare_attributes.
267
+ * Returns an array of fare_attributes that match query parameters.
255
268
  */
256
269
  export function getFareAttributes(
257
270
  query?: SqlWhere,
@@ -261,9 +274,9 @@ export function getFareAttributes(
261
274
  ): SqlResults;
262
275
 
263
276
  /**
264
- * Queries fare_rules and returns a promise for an array of fare_rules.
277
+ * Returns an array of fare_leg_rules that match query parameters.
265
278
  */
266
- export function getFareRules(
279
+ export function getFareLegRules(
267
280
  query?: SqlWhere,
268
281
  fields?: SqlSelect,
269
282
  sortBy?: SqlOrderBy,
@@ -271,9 +284,9 @@ export function getFareRules(
271
284
  ): SqlResults;
272
285
 
273
286
  /**
274
- * Queries feed_info and returns a promise for an array of feed_infos.
287
+ * Returns an array of fare_products that match query parameters.
275
288
  */
276
- export function getFeedInfo(
289
+ export function getFareProducts(
277
290
  query?: SqlWhere,
278
291
  fields?: SqlSelect,
279
292
  sortBy?: SqlOrderBy,
@@ -281,9 +294,9 @@ export function getFeedInfo(
281
294
  ): SqlResults;
282
295
 
283
296
  /**
284
- * Queries frequencies and returns a promise for an array of frequencies.
297
+ * Returns an array of fare_rules that match query parameters.
285
298
  */
286
- export function getFrequencies(
299
+ export function getFareRules(
287
300
  query?: SqlWhere,
288
301
  fields?: SqlSelect,
289
302
  sortBy?: SqlOrderBy,
@@ -291,9 +304,9 @@ export function getFrequencies(
291
304
  ): SqlResults;
292
305
 
293
306
  /**
294
- * Queries levels and returns a promise for an array of levels.
307
+ * Returns an array of fare_transfer_rules that match query parameters.
295
308
  */
296
- export function getLevels(
309
+ export function getFareTransferRules(
297
310
  query?: SqlWhere,
298
311
  fields?: SqlSelect,
299
312
  sortBy?: SqlOrderBy,
@@ -301,9 +314,9 @@ export function getLevels(
301
314
  ): SqlResults;
302
315
 
303
316
  /**
304
- * Queries pathways and returns a promise for an array of pathways.
317
+ * Returns an array of feed_info that match query parameters.
305
318
  */
306
- export function getPathways(
319
+ export function getFeedInfo(
307
320
  query?: SqlWhere,
308
321
  fields?: SqlSelect,
309
322
  sortBy?: SqlOrderBy,
@@ -311,9 +324,9 @@ export function getPathways(
311
324
  ): SqlResults;
312
325
 
313
326
  /**
314
- * Queries transfers and returns a promise for an array of transfers.
327
+ * Returns an array of frequencies that match query parameters.
315
328
  */
316
- export function getTransfers(
329
+ export function getFrequencies(
317
330
  query?: SqlWhere,
318
331
  fields?: SqlSelect,
319
332
  sortBy?: SqlOrderBy,
@@ -321,9 +334,9 @@ export function getTransfers(
321
334
  ): SqlResults;
322
335
 
323
336
  /**
324
- * Queries translations and returns a promise for an array of translations.
337
+ * Returns an array of levels that match query parameters.
325
338
  */
326
- export function getTranslations(
339
+ export function getLevels(
327
340
  query?: SqlWhere,
328
341
  fields?: SqlSelect,
329
342
  sortBy?: SqlOrderBy,
@@ -331,10 +344,9 @@ export function getTranslations(
331
344
  ): SqlResults;
332
345
 
333
346
  /**
334
- * Queries directions and returns a promise for an array of directions.
335
- * These are from the non-standard `directions.txt` file.
347
+ * Returns an array of pathways that match query parameters.
336
348
  */
337
- export function getDirections(
349
+ export function getPathways(
338
350
  query?: SqlWhere,
339
351
  fields?: SqlSelect,
340
352
  sortBy?: SqlOrderBy,
@@ -342,10 +354,9 @@ export function getDirections(
342
354
  ): SqlResults;
343
355
 
344
356
  /**
345
- * Queries stop_attributes and returns a promise for an array of stop_attributes.
346
- * These are from the non-standard `stop_attributes.txt` file.
357
+ * Returns an array of transfers that match query parameters.
347
358
  */
348
- export function getStopAttributes(
359
+ export function getTransfers(
349
360
  query?: SqlWhere,
350
361
  fields?: SqlSelect,
351
362
  sortBy?: SqlOrderBy,
@@ -353,10 +364,9 @@ export function getStopAttributes(
353
364
  ): SqlResults;
354
365
 
355
366
  /**
356
- * Queries timetables and returns a promise for an array of timetables.
357
- * These are from the non-standard `timetables.txt` file.
367
+ * Returns an array of translations that match query parameters.
358
368
  */
359
- export function getTimetables(
369
+ export function getTranslations(
360
370
  query?: SqlWhere,
361
371
  fields?: SqlSelect,
362
372
  sortBy?: SqlOrderBy,
@@ -364,10 +374,9 @@ export function getTimetables(
364
374
  ): SqlResults;
365
375
 
366
376
  /**
367
- * Queries timetable_stop_orders and returns a promise for an array of timetable_stop_orders.
368
- * These are from the non-standard `timetable_stop_order.txt` file.
377
+ * Returns an array of stop_areas that match query parameters.
369
378
  */
370
- export function getTimetableStopOrders(
379
+ export function getStopAreas(
371
380
  query?: SqlWhere,
372
381
  fields?: SqlSelect,
373
382
  sortBy?: SqlOrderBy,
@@ -375,10 +384,10 @@ export function getTimetableStopOrders(
375
384
  ): SqlResults;
376
385
 
377
386
  /**
378
- * Queries timetable_pages and returns a promise for an array of timetable_pages.
379
- * These are from the non-standard `timetable_pages.txt` file.
387
+ * Returns an array of directions that match query parameters.
388
+ * This is for the non-standard `directions.txt` file.
380
389
  */
381
- export function getTimetablePages(
390
+ export function getDirections(
382
391
  query?: SqlWhere,
383
392
  fields?: SqlSelect,
384
393
  sortBy?: SqlOrderBy,
@@ -386,10 +395,10 @@ export function getTimetablePages(
386
395
  ): SqlResults;
387
396
 
388
397
  /**
389
- * Queries timetable_notes and returns a promise for an array of timetable_notes.
390
- * These are from the non-standard `timetable_notes.txt` file.
398
+ * Returns an array of stop_attributes that match query parameters.
399
+ * This is for the non-standard `stop_attributes.txt` file.
391
400
  */
392
- export function getTimetableNotes(
401
+ export function getStopAttributes(
393
402
  query?: SqlWhere,
394
403
  fields?: SqlSelect,
395
404
  sortBy?: SqlOrderBy,
@@ -397,10 +406,10 @@ export function getTimetableNotes(
397
406
  ): SqlResults;
398
407
 
399
408
  /**
400
- * Queries timetable_notes_references and returns a promise for an array of timetable_notes references.
401
- * These are from the non-standard `timetable_notes_references.txt` file.
409
+ * Returns an array of timetables that match query parameters.
410
+ * This is for the non-standard `timetables.txt` file used in GTFS-to-HTML.
402
411
  */
403
- export function getTimetableNotesReferences(
412
+ export function getTimetables(
404
413
  query?: SqlWhere,
405
414
  fields?: SqlSelect,
406
415
  sortBy?: SqlOrderBy,
@@ -408,9 +417,10 @@ export function getTimetableNotesReferences(
408
417
  ): SqlResults;
409
418
 
410
419
  /**
411
- * Queries board-alights and returns a promise for an array of board-alights.
420
+ * Returns an array of timetable_stop_orders that match query parameters.
421
+ * This is for the non-standard `timetable_stop_order.txt` file used in GTFS-to-HTML.
412
422
  */
413
- export function getBoardAlights(
423
+ export function getTimetableStopOrders(
414
424
  query?: SqlWhere,
415
425
  fields?: SqlSelect,
416
426
  sortBy?: SqlOrderBy,
@@ -418,9 +428,10 @@ export function getBoardAlights(
418
428
  ): SqlResults;
419
429
 
420
430
  /**
421
- * Queries ride-feed-info and returns a promise for an array of ride-feed-info.
431
+ * Returns an array of timetable_pages that match query parameters.
432
+ * This is for the non-standard `timetable_pages.txt` file used in GTFS-to-HTML.
422
433
  */
423
- export function getRideFeedInfos(
434
+ export function getTimetablePages(
424
435
  query?: SqlWhere,
425
436
  fields?: SqlSelect,
426
437
  sortBy?: SqlOrderBy,
@@ -428,9 +439,10 @@ export function getRideFeedInfos(
428
439
  ): SqlResults;
429
440
 
430
441
  /**
431
- * Queries rider trips and returns a promise for an array of rider trips.
442
+ * Returns an array of timetable_notes that match query parameters.
443
+ * This is for the non-standard `timetable_notes.txt` file used in GTFS-to-HTML.
432
444
  */
433
- export function getRiderTrips(
445
+ export function getTimetableNotes(
434
446
  query?: SqlWhere,
435
447
  fields?: SqlSelect,
436
448
  sortBy?: SqlOrderBy,
@@ -438,9 +450,10 @@ export function getRiderTrips(
438
450
  ): SqlResults;
439
451
 
440
452
  /**
441
- * Queries riderships and returns a promise for an array of riderships.
453
+ * Returns an array of timetable_notes_references that match query parameters.
454
+ * This is for the non-standard `timetable_notes_references.txt` file used in GTFS-to-HTML.
442
455
  */
443
- export function getRiderships(
456
+ export function getTimetableNotesReferences(
444
457
  query?: SqlWhere,
445
458
  fields?: SqlSelect,
446
459
  sortBy?: SqlOrderBy,
@@ -448,9 +461,10 @@ export function getRiderships(
448
461
  ): SqlResults;
449
462
 
450
463
  /**
451
- * Queries trip-capacities and returns a promise for an array of trip-capacities.
464
+ * Returns an array of trips_dated_vehicle_journey that match query parameters.
465
+ * This is for the non-standard `trips_dated_vehicle_journey.txt` file.
452
466
  */
453
- export function getTripCapacities(
467
+ export function getTripsDatedVehicleJourneys(
454
468
  query?: SqlWhere,
455
469
  fields?: SqlSelect,
456
470
  sortBy?: SqlOrderBy,
@@ -458,7 +472,8 @@ export function getTripCapacities(
458
472
  ): SqlResults;
459
473
 
460
474
  /**
461
- * Queries trip-capacities and returns a promise for an array of service-alerts.
475
+ * Returns an array of GTFS Realtime service alerts that match query parameters.
476
+ * This only works if you configure GTFS Realtime import in node-gtfs.
462
477
  */
463
478
  export function getServiceAlerts(
464
479
  query?: SqlWhere,
@@ -468,7 +483,8 @@ export function getServiceAlerts(
468
483
  ): SqlResults;
469
484
 
470
485
  /**
471
- * Queries trip-capacities and returns a promise for an array of trip-updates.
486
+ * Returns an array of GTFS Realtime trip updates that match query parameters.
487
+ * This only works if you configure GTFS Realtime import in node-gtfs.
472
488
  */
473
489
  export function getTripUpdates(
474
490
  query?: SqlWhere,
@@ -478,9 +494,10 @@ export function getTripUpdates(
478
494
  ): SqlResults;
479
495
 
480
496
  /**
481
- * Queries trip-capacities and returns a promise for an array of vehicle-positions.
497
+ * Returns an array of GTFS Realtime stop time updates that match query parameters.
498
+ * This only works if you configure GTFS Realtime import in node-gtfs.
482
499
  */
483
- export function getVehiclePositions(
500
+ export function getStopTimesUpdates(
484
501
  query?: SqlWhere,
485
502
  fields?: SqlSelect,
486
503
  sortBy?: SqlOrderBy,
@@ -488,9 +505,10 @@ export function getVehiclePositions(
488
505
  ): SqlResults;
489
506
 
490
507
  /**
491
- * Queries trip-capacities and returns a promise for an array of stop-times-updates.
508
+ * Returns an array of GTFS Realtime vehicle positions that match query parameters.
509
+ * This only works if you configure GTFS Realtime import in node-gtfs.
492
510
  */
493
- export function getStopTimesUpdates(
511
+ export function getVehiclePositions(
494
512
  query?: SqlWhere,
495
513
  fields?: SqlSelect,
496
514
  sortBy?: SqlOrderBy,
package/@types/tests.ts CHANGED
@@ -22,7 +22,7 @@ import {
22
22
 
23
23
  await exportGtfs(config); // $ExpectType void
24
24
 
25
- openDb(config); // $ExpectType Database<Database, Statement>
25
+ openDb(config); // $ExpectType Database
26
26
 
27
27
  const results = getAgencies();
28
28
  results[0]; // $ExpectType Record<string, any>
package/CHANGELOG.md CHANGED
@@ -5,6 +5,24 @@ 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.0.2] - 2023-01-15
9
+
10
+ ### Changed
11
+
12
+ - In getStopsAsGeoJSON only return stops that are part of a route.
13
+
14
+ ### Updated
15
+
16
+ - Dependency updates
17
+
18
+ ## [4.0.1] - 2022-12-31
19
+
20
+ ### Updated
21
+
22
+ - Update types info
23
+ - Improved readme
24
+ - Improved queries
25
+
8
26
  ## [4.0.0] - 2022-12-30
9
27
 
10
28
  ### Changed
package/README.md CHANGED
@@ -688,7 +688,7 @@ const stops = getStops({
688
688
  });
689
689
  ```
690
690
 
691
- ### getStopsAsGeoJSON(query)
691
+ ### getStopsAsGeoJSON(query, options)
692
692
 
693
693
  Returns geoJSON object of stops that match query parameters. All valid queries for `getStops()` work for `getStopsAsGeoJSON()`.
694
694
 
@@ -800,7 +800,7 @@ const shapes = getShapes({
800
800
  });
801
801
  ```
802
802
 
803
- ### getShapesAsGeoJSON(query)
803
+ ### getShapesAsGeoJSON(query, options)
804
804
 
805
805
  Returns a geoJSON object of shapes that match query parameters. All valid queries for `getShapes()` work for `getShapesAsGeoJSON()`.
806
806
 
@@ -1237,23 +1237,24 @@ import { openDb } from 'gtfs';
1237
1237
  const db = openDb(config);
1238
1238
 
1239
1239
  // Get a specific trip
1240
- const statement = db.prepare('SELECT * FROM trips WHERE trip_id = ?');
1241
- const trip = statement.get('123');
1240
+ const trip = db.prepare('SELECT * FROM trips WHERE trip_id = ?').get('123');
1242
1241
 
1243
1242
  // Get all stops
1244
1243
  const stops = db.prepare('SELECT * from stops').all();
1245
1244
 
1246
1245
  // Get all calendar_ids for specific date
1247
- const statement = db.prepare(
1248
- 'SELECT service_id from calendar WHERE start_date <= $date AND end_date >= $date'
1249
- );
1250
- const calendarIds = statement.all({ date: 20150101 });
1246
+ const calendarIds = db
1247
+ .prepare(
1248
+ 'SELECT service_id from calendar WHERE start_date <= $date AND end_date >= $date'
1249
+ )
1250
+ .all({ date: 20150101 });
1251
1251
 
1252
1252
  // Find all stops for route_id=18 by joining tables
1253
- const statement = db.prepare(
1254
- 'SELECT DISTINCT stops.stop_id from stops INNER JOIN stop_times ON stops.stop_id = stop_times.stop_id INNER JOIN trips on trips.trip_id = stop_times.trip_id WHERE trips.route_id = ?'
1255
- );
1256
- const calendarIds = statement.all('18');
1253
+ const stopIds = db
1254
+ .prepare(
1255
+ 'SELECT DISTINCT stops.stop_id from stops INNER JOIN stop_times ON stops.stop_id = stop_times.stop_id INNER JOIN trips on trips.trip_id = stop_times.trip_id WHERE trips.route_id = ?'
1256
+ )
1257
+ .all('18');
1257
1258
 
1258
1259
  // Execute raw SQL
1259
1260
  const sql = "DELETE FROM trips where trip_id = '329'";
@@ -1,28 +1,16 @@
1
1
  {
2
2
  "agencies": [
3
3
  {
4
- "url": "http://www.bart.gov/dev/schedules/google_transit.zip",
5
- "exclude": ["shapes"],
4
+ "url": "https://marintransit.org/data/google_transit.zip",
6
5
  "realtimeUrls": [
7
- "https://opendata.samtrafiken.se/gtfs-rt/sl/TripUpdates.pb?key=yourkey",
8
- "https://opendata.samtrafiken.se/gtfs-rt/sl/VehiclePositions.pb?key=yourkey",
9
- "https://opendata.samtrafiken.se/gtfs-rt/sl/ServiceAlerts.pb?key=yourkey"
10
- ],
11
- "realtimeHeaders": {
12
- "X-CustomHeader": "MyCustomHeader"
13
- },
14
- "headers": {
15
- "X-CustomHeader": "MyCustomHeader"
16
- }
17
- },
18
- {
19
- "path": "/path/to/gtfs.zip",
20
- "exclude": ["stop_times", "shapes"]
6
+ "https://marintransit.net/gtfs-rt/alerts",
7
+ "https://marintransit.net/gtfs-rt/tripupdates",
8
+ "https://marintransit.net/gtfs-rt/vehiclepositions"
9
+ ]
21
10
  }
22
11
  ],
23
12
  "csvOptions": {
24
13
  "skip_lines_with_error": true
25
14
  },
26
- "sqlitePath": "/tmp/gtfs",
27
- "exportPath": "~/path/to/export/gtfs"
15
+ "sqlitePath": "/tmp/gtfs"
28
16
  }
package/lib/db.js CHANGED
@@ -27,6 +27,12 @@ export function openDb(config) {
27
27
  return dbs[filename];
28
28
  }
29
29
 
30
+ if (Object.keys(dbs).length > 1) {
31
+ throw new Error(
32
+ 'Multiple databases open, please specify which one to use.'
33
+ );
34
+ }
35
+
30
36
  throw new Error('Unable to find database connection.');
31
37
  }
32
38
 
package/lib/gtfs/stops.js CHANGED
@@ -87,7 +87,7 @@ export function getStopsAsGeoJSON(query = {}, options = {}) {
87
87
  'SELECT DISTINCT route_id FROM trips WHERE trip_id IN (SELECT DISTINCT trip_id FROM stop_times WHERE stop_id = ?)';
88
88
  const routes = db
89
89
  .prepare(`SELECT * FROM routes WHERE route_id IN (${routeSubquery})`)
90
- .run(stop.stop_id);
90
+ .all(stop.stop_id);
91
91
 
92
92
  stop.routes = orderBy(routes, (route) =>
93
93
  Number.parseInt(route.route_short_name, 10)
@@ -97,5 +97,8 @@ export function getStopsAsGeoJSON(query = {}, options = {}) {
97
97
  return stop;
98
98
  });
99
99
 
100
- return stopsToGeoJSON(preparedStops);
100
+ // Exclude stops not part of any route
101
+ const filteredStops = preparedStops.filter((stop) => stop.routes.length > 0);
102
+
103
+ return stopsToGeoJSON(filteredStops);
101
104
  }
package/lib/import.js CHANGED
@@ -82,76 +82,33 @@ function getDescendantProp(obj, desc, defaultvalue) {
82
82
  return obj;
83
83
  }
84
84
 
85
- const markRealtimeDataStale = (db, log) => {
86
- const vehiclePositionModel = models.find(
87
- (x) => x.filenameBase === 'vehicle_positions'
88
- );
89
- const tripUpdatesModel = models.find(
90
- (x) => x.filenameBase === 'trip_updates'
91
- );
92
- const stopTimesUpdatesModel = models.find(
93
- (x) => x.filenameBase === 'stop_times_updates'
94
- );
95
- const serviceAlertsModel = models.find(
96
- (x) => x.filenameBase === 'service_alerts'
97
- );
98
- const serviceAlertTargetsModel = models.find(
99
- (x) => x.filenameBase === 'service_alert_targets'
100
- );
85
+ const markRealtimeDataStale = (config, log) => {
86
+ const db = openDb(config);
101
87
 
102
- // Mark all data as stale
103
88
  log(`Marking GTFS-Realtime data as stale..`);
104
- db.prepare(
105
- `UPDATE ${vehiclePositionModel.filenameBase} SET isUpdated=0`
106
- ).run();
107
- db.prepare(`UPDATE ${tripUpdatesModel.filenameBase} SET isUpdated=0`).run();
108
- db.prepare(
109
- `UPDATE ${stopTimesUpdatesModel.filenameBase} SET isUpdated=0`
110
- ).run();
111
- db.prepare(`UPDATE ${serviceAlertsModel.filenameBase} SET isUpdated=0`).run();
112
- db.prepare(
113
- `UPDATE ${serviceAlertTargetsModel.filenameBase} SET isUpdated=0`
114
- ).run();
89
+ db.prepare(`UPDATE vehicle_positions SET isUpdated=0`).run();
90
+ db.prepare(`UPDATE trip_updates SET isUpdated=0`).run();
91
+ db.prepare(`UPDATE stop_times_updates SET isUpdated=0`).run();
92
+ db.prepare(`UPDATE service_alerts SET isUpdated=0`).run();
93
+ db.prepare(`UPDATE service_alert_targets SET isUpdated=0`).run();
115
94
  log(`Marked GTFS-Realtime data as stale\r`, true);
116
95
  };
117
96
 
118
- const cleanStaleRealtimeData = (db, log) => {
119
- const vehiclePositionModel = models.find(
120
- (x) => x.filenameBase === 'vehicle_positions'
121
- );
122
- const tripUpdatesModel = models.find(
123
- (x) => x.filenameBase === 'trip_updates'
124
- );
125
- const stopTimesUpdatesModel = models.find(
126
- (x) => x.filenameBase === 'stop_times_updates'
127
- );
128
- const serviceAlertsModel = models.find(
129
- (x) => x.filenameBase === 'service_alerts'
130
- );
131
- const serviceAlertTargetsModel = models.find(
132
- (x) => x.filenameBase === 'service_alert_targets'
133
- );
97
+ const cleanStaleRealtimeData = (config, log) => {
98
+ const db = openDb(config);
134
99
 
135
100
  log(`Cleaning stale GTFS-RT data..`);
136
- db.prepare(
137
- `DELETE FROM ${vehiclePositionModel.filenameBase} WHERE isUpdated=0`
138
- ).run();
139
- db.prepare(
140
- `DELETE FROM ${tripUpdatesModel.filenameBase} WHERE isUpdated=0`
141
- ).run();
142
- db.prepare(
143
- `DELETE FROM ${stopTimesUpdatesModel.filenameBase} WHERE isUpdated=0`
144
- ).run();
145
- db.prepare(
146
- `DELETE FROM ${serviceAlertsModel.filenameBase} WHERE isUpdated=0`
147
- ).run();
148
- db.prepare(
149
- `DELETE FROM ${serviceAlertTargetsModel.filenameBase} WHERE isUpdated=0`
150
- ).run();
101
+ db.prepare(`DELETE FROM vehicle_positions WHERE isUpdated=0`).run();
102
+ db.prepare(`DELETE FROM trip_updates WHERE isUpdated=0`).run();
103
+ db.prepare(`DELETE FROM stop_times_updates WHERE isUpdated=0`).run();
104
+ db.prepare(`DELETE FROM service_alerts WHERE isUpdated=0`).run();
105
+ db.prepare(`DELETE FROM service_alert_targets WHERE isUpdated=0`).run();
151
106
  log(`Cleaned stale GTFS-Realtime data\r`, true);
152
107
  };
153
108
 
154
109
  const updateRealtimeData = async (task) => {
110
+ const db = openDb(task);
111
+
155
112
  const model = {
156
113
  vehicle_positions: models.find(
157
114
  (x) => x.filenameBase === 'vehicle_positions'
@@ -225,13 +182,11 @@ const updateRealtimeData = async (task) => {
225
182
  );
226
183
 
227
184
  try {
228
- task.db
229
- .prepare(
230
- `REPLACE INTO ${model[gtfsRealtimeType].filenameBase} (${
231
- fields[gtfsRealtimeType]
232
- }) VALUES (${fieldValues.join(', ')})`
233
- )
234
- .run();
185
+ db.prepare(
186
+ `REPLACE INTO ${model[gtfsRealtimeType].filenameBase} (${
187
+ fields[gtfsRealtimeType]
188
+ }) VALUES (${fieldValues.join(', ')})`
189
+ ).run();
235
190
  } catch (error) {
236
191
  task.warn('Import error: ' + error.message);
237
192
  }
@@ -251,13 +206,11 @@ const updateRealtimeData = async (task) => {
251
206
  }
252
207
 
253
208
  try {
254
- task.db
255
- .prepare(
256
- `REPLACE INTO ${model.stop_times_updates.filenameBase} (${
257
- fields.stop_times_updates
258
- }) VALUES ${stopUpdateArray.join(', ')}`
259
- )
260
- .run();
209
+ db.prepare(
210
+ `REPLACE INTO ${model.stop_times_updates.filenameBase} (${
211
+ fields.stop_times_updates
212
+ }) VALUES ${stopUpdateArray.join(', ')}`
213
+ ).run();
261
214
  } catch (error) {
262
215
  task.warn('Import error: ' + error.message);
263
216
  }
@@ -278,13 +231,11 @@ const updateRealtimeData = async (task) => {
278
231
  }
279
232
 
280
233
  try {
281
- task.db
282
- .prepare(
283
- `REPLACE INTO ${model.service_alert_targets.filenameBase} (${
284
- fields.service_alert_targets
285
- }) VALUES ${alertTargetArray.join(', ')}`
286
- )
287
- .run();
234
+ db.prepare(
235
+ `REPLACE INTO ${model.service_alert_targets.filenameBase} (${
236
+ fields.service_alert_targets
237
+ }) VALUES ${alertTargetArray.join(', ')}`
238
+ ).run();
288
239
  } catch (error) {
289
240
  task.warn('Import error: ' + error.message);
290
241
  }
@@ -478,6 +429,8 @@ const formatLine = (line, model, totalLineCount) => {
478
429
  };
479
430
 
480
431
  const importLines = (task, lines, model, totalLineCount) => {
432
+ const db = openDb(task);
433
+
481
434
  if (lines.length === 0) {
482
435
  return;
483
436
  }
@@ -496,12 +449,11 @@ const importLines = (task, lines, model, totalLineCount) => {
496
449
  }
497
450
 
498
451
  try {
499
- const insert = task.db.prepare(
452
+ db.prepare(
500
453
  `INSERT ${task.ignoreDuplicates ? 'OR IGNORE' : ''} INTO ${
501
454
  model.filenameBase
502
455
  } (${fieldNames.join(', ')}) VALUES ${placeholders.join(',')}`
503
- );
504
- insert.run(...values);
456
+ ).run(...values);
505
457
  } catch (error) {
506
458
  task.warn(
507
459
  `Check ${model.filenameBase}.txt for invalid data between lines ${
@@ -625,16 +577,10 @@ export async function importGtfs(initialConfig) {
625
577
  path: agency.path,
626
578
  csvOptions: config.csvOptions || {},
627
579
  ignoreDuplicates: config.ignoreDuplicates,
628
- db,
629
- log(message, overwrite) {
630
- log(message, overwrite);
631
- },
632
- warn(message) {
633
- logWarning(message);
634
- },
635
- error(message) {
636
- logError(message);
637
- },
580
+ sqlitePath: config.sqlitePath,
581
+ log,
582
+ warn: logWarning,
583
+ error: logError,
638
584
  };
639
585
 
640
586
  if (task.agency_url) {
@@ -671,7 +617,49 @@ export async function updateGtfsRealtime(initialConfig) {
671
617
  const log = _log(config);
672
618
  const logError = _logError(config);
673
619
  const logWarning = _logWarning(config);
674
- const db = openDb(config).catch((error) => {
620
+
621
+ try {
622
+ openDb(config);
623
+
624
+ const agencyCount = config.agencies.length;
625
+ log(
626
+ `Starting GTFS-Realtime refresh for ${pluralize(
627
+ 'agencies',
628
+ agencyCount,
629
+ true
630
+ )} using SQLite database at ${config.sqlitePath}`
631
+ );
632
+
633
+ markRealtimeDataStale(config, log);
634
+
635
+ await Promise.all(
636
+ config.agencies.map(async (agency) => {
637
+ if (!agency.realtimeUrls) {
638
+ return;
639
+ }
640
+
641
+ const task = {
642
+ realtime_headers: agency.realtimeHeaders || false,
643
+ realtime_urls: agency.realtimeUrls || false,
644
+ sqlitePath: config.sqlitePath,
645
+ log,
646
+ warn: logWarning,
647
+ error: logError,
648
+ };
649
+
650
+ await updateRealtimeData(task);
651
+ })
652
+ );
653
+
654
+ cleanStaleRealtimeData(config, log);
655
+ log(
656
+ `Completed GTFS-Realtime refresh for ${pluralize(
657
+ 'agencies',
658
+ agencyCount,
659
+ true
660
+ )}\n`
661
+ );
662
+ } catch (error) {
675
663
  if (error instanceof Error && error.code === 'SQLITE_CANTOPEN') {
676
664
  logError(
677
665
  `Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
@@ -679,46 +667,5 @@ export async function updateGtfsRealtime(initialConfig) {
679
667
  }
680
668
 
681
669
  throw error;
682
- });
683
-
684
- const agencyCount = config.agencies.length;
685
- log(
686
- `Starting GTFS-Realtime refresh for ${pluralize(
687
- 'agencies',
688
- agencyCount,
689
- true
690
- )} using SQLite database at ${config.sqlitePath}`
691
- );
692
-
693
- await markRealtimeDataStale(db, log);
694
-
695
- await mapSeries(config.agencies, async (agency) => {
696
- const task = {
697
- realtime_headers: agency.realtimeHeaders || false,
698
- realtime_urls: agency.realtimeUrls || false,
699
- db,
700
- log(message, overwrite) {
701
- log(message, overwrite);
702
- },
703
- warn(message) {
704
- logWarning(message);
705
- },
706
- error(message) {
707
- logError(message);
708
- },
709
- };
710
-
711
- if (task.realtime_urls) {
712
- await updateRealtimeData(task);
713
- }
714
- });
715
-
716
- await cleanStaleRealtimeData(db, log);
717
- log(
718
- `Completed GTFS-Realtime refresh for ${pluralize(
719
- 'agencies',
720
- agencyCount,
721
- true
722
- )}\n`
723
- );
670
+ }
724
671
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gtfs",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "Import GTFS transit data into SQLite and query routes, stops, times, fares and more",
5
5
  "keywords": [
6
6
  "transit",
@@ -95,13 +95,14 @@
95
95
  "yoctocolors": "^1.0.0"
96
96
  },
97
97
  "devDependencies": {
98
+ "@types/better-sqlite3": "^7.6.3",
98
99
  "dtslint": "^4.2.1",
99
- "eslint": "^8.30.0",
100
- "eslint-config-prettier": "^8.5.0",
100
+ "eslint": "^8.32.0",
101
+ "eslint-config-prettier": "^8.6.0",
101
102
  "eslint-config-xo": "^0.43.1",
102
- "husky": "^8.0.2",
103
+ "husky": "^8.0.3",
103
104
  "mocha": "^10.2.0",
104
- "prettier": "^2.8.1",
105
+ "prettier": "^2.8.3",
105
106
  "pretty-quick": "^3.1.3",
106
107
  "should": "^13.2.3"
107
108
  },