gtfs 4.15.2 → 4.15.4
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/README.md +54 -22
- package/dist/bin/gtfs-export.js +18 -10
- package/dist/bin/gtfs-export.js.map +1 -1
- package/dist/bin/gtfs-import.js +20 -25
- package/dist/bin/gtfs-import.js.map +1 -1
- package/dist/bin/gtfsrealtime-update.js +18 -21
- package/dist/bin/gtfsrealtime-update.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +120 -57
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3484,6 +3484,21 @@ function formatOrderByClause(orderBy2) {
|
|
|
3484
3484
|
}
|
|
3485
3485
|
return orderByClause;
|
|
3486
3486
|
}
|
|
3487
|
+
function getDayOfWeekFromDate(date) {
|
|
3488
|
+
const daysOfWeek = [
|
|
3489
|
+
"sunday",
|
|
3490
|
+
"monday",
|
|
3491
|
+
"tuesday",
|
|
3492
|
+
"wednesday",
|
|
3493
|
+
"thursday",
|
|
3494
|
+
"friday",
|
|
3495
|
+
"saturday"
|
|
3496
|
+
];
|
|
3497
|
+
const dateString = date.toString().replace(/(\d{4})(\d{2})(\d{2})/, "$1-$2-$3");
|
|
3498
|
+
const [year, month, day] = dateString.split("-").map(Number);
|
|
3499
|
+
const dayOfWeek = new Date(year, month - 1, day).getDay();
|
|
3500
|
+
return daysOfWeek[dayOfWeek];
|
|
3501
|
+
}
|
|
3487
3502
|
|
|
3488
3503
|
// src/lib/import-gtfs-realtime.ts
|
|
3489
3504
|
function getNestedProperty(obj, defaultValue, path3) {
|
|
@@ -3548,9 +3563,8 @@ async function fetchGtfsRealtimeData(urlConfig, task) {
|
|
|
3548
3563
|
});
|
|
3549
3564
|
}
|
|
3550
3565
|
function removeExpiredRealtimeData(config) {
|
|
3551
|
-
const log2 = log(config);
|
|
3552
3566
|
const db = openDb(config);
|
|
3553
|
-
|
|
3567
|
+
log(config)(`Removing expired GTFS-Realtime data`);
|
|
3554
3568
|
db.prepare(
|
|
3555
3569
|
`DELETE FROM vehicle_positions WHERE expiration_timestamp <= strftime('%s','now')`
|
|
3556
3570
|
).run();
|
|
@@ -3566,7 +3580,7 @@ function removeExpiredRealtimeData(config) {
|
|
|
3566
3580
|
db.prepare(
|
|
3567
3581
|
`DELETE FROM service_alert_targets WHERE expiration_timestamp <= strftime('%s','now')`
|
|
3568
3582
|
).run();
|
|
3569
|
-
|
|
3583
|
+
log(config)(`Removed expired GTFS-Realtime data\r`, true);
|
|
3570
3584
|
}
|
|
3571
3585
|
function prepareRealtimeFieldValue(entity, column, task) {
|
|
3572
3586
|
if (column.name === "created_timestamp") {
|
|
@@ -3720,13 +3734,10 @@ async function updateGtfsRealtimeData(task) {
|
|
|
3720
3734
|
async function updateGtfsRealtime(initialConfig) {
|
|
3721
3735
|
const config = setDefaultConfig(initialConfig);
|
|
3722
3736
|
validateConfigForImport(config);
|
|
3723
|
-
const log2 = log(config);
|
|
3724
|
-
const logError2 = logError(config);
|
|
3725
|
-
const logWarning2 = logWarning(config);
|
|
3726
3737
|
try {
|
|
3727
3738
|
openDb(config);
|
|
3728
3739
|
const agencyCount = config.agencies.length;
|
|
3729
|
-
|
|
3740
|
+
log(config)(
|
|
3730
3741
|
`Starting GTFS-Realtime refresh for ${pluralize(
|
|
3731
3742
|
"agencies",
|
|
3732
3743
|
agencyCount,
|
|
@@ -3745,20 +3756,20 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
3745
3756
|
ignoreErrors: config.ignoreErrors,
|
|
3746
3757
|
sqlitePath: config.sqlitePath,
|
|
3747
3758
|
currentTimestamp: Math.floor(Date.now() / 1e3),
|
|
3748
|
-
log:
|
|
3749
|
-
logWarning:
|
|
3750
|
-
logError:
|
|
3759
|
+
log: log(config),
|
|
3760
|
+
logWarning: logWarning(config),
|
|
3761
|
+
logError: logError(config)
|
|
3751
3762
|
};
|
|
3752
3763
|
await updateGtfsRealtimeData(task);
|
|
3753
3764
|
} catch (error) {
|
|
3754
3765
|
if (config.ignoreErrors) {
|
|
3755
|
-
|
|
3766
|
+
logError(config)(error.message);
|
|
3756
3767
|
} else {
|
|
3757
3768
|
throw error;
|
|
3758
3769
|
}
|
|
3759
3770
|
}
|
|
3760
3771
|
});
|
|
3761
|
-
|
|
3772
|
+
log(config)(
|
|
3762
3773
|
`Completed GTFS-Realtime refresh for ${pluralize(
|
|
3763
3774
|
"agencies",
|
|
3764
3775
|
agencyCount,
|
|
@@ -3767,16 +3778,13 @@ async function updateGtfsRealtime(initialConfig) {
|
|
|
3767
3778
|
`
|
|
3768
3779
|
);
|
|
3769
3780
|
} catch (error) {
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
}
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
|
|
3777
|
-
);
|
|
3781
|
+
if (error?.code === "SQLITE_CANTOPEN") {
|
|
3782
|
+
logError(config)(
|
|
3783
|
+
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
|
|
3784
|
+
);
|
|
3785
|
+
}
|
|
3786
|
+
throw error;
|
|
3778
3787
|
}
|
|
3779
|
-
throw error;
|
|
3780
3788
|
}
|
|
3781
3789
|
|
|
3782
3790
|
// src/lib/import-gtfs.ts
|
|
@@ -4122,13 +4130,10 @@ async function importGtfs(initialConfig) {
|
|
|
4122
4130
|
timer.start();
|
|
4123
4131
|
const config = setDefaultConfig(initialConfig);
|
|
4124
4132
|
validateConfigForImport(config);
|
|
4125
|
-
const log2 = log(config);
|
|
4126
|
-
const logError2 = logError(config);
|
|
4127
|
-
const logWarning2 = logWarning(config);
|
|
4128
4133
|
try {
|
|
4129
4134
|
const db = openDb(config);
|
|
4130
4135
|
const agencyCount = config.agencies.length;
|
|
4131
|
-
|
|
4136
|
+
log(config)(
|
|
4132
4137
|
`Starting GTFS import for ${pluralize2("file", agencyCount, true)} using SQLite database at ${config.sqlitePath}`
|
|
4133
4138
|
);
|
|
4134
4139
|
createGtfsTables(db);
|
|
@@ -4152,9 +4157,9 @@ async function importGtfs(initialConfig) {
|
|
|
4152
4157
|
sqlitePath: config.sqlitePath,
|
|
4153
4158
|
prefix: agency2.prefix,
|
|
4154
4159
|
currentTimestamp: Math.floor(Date.now() / 1e3),
|
|
4155
|
-
log:
|
|
4156
|
-
logWarning:
|
|
4157
|
-
logError:
|
|
4160
|
+
log: log(config),
|
|
4161
|
+
logWarning: logWarning(config),
|
|
4162
|
+
logError: logError(config)
|
|
4158
4163
|
};
|
|
4159
4164
|
if (task.url) {
|
|
4160
4165
|
await downloadGtfsFiles(task);
|
|
@@ -4164,36 +4169,30 @@ async function importGtfs(initialConfig) {
|
|
|
4164
4169
|
await updateGtfsRealtimeData(task);
|
|
4165
4170
|
await rm2(tempPath, { recursive: true });
|
|
4166
4171
|
} catch (error) {
|
|
4167
|
-
|
|
4172
|
+
if (config.ignoreErrors) {
|
|
4173
|
+
logError(config)(error.message);
|
|
4174
|
+
} else {
|
|
4175
|
+
throw error;
|
|
4176
|
+
}
|
|
4168
4177
|
}
|
|
4169
4178
|
});
|
|
4170
|
-
|
|
4179
|
+
log(config)(`Creating DB indexes`);
|
|
4171
4180
|
createGtfsIndexes(db);
|
|
4172
4181
|
const seconds = Math.round(timer.time() / 1e3);
|
|
4173
4182
|
timer.stop();
|
|
4174
|
-
|
|
4183
|
+
log(config)(
|
|
4175
4184
|
`Completed GTFS import for ${pluralize2("agency", agencyCount, true)} in ${seconds} seconds
|
|
4176
4185
|
`
|
|
4177
4186
|
);
|
|
4178
4187
|
} catch (error) {
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
}
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
logError2(error.message);
|
|
4185
|
-
} else {
|
|
4188
|
+
if (error?.code === "SQLITE_CANTOPEN") {
|
|
4189
|
+
logError(config)(
|
|
4190
|
+
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
|
|
4191
|
+
);
|
|
4192
|
+
}
|
|
4186
4193
|
throw error;
|
|
4187
4194
|
}
|
|
4188
4195
|
}
|
|
4189
|
-
function handleDatabaseError2(error, config, logError2) {
|
|
4190
|
-
if (error?.code === "SQLITE_CANTOPEN") {
|
|
4191
|
-
logError2(
|
|
4192
|
-
`Unable to open sqlite database "${config.sqlitePath}" defined as \`sqlitePath\` config.json. Ensure the parent directory exists or remove \`sqlitePath\` from config.json.`
|
|
4193
|
-
);
|
|
4194
|
-
}
|
|
4195
|
-
throw error;
|
|
4196
|
-
}
|
|
4197
4196
|
|
|
4198
4197
|
// src/lib/export.ts
|
|
4199
4198
|
import path2 from "node:path";
|
|
@@ -4220,8 +4219,6 @@ var getAgencies = (db, config) => {
|
|
|
4220
4219
|
};
|
|
4221
4220
|
var exportGtfs = async (initialConfig) => {
|
|
4222
4221
|
const config = setDefaultConfig(initialConfig);
|
|
4223
|
-
const log2 = log(config);
|
|
4224
|
-
const logWarning2 = logWarning(config);
|
|
4225
4222
|
const db = openDb(config);
|
|
4226
4223
|
const agencies = getAgencies(db, config);
|
|
4227
4224
|
const agencyCount = agencies.length;
|
|
@@ -4230,11 +4227,11 @@ var exportGtfs = async (initialConfig) => {
|
|
|
4230
4227
|
"No agencies found in SQLite. Be sure to first import data into SQLite using `gtfs-import` or `importGtfs(config);`"
|
|
4231
4228
|
);
|
|
4232
4229
|
} else if (agencyCount > 1) {
|
|
4233
|
-
|
|
4230
|
+
logWarning(config)(
|
|
4234
4231
|
"More than one agency is defined in config.json. Export will merge all into one GTFS file."
|
|
4235
4232
|
);
|
|
4236
4233
|
}
|
|
4237
|
-
|
|
4234
|
+
log(config)(
|
|
4238
4235
|
`Starting GTFS export for ${pluralize3(
|
|
4239
4236
|
"agency",
|
|
4240
4237
|
agencyCount,
|
|
@@ -4259,7 +4256,7 @@ var exportGtfs = async (initialConfig) => {
|
|
|
4259
4256
|
const lines = db.prepare(`SELECT * FROM ${tableName};`).all();
|
|
4260
4257
|
if (!lines || lines.length === 0) {
|
|
4261
4258
|
if (!model.nonstandard) {
|
|
4262
|
-
|
|
4259
|
+
log(config)(
|
|
4263
4260
|
`Skipping (no data) - ${model.filenameBase}.${model.filenameExtension}\r`
|
|
4264
4261
|
);
|
|
4265
4262
|
}
|
|
@@ -4301,17 +4298,23 @@ var exportGtfs = async (initialConfig) => {
|
|
|
4301
4298
|
`Unexpected filename extension: ${model.filenameExtension}`
|
|
4302
4299
|
);
|
|
4303
4300
|
}
|
|
4304
|
-
|
|
4301
|
+
log(config)(
|
|
4302
|
+
`Exporting - ${model.filenameBase}.${model.filenameExtension}\r`
|
|
4303
|
+
);
|
|
4305
4304
|
return `${model.filenameBase}.${model.filenameExtension}`;
|
|
4306
4305
|
}
|
|
4307
4306
|
);
|
|
4308
4307
|
if (compact2(exportedFiles).length === 0) {
|
|
4309
|
-
|
|
4308
|
+
log(config)(
|
|
4309
|
+
"No GTFS data exported. Be sure to first import data into SQLite."
|
|
4310
|
+
);
|
|
4310
4311
|
return;
|
|
4311
4312
|
}
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
`)
|
|
4313
|
+
log(config)(`Completed GTFS export to ${exportPath}`);
|
|
4314
|
+
log(config)(
|
|
4315
|
+
`Completed GTFS export for ${pluralize3("agency", agencyCount, true)}
|
|
4316
|
+
`
|
|
4317
|
+
);
|
|
4315
4318
|
};
|
|
4316
4319
|
|
|
4317
4320
|
// src/lib/advancedQuery.ts
|
|
@@ -4407,6 +4410,31 @@ function getCalendars(query = {}, fields = [], orderBy2 = [], options = {}) {
|
|
|
4407
4410
|
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`
|
|
4408
4411
|
).all();
|
|
4409
4412
|
}
|
|
4413
|
+
function getServiceIdsByDate(date, options = {}) {
|
|
4414
|
+
const db = options.db ?? openDb();
|
|
4415
|
+
if (!date) {
|
|
4416
|
+
throw new Error("`date` is a required query parameter");
|
|
4417
|
+
}
|
|
4418
|
+
const dayOfWeek = getDayOfWeekFromDate(date);
|
|
4419
|
+
const results = db.prepare(
|
|
4420
|
+
`
|
|
4421
|
+
SELECT service_id FROM (
|
|
4422
|
+
SELECT service_id
|
|
4423
|
+
FROM calendar
|
|
4424
|
+
WHERE start_date <= ? AND end_date >= ? AND ${dayOfWeek} = 1
|
|
4425
|
+
UNION
|
|
4426
|
+
SELECT service_id
|
|
4427
|
+
FROM calendar_dates
|
|
4428
|
+
WHERE date = ? AND exception_type = 1
|
|
4429
|
+
)
|
|
4430
|
+
EXCEPT
|
|
4431
|
+
SELECT service_id
|
|
4432
|
+
FROM calendar_dates
|
|
4433
|
+
WHERE date = ? AND exception_type = 2
|
|
4434
|
+
`
|
|
4435
|
+
).all(date, date, date, date);
|
|
4436
|
+
return results.map((record) => record.service_id);
|
|
4437
|
+
}
|
|
4410
4438
|
|
|
4411
4439
|
// src/lib/gtfs/fare-attributes.ts
|
|
4412
4440
|
function getFareAttributes(query = {}, fields = [], orderBy2 = [], options = {}) {
|
|
@@ -4827,12 +4855,46 @@ function getStopsAsGeoJSON(query = {}, options = {}) {
|
|
|
4827
4855
|
}
|
|
4828
4856
|
|
|
4829
4857
|
// src/lib/gtfs/stop-times.ts
|
|
4858
|
+
import { omit as omit6 } from "lodash-es";
|
|
4859
|
+
import sqlString5 from "sqlstring-sqlite";
|
|
4830
4860
|
function getStoptimes(query = {}, fields = [], orderBy2 = [], options = {}) {
|
|
4831
4861
|
const db = options.db ?? openDb();
|
|
4832
4862
|
const tableName = "stop_times";
|
|
4833
4863
|
const selectClause = formatSelectClause(fields);
|
|
4834
|
-
|
|
4864
|
+
let whereClause = "";
|
|
4835
4865
|
const orderByClause = formatOrderByClause(orderBy2);
|
|
4866
|
+
const stoptimeQueryOmitKeys = ["date", "start_time", "end_time"];
|
|
4867
|
+
let stoptimeQuery = omit6(query, stoptimeQueryOmitKeys);
|
|
4868
|
+
const whereClauses = Object.entries(stoptimeQuery).map(
|
|
4869
|
+
([key, value]) => formatWhereClause(key, value)
|
|
4870
|
+
);
|
|
4871
|
+
if (query.date) {
|
|
4872
|
+
if (typeof query.date !== "number") {
|
|
4873
|
+
throw new Error("`date` must be a number in yyyymmdd format");
|
|
4874
|
+
}
|
|
4875
|
+
const serviceIds = getServiceIdsByDate(query.date);
|
|
4876
|
+
const tripSubquery = `SELECT DISTINCT trip_id FROM trips WHERE service_id IN (${serviceIds.map((id) => sqlString5.escape(id)).join(",")})`;
|
|
4877
|
+
whereClauses.push(`trip_id IN (${tripSubquery})`);
|
|
4878
|
+
}
|
|
4879
|
+
if (query.start_time) {
|
|
4880
|
+
if (typeof query.start_time !== "string") {
|
|
4881
|
+
throw new Error("`start_time` must be a string in HH:mm:ss format");
|
|
4882
|
+
}
|
|
4883
|
+
whereClauses.push(
|
|
4884
|
+
`arrival_timestamp >= ${calculateSecondsFromMidnight(query.start_time)}`
|
|
4885
|
+
);
|
|
4886
|
+
}
|
|
4887
|
+
if (query.end_time) {
|
|
4888
|
+
if (typeof query.end_time !== "string") {
|
|
4889
|
+
throw new Error("`end_time` must be a string in HH:mm:ss format");
|
|
4890
|
+
}
|
|
4891
|
+
whereClauses.push(
|
|
4892
|
+
`departure_timestamp <= ${calculateSecondsFromMidnight(query.end_time)}`
|
|
4893
|
+
);
|
|
4894
|
+
}
|
|
4895
|
+
if (whereClauses.length > 0) {
|
|
4896
|
+
whereClause = `WHERE ${whereClauses.join(" AND ")}`;
|
|
4897
|
+
}
|
|
4836
4898
|
return db.prepare(
|
|
4837
4899
|
`${selectClause} FROM ${tableName} ${whereClause} ${orderByClause};`
|
|
4838
4900
|
).all();
|
|
@@ -5190,6 +5252,7 @@ export {
|
|
|
5190
5252
|
getRunEvents,
|
|
5191
5253
|
getRunsPieces,
|
|
5192
5254
|
getServiceAlerts,
|
|
5255
|
+
getServiceIdsByDate,
|
|
5193
5256
|
getShapes,
|
|
5194
5257
|
getShapesAsGeoJSON,
|
|
5195
5258
|
getStopAreas,
|