Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
07ecda4
refactor(Initial fares v2 work):
br648 Aug 15, 2024
1d57cd6
refactor(GTFSTest): Addressed failing test
br648 Aug 15, 2024
208ea3c
refactor(Various new tests):
br648 Aug 16, 2024
5f0c806
refactor(Entity.java): Updated zip sub directory file name check
br648 Aug 19, 2024
5dd609b
refactor(Updated to extract the file name from path):
br648 Aug 19, 2024
1d82b21
refactor(Refactored GraphQL classes to accom fares v2):
br648 Aug 23, 2024
1d95cf5
refactor(Update to include network_id in the route GraphQL obj):
br648 Oct 18, 2024
3faaa1e
Merge branch 'dev' into feature/DT-448-fares-v2
br648 Jan 28, 2025
fbf5282
refactor(Replaced camel case with snake case for GrpahQL objs):
br648 Jan 28, 2025
7d41e00
improvement(Added JDBC table writer tests for fares v2 entities): New…
br648 Jan 31, 2025
62a7ed2
fix(JDBCTableWriterFaresV2Test.java): Replaced Windows new line separ…
br648 Jan 31, 2025
a2db1a7
improvement(GTFSFaresV2Test): Removed superceded JDBC table writer tests
br648 Feb 5, 2025
e96e834
improvement(Removed the id param from the create entities to closer m…
br648 Feb 5, 2025
2390130
improvement(Altered GraphQL test data): Similified fare product query…
br648 Feb 5, 2025
2c256c9
improvement(Removed child entities from GraphQL schema): Only parent …
br648 Feb 6, 2025
518fcc2
improvement(Table.java): Reinstated key field is not unique check for…
br648 Feb 6, 2025
1cac512
Merge branch 'dev' into feature/DT-448-fares-v2
br648 Jun 17, 2025
731dcf0
feat(Merging stop areas into stops): import stop areas into stops and…
br648 Jul 31, 2025
a3481b0
improvement(A few minor changes with comments):
br648 Jul 31, 2025
2b1302c
improvement(GraphQL updates): Removed stop areas. Added fares v2 stop…
br648 Aug 5, 2025
00b9d65
improvement(Entry in zip subdirecotry): Allow for stop areas being in…
br648 Aug 11, 2025
dd97252
improvement(Stop.java): Updated stop areas separator to a special uni…
br648 Aug 11, 2025
6117108
improvement(Stop.java): Corrected separator char
br648 Aug 11, 2025
f3ef2c4
improvement(Checking for files in zip subdirectories): Updated all lo…
br648 Aug 11, 2025
8353334
improvement(Exporting): Added the functionality to export stop areas
br648 Aug 14, 2025
7299ed4
improvement(Addressed PR feedback):
br648 Aug 18, 2025
9436984
improvement(Stop export): Remove stop areas from stop export
br648 Aug 20, 2025
ff93df6
improvement(Entity.java): Reinstated space
br648 Aug 20, 2025
77e3b61
improvement(Addressed PR feedback): Streamlined writting to zip
br648 Aug 21, 2025
c3ba52d
Merge pull request #15 from ibi-group/merge-stop-areas
br648 Aug 21, 2025
b091a91
feat(route network merge): Started on merging rout networks into routes
br648 Aug 18, 2025
9824180
improvement(Various updates to accom route networks in routes):
br648 Aug 20, 2025
a93b5bc
improvement(Further dev work):
br648 Aug 21, 2025
d045979
improvement(Minor changes and address bug):
br648 Aug 21, 2025
f787aa2
improvement(GTFSTest.java): Updated test to allow for now route netwo…
br648 Aug 21, 2025
5193713
improvement(Consolidating methods): Moved methods from stops and rout…
br648 Aug 21, 2025
116a8dd
improvement(Route from editor export): Update to export only approved…
br648 Aug 22, 2025
f43fa02
improvement(Route.java): Added route export count and removed redunda…
br648 Aug 22, 2025
6739bc6
improvement(Efficiency updates and row count outputs):
br648 Aug 22, 2025
82684ac
improvement(Addressed PR feedback):
br648 Aug 26, 2025
d63eaca
improvement(Reverted concat changes):
br648 Aug 26, 2025
a65a86a
improvement(Entity.java): Corrected param name change
br648 Aug 26, 2025
f0bd480
refactor(Entity): Extract logic for printing col after existing ones.
binh-dam-ibigroup Aug 26, 2025
43777fb
Merge pull request #17 from ibi-group/merge-route-networks-qbd
br648 Aug 27, 2025
bf7aaa9
Merge pull request #16 from ibi-group/merge-route-networks
br648 Aug 27, 2025
8d087c0
improvement(Fixed merged conflicts and bumped node version to 22.x):
br648 Oct 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ jobs:
uses: actions/setup-java@v1
with:
java-version: 1.8
# Install node 20.11.0 (LTS) for running maven-semantic-release.
- name: Use Node.js 20.X
# Install node 22.x (LTS) for running maven-semantic-release.
- name: Use Node.js 22.X
uses: actions/setup-node@v1
with:
node-version: 20.11.0
node-version: 22.x
- name: Install maven-semantic-release
# FIXME: Enable cache for node packages (add package.json?)
run: |
Expand Down Expand Up @@ -64,10 +64,10 @@ jobs:
#
# The git commands get the commit hash of the HEAD commit and the commit just before HEAD.
# Install node 14+ for running maven-semantic-release.
- name: Use Node.js 20.X
- name: Use Node.js 22.X
uses: actions/setup-node@v1
with:
node-version: 20.11.0
node-version: 22.x
- name: Run maven-semantic-release
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
Expand Down
57 changes: 57 additions & 0 deletions src/main/java/com/conveyal/gtfs/GTFSFeed.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import static com.conveyal.gtfs.model.RouteNetwork.ROUTE_NETWORK_FILE_NAME;

/**
* All entities must be from a single feed namespace.
* Composed of several GTFSTables.
Expand All @@ -62,6 +64,7 @@ public class GTFSFeed implements Cloneable, Closeable {
// This is how you do a multimap in mapdb: https://github.com/jankotek/MapDB/blob/release-1.0/src/test/java/examples/MultiMap.java
public final NavigableSet<Tuple2<String, Frequency>> frequencies;
public final Map<String, Route> routes;
public final Map<String, StopArea> stop_areas;
public final Map<String, Stop> stops;
public final Map<String, Transfer> transfers;
public final BTreeMap<String, Trip> trips;
Expand Down Expand Up @@ -110,6 +113,15 @@ public class GTFSFeed implements Cloneable, Closeable {
/* A place to store an event bus that is passed through constructor. */
public transient EventBus eventBus;

public final Map<String, Area> areas;
public final Map<String, FareProduct> fare_products;
public final Map<String, FareMedia> fare_medias;
public final Map<String, TimeFrame> time_frames;
public final Map<String, FareLegRule> fare_leg_rules;
public final Map<String, FareTransferRule> fare_transfer_rules;
public final Map<String, Network> networks;
public final Map<String, RouteNetwork> route_networks;

/**
* The order in which we load the tables is important for two reasons.
* 1. We must load feed_info first so we know the feed ID before loading any other entities. This could be relaxed
Expand Down Expand Up @@ -170,13 +182,31 @@ else if (feedId == null || feedId.isEmpty()) {
fares = null; // free memory

new Pattern.Loader(this).loadTable(zip);
new RouteNetwork.Loader(this).loadTable(zip);
new Route.Loader(this).loadTable(zip);
if (!route_networks.isEmpty()) {
Route.mergeRouteNetworks(routes, route_networks);
}
new ShapePoint.Loader(this).loadTable(zip);
new StopArea.Loader(this).loadTable(zip);
new Stop.Loader(this).loadTable(zip);
if (!stop_areas.isEmpty()) {
Stop.mergeStopAreas(stops, stop_areas);
}
new Transfer.Loader(this).loadTable(zip);
new Trip.Loader(this).loadTable(zip);
new Frequency.Loader(this).loadTable(zip);
new StopTime.Loader(this).loadTable(zip); // comment out this line for quick testing using NL feed

// Fares v2.
new Area.Loader(this).loadTable(zip);
new TimeFrame.Loader(this).loadTable(zip);
new Network.Loader(this).loadTable(zip);
new FareMedia.Loader(this).loadTable(zip);
new FareProduct.Loader(this).loadTable(zip);
new FareLegRule.Loader(this).loadTable(zip);
new FareTransferRule.Loader(this).loadTable(zip);

LOG.info("{} errors", errors.size());
for (GTFSError error : errors) {
LOG.info("{}", error);
Expand Down Expand Up @@ -212,12 +242,30 @@ public void toFile (String file) {
new FareRule.Writer(this).writeTable(zip);
new Frequency.Writer(this).writeTable(zip);
new Route.Writer(this).writeTable(zip);
if (!routes.isEmpty()) {
// Export route networks.
Entity.writeEntityToFile(zip, new ArrayList<>(routes.values()), ROUTE_NETWORK_FILE_NAME);
}
new Stop.Writer(this).writeTable(zip);
if (!stops.isEmpty()) {
// Export stop areas.
Entity.writeEntityToFile(zip, new ArrayList<>(stops.values()), Stop.STOP_AREAS_FILE_NAME);
}
new ShapePoint.Writer(this).writeTable(zip);
new Transfer.Writer(this).writeTable(zip);
new Trip.Writer(this).writeTable(zip);
new StopTime.Writer(this).writeTable(zip);
new Pattern.Writer(this).writeTable(zip);

// Fares v2.
new Area.Writer(this).writeTable(zip);
new TimeFrame.Writer(this).writeTable(zip);
new Network.Writer(this).writeTable(zip);
new FareMedia.Writer(this).writeTable(zip);
new FareProduct.Writer(this).writeTable(zip);
new FareLegRule.Writer(this).writeTable(zip);
new FareTransferRule.Writer(this).writeTable(zip);

LOG.info("GTFS file written");
} catch (Exception e) {
LOG.error("Error saving GTFS: {}", e.getMessage());
Expand Down Expand Up @@ -605,16 +653,25 @@ private GTFSFeed (DB db) {
this.db = db;

agency = db.getTreeMap("agency");
areas = db.getTreeMap("area");
fare_leg_rules = db.getTreeMap("fare_leg_rules");
fare_medias = db.getTreeMap("fare_medias");
fare_products = db.getTreeMap("fare_products");
fare_transfer_rules = db.getTreeMap("fare_transfer_rules");
feedInfo = db.getTreeMap("feed_info");
networks = db.getTreeMap("networks");
routes = db.getTreeMap("routes");
route_networks = db.getTreeMap("route_networks");
trips = db.getTreeMap("trips");
stop_times = db.getTreeMap("stop_times");
frequencies = db.getTreeSet("frequencies");
transfers = db.getTreeMap("transfers");
stop_areas = db.getTreeMap("stop_areas");
stops = db.getTreeMap("stops");
fares = db.getTreeMap("fares");
services = db.getTreeMap("services");
shape_points = db.getTreeMap("shape_points");
time_frames = db.getTreeMap("time_frames");
translations = db.getTreeMap("translations");
attributions = db.getTreeMap("attributions");

Expand Down
111 changes: 111 additions & 0 deletions src/main/java/com/conveyal/gtfs/graphql/GraphQLGtfsFaresV2Schema.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package com.conveyal.gtfs.graphql;

import com.conveyal.gtfs.graphql.fetchers.MapFetcher;
import com.conveyal.gtfs.model.Area;
import com.conveyal.gtfs.model.FareLegRule;
import com.conveyal.gtfs.model.FareMedia;
import com.conveyal.gtfs.model.FareProduct;
import com.conveyal.gtfs.model.FareTransferRule;
import com.conveyal.gtfs.model.Network;
import com.conveyal.gtfs.model.RouteNetwork;
import com.conveyal.gtfs.model.TimeFrame;
import graphql.schema.GraphQLFieldDefinition;
import graphql.schema.GraphQLObjectType;

import java.util.Arrays;
import java.util.List;

import static com.conveyal.gtfs.graphql.GraphQLUtil.createFieldDefinition;
import static graphql.Scalars.GraphQLInt;
import static graphql.schema.GraphQLObjectType.newObject;

public class GraphQLGtfsFaresV2Schema {

private static final String AREA_TYPE_NAME = "area";
private static final String TIME_FRAME_TYPE_NAME = "time_frame";
private static final String NETWORK_TYPE_NAME = "network";
private static final String FARE_MEDIA_TYPE_NAME = "fare_media";
private static final String FARE_PRODUCT_TYPE_NAME = "fare_product";
private static final String FARE_LEG_RULE_TYPE_NAME = "fare_leg_rule";
private static final String FARE_TRANSFER_RULE_TYPE_NAME = "fare_transfer_rule";

private GraphQLGtfsFaresV2Schema() {}

public static final GraphQLObjectType areaType = newObject().name(AREA_TYPE_NAME)
.description("A GTFS area object")
.field(MapFetcher.field("id", GraphQLInt))
.field(MapFetcher.field(Area.AREA_ID_NAME))
.field(MapFetcher.field(Area.AREA_NAME_NAME))
.build();

public static final GraphQLObjectType timeFrameType = newObject().name(TIME_FRAME_TYPE_NAME)
.description("A GTFS time frame object")
.field(MapFetcher.field("id", GraphQLInt))
.field(MapFetcher.field(TimeFrame.TIME_FRAME_GROUP_ID_NAME))
.field(MapFetcher.field(TimeFrame.START_TIME_NAME))
.field(MapFetcher.field(TimeFrame.END_TIME_NAME))
.field(MapFetcher.field(TimeFrame.SERVICE_ID_NAME))
.build();

public static final GraphQLObjectType networkType = newObject().name(NETWORK_TYPE_NAME)
.description("A GTFS network object")
.field(MapFetcher.field("id", GraphQLInt))
.field(MapFetcher.field(Network.NETWORK_ID_NAME))
.field(MapFetcher.field(Network.NETWORK_NAME_NAME))
.build();

public static final GraphQLObjectType fareMediaType = newObject().name(FARE_MEDIA_TYPE_NAME)
.description("A GTFS fare media object")
.field(MapFetcher.field("id", GraphQLInt))
.field(MapFetcher.field(FareMedia.FARE_MEDIA_ID_NAME))
.field(MapFetcher.field(FareMedia.FARE_MEDIA_NAME_NAME))
.field(MapFetcher.field(FareMedia.FARE_MEDIA_TYPE_NAME))
.build();

public static final GraphQLObjectType fareProductType = newObject().name(FARE_PRODUCT_TYPE_NAME)
.description("A GTFS fare product object")
.field(MapFetcher.field("id", GraphQLInt))
.field(MapFetcher.field(FareProduct.FARE_PRODUCT_ID_NAME))
.field(MapFetcher.field(FareProduct.FARE_PRODUCT_NAME_NAME))
.field(MapFetcher.field(FareProduct.FARE_MEDIA_ID_NAME))
.field(MapFetcher.field(FareProduct.AMOUNT_NAME))
.field(MapFetcher.field(FareProduct.CURRENCY_NAME))
.build();

public static final GraphQLObjectType fareLegRuleType = newObject().name(FARE_LEG_RULE_TYPE_NAME)
.description("A GTFS fare leg rule object")
.field(MapFetcher.field("id", GraphQLInt))
.field(MapFetcher.field(FareLegRule.LEG_GROUP_ID_NAME))
.field(MapFetcher.field(FareLegRule.NETWORK_ID_NAME))
.field(MapFetcher.field(FareLegRule.FROM_AREA_ID_NAME))
.field(MapFetcher.field(FareLegRule.TO_AREA_ID_NAME))
.field(MapFetcher.field(FareLegRule.FROM_TIMEFRAME_GROUP_ID_NAME))
.field(MapFetcher.field(FareLegRule.TO_TIMEFRAME_GROUP_ID_NAME))
.field(MapFetcher.field(FareLegRule.FARE_PRODUCT_ID_NAME))
.field(MapFetcher.field(FareLegRule.RULE_PRIORITY_NAME))
.build();

public static final GraphQLObjectType fareTransferRuleType = newObject().name(FARE_TRANSFER_RULE_TYPE_NAME)
.description("A GTFS fare transfer rule object")
.field(MapFetcher.field("id", GraphQLInt))
.field(MapFetcher.field(FareTransferRule.FROM_LEG_GROUP_ID_NAME))
.field(MapFetcher.field(FareTransferRule.TO_LEG_GROUP_ID_NAME))
.field(MapFetcher.field(FareTransferRule.TRANSFER_COUNT_NAME))
.field(MapFetcher.field(FareTransferRule.DURATION_LIMIT_NAME))
.field(MapFetcher.field(FareTransferRule.DURATION_LIMIT_TYPE_NAME))
.field(MapFetcher.field(FareTransferRule.FARE_TRANSFER_TYPE_NAME))
.field(MapFetcher.field(FareTransferRule.FARE_PRODUCT_ID_NAME))
.build();

public static List<GraphQLFieldDefinition> getFaresV2FieldDefinitions() {
return Arrays.asList(
createFieldDefinition(AREA_TYPE_NAME, areaType, Area.TABLE_NAME),
createFieldDefinition(FARE_LEG_RULE_TYPE_NAME, fareLegRuleType, FareLegRule.TABLE_NAME),
createFieldDefinition(FARE_MEDIA_TYPE_NAME, fareMediaType, FareMedia.TABLE_NAME),
createFieldDefinition(FARE_PRODUCT_TYPE_NAME, fareProductType, FareProduct.TABLE_NAME),
createFieldDefinition(FARE_TRANSFER_RULE_TYPE_NAME, fareTransferRuleType, FareTransferRule.TABLE_NAME),
createFieldDefinition(NETWORK_TYPE_NAME, networkType, Network.TABLE_NAME),
createFieldDefinition(TIME_FRAME_TYPE_NAME, timeFrameType, TimeFrame.TABLE_NAME)
);
}
}
Loading