Skip to content

Commit

Permalink
Merge pull request conveyal#398 from conveyal/feature/DT-209-enhance-…
Browse files Browse the repository at this point in the history
…transfers

Update transfers inline with latest spec
  • Loading branch information
philip-cline authored Nov 10, 2023
2 parents bde0936 + e5355d3 commit 5212691
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 29 deletions.
2 changes: 1 addition & 1 deletion src/main/java/com/conveyal/gtfs/loader/JdbcGtfsLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,8 +163,8 @@ public FeedLoadResult loadTables() {
result.patterns = load(Table.PATTERNS); // refs shapes and routes.
result.stops = load(Table.STOPS);
result.fareRules = load(Table.FARE_RULES);
result.transfers = load(Table.TRANSFERS);
result.trips = load(Table.TRIPS); // refs routes
result.transfers = load(Table.TRANSFERS); // refs trips.
result.frequencies = load(Table.FREQUENCIES); // refs trips
result.stopTimes = load(Table.STOP_TIMES);
result.translations = load(Table.TRANSLATIONS);
Expand Down
30 changes: 19 additions & 11 deletions src/main/java/com/conveyal/gtfs/loader/Table.java
Original file line number Diff line number Diff line change
Expand Up @@ -326,17 +326,6 @@ public Table (String name, Class<? extends Entity> entityClass, Requirement requ
).withParentTable(PATTERNS)
.addPrimaryKeyNames("pattern_id", "stop_sequence");

public static final Table TRANSFERS = new Table("transfers", Transfer.class, OPTIONAL,
// FIXME: Do we need an index on from_ and to_stop_id
new StringField("from_stop_id", REQUIRED).isReferenceTo(STOPS),
new StringField("to_stop_id", REQUIRED).isReferenceTo(STOPS),
new ShortField("transfer_type", REQUIRED, 3),
new StringField("min_transfer_time", OPTIONAL)
).addPrimaryKey()
.keyFieldIsNotUnique()
.hasCompoundKey()
.addPrimaryKeyNames("from_stop_id", "to_stop_id");

public static final Table TRIPS = new Table("trips", Trip.class, REQUIRED,
new StringField("trip_id", REQUIRED),
new StringField("route_id", REQUIRED).isReferenceTo(ROUTES).indexThisColumn(),
Expand All @@ -355,6 +344,25 @@ public Table (String name, Class<? extends Entity> entityClass, Requirement requ
).addPrimaryKey()
.addPrimaryKeyNames("trip_id");

// Must come after TRIPS table to which it has references.
public static final Table TRANSFERS = new Table("transfers", Transfer.class, OPTIONAL,
// Conditionally required fields (from_stop_id, to_stop_id, from_trip_id and to_trip_id) are defined here as
// optional so as not to trigger required field checks as part of GTFS-lib validation. Correct validation of
// these fields will be managed by the MobilityData validator.
new StringField("from_stop_id", OPTIONAL).isReferenceTo(STOPS),
new StringField("to_stop_id", OPTIONAL).isReferenceTo(STOPS),
new StringField("from_route_id", OPTIONAL).isReferenceTo(ROUTES),
new StringField("to_route_id", OPTIONAL).isReferenceTo(ROUTES),
new StringField("from_trip_id", OPTIONAL).isReferenceTo(TRIPS),
new StringField("to_trip_id", OPTIONAL).isReferenceTo(TRIPS),
new ShortField("transfer_type", REQUIRED, 3),
new StringField("min_transfer_time", OPTIONAL)
)
.addPrimaryKey()
.keyFieldIsNotUnique()
.hasCompoundKey()
.addPrimaryKeyNames("from_stop_id", "to_stop_id", "from_trip_id", "to_trip_id", "from_route_id", "to_route_id");

// Must come after TRIPS and STOPS table to which it has references
public static final Table STOP_TIMES = new Table("stop_times", StopTime.class, REQUIRED,
new StringField("trip_id", REQUIRED).isReferenceTo(TRIPS),
Expand Down
60 changes: 44 additions & 16 deletions src/main/java/com/conveyal/gtfs/model/Transfer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,18 @@ public void setStatementParameters(PreparedStatement statement, boolean setDefau
if (!setDefaultId) statement.setInt(oneBasedIndex++, id);
statement.setString(oneBasedIndex++, from_stop_id);
statement.setString(oneBasedIndex++, to_stop_id);
statement.setString(oneBasedIndex++, from_trip_id);
statement.setString(oneBasedIndex++, to_trip_id);
statement.setString(oneBasedIndex++, from_route_id);
statement.setString(oneBasedIndex++, to_route_id);
setIntParameter(statement, oneBasedIndex++, transfer_type);
setIntParameter(statement, oneBasedIndex++, min_transfer_time);
setIntParameter(statement, oneBasedIndex, min_transfer_time);
}

// TODO: Add id method for Transfer.
// @Override
// public String getId() {
//// return trip_id;
// }
@Override
public String getId() {
return createId(from_stop_id, to_stop_id, from_trip_id, to_trip_id, from_route_id, to_route_id);
}

public static class Loader extends Entity.Loader<Transfer> {

Expand All @@ -54,24 +57,24 @@ protected boolean isRequired() {
public void loadOneRow() throws IOException {
Transfer tr = new Transfer();
tr.id = row + 1; // offset line number by 1 to account for 0-based row index
tr.from_stop_id = getStringField("from_stop_id", true);
tr.to_stop_id = getStringField("to_stop_id", true);
tr.transfer_type = getIntField("transfer_type", true, 0, 3);
tr.min_transfer_time = getIntField("min_transfer_time", false, 0, Integer.MAX_VALUE);
tr.from_stop_id = getStringField("from_stop_id", false);
tr.to_stop_id = getStringField("to_stop_id", false);
tr.from_route_id = getStringField("from_route_id", false);
tr.to_route_id = getStringField("to_route_id", false);
tr.from_trip_id = getStringField("from_trip_id", false);
tr.to_trip_id = getStringField("to_trip_id", false);
tr.transfer_type = getIntField("transfer_type", true, 0, 3);
tr.min_transfer_time = getIntField("min_transfer_time", false, 0, Integer.MAX_VALUE);

getRefField("from_stop_id", true, feed.stops);
getRefField("to_stop_id", true, feed.stops);
getRefField("from_stop_id", false, feed.stops);
getRefField("to_stop_id", false, feed.stops);
getRefField("from_route_id", false, feed.routes);
getRefField("to_route_id", false, feed.routes);
getRefField("from_trip_id", false, feed.trips);
getRefField("to_trip_id", false, feed.trips);

tr.feed = feed;
feed.transfers.put(Long.toString(row), tr);
feed.transfers.put(tr.getId(), tr);
}

}
Expand All @@ -83,13 +86,26 @@ public Writer (GTFSFeed feed) {

@Override
protected void writeHeaders() throws IOException {
writer.writeRecord(new String[] {"from_stop_id", "to_stop_id", "transfer_type", "min_transfer_time"});
writer.writeRecord(new String[] {
"from_stop_id",
"to_stop_id",
"from_trip_id",
"to_trip_id",
"from_route_id",
"to_route_id",
"transfer_type",
"min_transfer_time"
});
}

@Override
protected void writeOneRow(Transfer t) throws IOException {
writeStringField(t.from_stop_id);
writeStringField(t.to_stop_id);
writeStringField(t.from_trip_id);
writeStringField(t.to_trip_id);
writeStringField(t.from_route_id);
writeStringField(t.to_route_id);
writeIntField(t.transfer_type);
writeIntField(t.min_transfer_time);
endRecord();
Expand All @@ -99,7 +115,19 @@ protected void writeOneRow(Transfer t) throws IOException {
protected Iterator<Transfer> iterator() {
return feed.transfers.values().iterator();
}
}


/**
* Transfer entries have no ID in GTFS so we define one based on the fields in the transfer entry.
*/
private static String createId(
String fromStopId,
String toStopId,
String fromTripId,
String toTripId,
String fromRouteId,
String toRouteId
) {
return String.format("%s_%s_%s_%s_%s_%s", fromStopId, toStopId, fromTripId, toTripId, fromRouteId, toRouteId);
}
}
}
13 changes: 13 additions & 0 deletions src/test/java/com/conveyal/gtfs/GTFSTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,19 @@ private void assertThatPersistenceExpectationRecordWasFound(
new RecordExpectation("bikes_allowed", 0),
new RecordExpectation("wheelchair_accessible", 0)
}
),
new PersistenceExpectation(
"transfers",
new RecordExpectation[]{
new RecordExpectation("from_stop_id", "4u6g"),
new RecordExpectation("to_stop_id", "johv"),
new RecordExpectation("from_trip_id", "a30277f8-e50a-4a85-9141-b1e0da9d429d"),
new RecordExpectation("to_trip_id", "frequency-trip"),
new RecordExpectation("from_route_id", "1"),
new RecordExpectation("to_route_id", "1"),
new RecordExpectation("transfer_type", "1"),
new RecordExpectation("min_transfer_time", "60")
}
)
};

Expand Down
4 changes: 3 additions & 1 deletion src/test/resources/fake-agency/transfers.txt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from_stop_id,to_stop_id,transfer_type,min_transfer_time
from_stop_id,to_stop_id,from_trip_id,to_trip_id,from_route_id,to_route_id,transfer_type,min_transfer_time
4u6g,johv,a30277f8-e50a-4a85-9141-b1e0da9d429d,frequency-trip,1,1,1,60
4u6g,123,,,,,1,60

0 comments on commit 5212691

Please sign in to comment.