From 4b052d5398c4a9ac920ae91a0b50471f214c3669 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Mon, 2 Oct 2023 17:01:59 +0300 Subject: [PATCH 01/48] Draft upcoming cancelled trips query --- .../apis/gtfs/datafetchers/DatedTripImpl.java | 37 ++++++++++++ .../gtfs/datafetchers/NodeTypeResolver.java | 4 ++ .../apis/gtfs/datafetchers/QueryTypeImpl.java | 20 +++++++ .../gtfs/generated/GraphQLDataFetchers.java | 38 ++++++++++++ .../apis/gtfs/generated/GraphQLTypes.java | 60 +++++++++++++++++++ .../apis/gtfs/generated/graphql-codegen.yml | 3 + .../transit/model/timetable/DatedTrip.java | 8 +++ .../service/DefaultTransitService.java | 32 ++++++++++ .../transit/service/TransitService.java | 3 + .../opentripplanner/apis/gtfs/schema.graphqls | 31 ++++++++++ 10 files changed, 236 insertions(+) create mode 100644 src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java create mode 100644 src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java new file mode 100644 index 00000000000..07f7c482754 --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java @@ -0,0 +1,37 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.relay.Relay; +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import org.opentripplanner.api.mapping.LocalDateMapper; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.transit.model.timetable.DatedTrip; +import org.opentripplanner.transit.model.timetable.Trip; + +public class DatedTripImpl implements GraphQLDataFetchers.GraphQLDatedTrip { + + @Override + public DataFetcher date() { + return env -> LocalDateMapper.mapToApi(getSource(env).serviceDate()); + } + + @Override + public DataFetcher trip() { + return env -> getSource(env).trip(); + } + + @Override + public DataFetcher id() { + return env -> + new Relay.ResolvedGlobalId( + "DatedTrip", + getSource(env).trip().getId().toString() + + ';' + + LocalDateMapper.mapToApi(getSource(env).serviceDate()) + ); + } + + private DatedTrip getSource(DataFetchingEnvironment environment) { + return environment.getSource(); + } +} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java index 437d75e03e9..63f80fb643f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java @@ -20,6 +20,7 @@ import org.opentripplanner.transit.model.organization.Agency; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.Station; +import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; public class NodeTypeResolver implements TypeResolver { @@ -85,6 +86,9 @@ public GraphQLObjectType getType(TypeResolutionEnvironment environment) { if (o instanceof Trip) { return schema.getObjectType("Trip"); } + if (o instanceof DatedTrip) { + return schema.getObjectType("DatedTrip"); + } return null; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index dfa4a60ce1c..0af024b284e 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -63,6 +63,7 @@ import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.updater.GtfsRealtimeFuzzyTripMatcher; @@ -422,6 +423,8 @@ public DataFetcher node() { return new PlaceAtDistance(place, Double.parseDouble(parts[0])); } + case "DatedTrip": + return null; // ???? case "Route": return transitService.getRouteForId(FeedScopedId.parse(id)); case "Stop": @@ -787,6 +790,23 @@ public DataFetcher> trips() { }; } + @Override + public DataFetcher> cancelledTrips() { + return environment -> { + // var args = new GraphQLTypes.GraphQLQueryTypeGetTripsArgs(environment.getArguments()); + + Stream tripStream = getTransitService(environment).getCancelledTrips().stream(); + + /* if (args.getGraphQLFeeds() != null) { + List feeds = args.getGraphQLFeeds(); + tripStream = tripStream.filter(datedTrip -> feeds.contains(datedTrip.getTrip().getId().getFeedId())); + }*/ + + var datedTrips = tripStream.collect(Collectors.toList()); + return new SimpleListConnection<>(datedTrips).get(environment); + }; + } + @Override public DataFetcher vehicleParking() { return environment -> { diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index d0562215f70..b4050392ed7 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -2,11 +2,16 @@ package org.opentripplanner.apis.gtfs.generated; import graphql.relay.Connection; +import graphql.relay.Connection; +import graphql.relay.Connection; +import graphql.relay.Edge; +import graphql.relay.Edge; import graphql.relay.Edge; import graphql.schema.DataFetcher; import graphql.schema.TypeResolver; import java.util.Currency; import java.util.Map; +import java.util.Map; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.opentripplanner.api.resource.DebugOutput; @@ -20,7 +25,11 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRoutingErrorCode; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; import org.opentripplanner.apis.gtfs.model.RideHailingProvider; +import org.opentripplanner.apis.gtfs.model.RouteTypeModel; +import org.opentripplanner.apis.gtfs.model.StopOnRouteModel; +import org.opentripplanner.apis.gtfs.model.StopOnTripModel; import org.opentripplanner.apis.gtfs.model.StopPosition; +import org.opentripplanner.apis.gtfs.model.UnknownModel; import org.opentripplanner.ext.fares.model.FareRuleSet; import org.opentripplanner.ext.ridehailing.model.RideEstimate; import org.opentripplanner.model.StopTimesInPattern; @@ -42,6 +51,8 @@ import org.opentripplanner.routing.graphfinder.PatternAtStop; import org.opentripplanner.routing.graphfinder.PlaceAtDistance; import org.opentripplanner.routing.vehicle_parking.VehicleParking; +import org.opentripplanner.routing.vehicle_parking.VehicleParking; +import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; import org.opentripplanner.routing.vehicle_parking.VehicleParkingState; import org.opentripplanner.service.vehiclepositions.model.RealtimeVehiclePosition; @@ -50,11 +61,13 @@ import org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStation; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; +import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; import org.opentripplanner.service.vehiclerental.model.VehicleRentalVehicle; import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.organization.Agency; +import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; public class GraphQLDataFetchers { @@ -293,6 +306,29 @@ public interface GraphQLCurrency { public DataFetcher digits(); } + /** Trip on a specific date */ + public interface GraphQLDatedTrip { + public DataFetcher date(); + + public DataFetcher id(); + + public DataFetcher trip(); + } + + /** A connection to a list of dated trips */ + public interface GraphQLDatedTripConnection { + public DataFetcher>> edges(); + + public DataFetcher pageInfo(); + } + + /** An edge for DatedTrip connection */ + public interface GraphQLDatedTripEdge { + public DataFetcher cursor(); + + public DataFetcher node(); + } + /** * The standard case of a fare product: it only has a single price to be paid by the passenger * and no discounts are applied. @@ -665,6 +701,8 @@ public interface GraphQLQueryType { public DataFetcher> cancelledTripTimes(); + public DataFetcher> cancelledTrips(); + public DataFetcher carPark(); public DataFetcher> carParks(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 3593145e274..202364238ae 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -1,6 +1,7 @@ // THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. package org.opentripplanner.apis.gtfs.generated; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -1205,6 +1206,65 @@ public void setGraphQLTrips(List trips) { } } + public static class GraphQLQueryTypeCancelledTripsArgs { + + private String after; + private String before; + private List feeds; + private Integer first; + private Integer last; + + public GraphQLQueryTypeCancelledTripsArgs(Map args) { + if (args != null) { + this.after = (String) args.get("after"); + this.before = (String) args.get("before"); + this.feeds = (List) args.get("feeds"); + this.first = (Integer) args.get("first"); + this.last = (Integer) args.get("last"); + } + } + + public String getGraphQLAfter() { + return this.after; + } + + public String getGraphQLBefore() { + return this.before; + } + + public List getGraphQLFeeds() { + return this.feeds; + } + + public Integer getGraphQLFirst() { + return this.first; + } + + public Integer getGraphQLLast() { + return this.last; + } + + public void setGraphQLAfter(String after) { + this.after = after; + } + + public void setGraphQLBefore(String before) { + this.before = before; + } + + public void setGraphQLFeeds(List feeds) { + this.feeds = feeds; + } + + public void setGraphQLFirst(Integer first) { + this.first = first; + } + + public void setGraphQLLast(Integer last) { + this.last = last; + } + } + public static class GraphQLQueryTypeCarParkArgs { private String id; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 14d00ec1bd4..25002da4659 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -47,6 +47,9 @@ config: ContactInfo: org.opentripplanner.transit.model.organization.ContactInfo Cluster: Object Coordinates: org.locationtech.jts.geom.Coordinate#Coordinate + DatedTrip: org.opentripplanner.transit.model.timetable.DatedTrip#DatedTrip + DatedTripConnection: graphql.relay.Connection#Connection + DatedTripEdge: graphql.relay.Edge#Edge debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java b/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java new file mode 100644 index 00000000000..0d544bb0c72 --- /dev/null +++ b/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java @@ -0,0 +1,8 @@ +package org.opentripplanner.transit.model.timetable; + +import java.time.LocalDate; + +/** + * Class which represents a trin on a specific date + */ +public record DatedTrip(Trip trip, LocalDate serviceDate) {} diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 31c453056af..21521024384 100644 --- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -8,6 +8,7 @@ import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -46,6 +47,8 @@ import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.site.StopLocationsGroup; +import org.opentripplanner.transit.model.timetable.DatedTrip; +import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -247,6 +250,35 @@ public Trip getTripForId(FeedScopedId id) { return this.transitModelIndex.getTripForId().get(id); } + @Override + public Collection getCancelledTrips() { + OTPRequestTimeoutException.checkForTimeout(); + List cancelledTrips = new ArrayList<>(); + var timetableSnapshot = lazyGetTimeTableSnapShot(); + if (timetableSnapshot == null) { + return cancelledTrips; + } + var calendarService = getCalendarService(); + var patternMap = transitModelIndex.getPatternForTrip(); + + transitModelIndex + .getTripForId() + .values() + .forEach(trip -> { + Set serviceDates = calendarService.getServiceDatesForServiceId( + trip.getServiceId() + ); + var pattern = patternMap.get(trip); + for (LocalDate date : serviceDates) { + var tt = timetableSnapshot.resolve(pattern, date); + if (tt.getTripTimes(trip).getRealTimeState() == RealTimeState.CANCELED) { + cancelledTrips.add(new DatedTrip(trip, date)); + } + } + }); + return cancelledTrips; + } + @Override public Collection getAllTrips() { OTPRequestTimeoutException.checkForTimeout(); diff --git a/src/main/java/org/opentripplanner/transit/service/TransitService.java b/src/main/java/org/opentripplanner/transit/service/TransitService.java index 78c867ac83e..b612462fbca 100644 --- a/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -38,6 +38,7 @@ import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.site.StopLocationsGroup; +import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -108,6 +109,8 @@ public interface TransitService { Collection getAllTrips(); + Collection getCancelledTrips(); + Collection getAllRoutes(); TripPattern getPatternForTrip(Trip trip); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index aaf312244d1..20837e7699c 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2649,6 +2649,16 @@ type QueryType { maxArrivalTime: Int ): [Stoptime] + """Get cancelled Trips""" + cancelledTrips( + """Feed feedIds (e.g. ["HSL"]).""" + feeds: [String] + before: String + after: String + first: Int + last: Int + ): DatedTripConnection + """Get all patterns""" patterns: [Pattern] @@ -3974,6 +3984,27 @@ type Trip implements Node { ): [Alert] } +""" +Trip on a specific date +""" +type DatedTrip implements Node { + id: ID! + trip: Trip! + date: String! +} + +"""An edge for DatedTrip connection""" +type DatedTripEdge { + node: DatedTrip + cursor: String! +} + +"""A connection to a list of dated trips""" +type DatedTripConnection { + edges: [DatedTripEdge] + pageInfo: PageInfo! +} + """Entities, which are relevant for a trip and can contain alerts""" enum TripAlertType { """Alerts affecting the trip""" From 2e6529e9699e241ccfc9d15a55105df79ec75d12 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Tue, 3 Oct 2023 07:42:42 +0300 Subject: [PATCH 02/48] Remove duplicate imports --- .../apis/gtfs/generated/GraphQLDataFetchers.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index b4050392ed7..5f835dbbfc7 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -2,16 +2,11 @@ package org.opentripplanner.apis.gtfs.generated; import graphql.relay.Connection; -import graphql.relay.Connection; -import graphql.relay.Connection; -import graphql.relay.Edge; -import graphql.relay.Edge; import graphql.relay.Edge; import graphql.schema.DataFetcher; import graphql.schema.TypeResolver; import java.util.Currency; import java.util.Map; -import java.util.Map; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.opentripplanner.api.resource.DebugOutput; @@ -51,8 +46,6 @@ import org.opentripplanner.routing.graphfinder.PatternAtStop; import org.opentripplanner.routing.graphfinder.PlaceAtDistance; import org.opentripplanner.routing.vehicle_parking.VehicleParking; -import org.opentripplanner.routing.vehicle_parking.VehicleParking; -import org.opentripplanner.routing.vehicle_parking.VehicleParking; import org.opentripplanner.routing.vehicle_parking.VehicleParkingSpaces; import org.opentripplanner.routing.vehicle_parking.VehicleParkingState; import org.opentripplanner.service.vehiclepositions.model.RealtimeVehiclePosition; @@ -61,7 +54,6 @@ import org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStation; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; -import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; import org.opentripplanner.service.vehiclerental.model.VehicleRentalVehicle; import org.opentripplanner.transit.model.basic.Money; import org.opentripplanner.transit.model.network.Route; From 627d251c3890fe1179a78e73ecf223ba29de027c Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Tue, 3 Oct 2023 15:20:52 +0300 Subject: [PATCH 03/48] Node resolver for DatedTrip --- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 0af024b284e..4d1fb20f5a5 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -13,6 +13,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingEnvironmentImpl; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -424,7 +425,11 @@ public DataFetcher node() { return new PlaceAtDistance(place, Double.parseDouble(parts[0])); } case "DatedTrip": - return null; // ???? + { + String[] parts = id.split(";"); + var trip = transitService.getTripForId(FeedScopedId.parse(parts[0])); + return new DatedTrip(trip, LocalDate.parse(parts[1])); + } case "Route": return transitService.getRouteForId(FeedScopedId.parse(id)); case "Stop": From 6c264348bd23c995f8badd5a786b4963df330b58 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Wed, 4 Oct 2023 12:15:03 +0300 Subject: [PATCH 04/48] Hook in DatedTrip data fetcher --- .../java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index d7b936a6198..d4ada6e4552 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -38,6 +38,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.CoordinatesImpl; import org.opentripplanner.apis.gtfs.datafetchers.CurrencyImpl; +import org.opentripplanner.apis.gtfs.datafetchers.DatedTripImpl; import org.opentripplanner.apis.gtfs.datafetchers.DefaultFareProductImpl; import org.opentripplanner.apis.gtfs.datafetchers.DepartureRowImpl; import org.opentripplanner.apis.gtfs.datafetchers.FareProductTypeResolver; @@ -170,6 +171,7 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(CurrencyImpl.class)) .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) + .type(typeWiring.build(DatedTripImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); From fb71d748a1ff84266a6948396bd87b8aff4ccca0 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Wed, 4 Oct 2023 14:33:18 +0300 Subject: [PATCH 05/48] Feed filtering parameter for cancelled trips query --- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 4d1fb20f5a5..19acfcaaef2 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -798,14 +798,15 @@ public DataFetcher> trips() { @Override public DataFetcher> cancelledTrips() { return environment -> { - // var args = new GraphQLTypes.GraphQLQueryTypeGetTripsArgs(environment.getArguments()); + var args = new GraphQLTypes.GraphQLQueryTypeCancelledTripsArgs(environment.getArguments()); Stream tripStream = getTransitService(environment).getCancelledTrips().stream(); - /* if (args.getGraphQLFeeds() != null) { - List feeds = args.getGraphQLFeeds(); - tripStream = tripStream.filter(datedTrip -> feeds.contains(datedTrip.getTrip().getId().getFeedId())); - }*/ + List feeds = args.getGraphQLFeeds(); + if (feeds != null) { + tripStream = + tripStream.filter(datedTrip -> feeds.contains(datedTrip.trip().getId().getFeedId())); + } var datedTrips = tripStream.collect(Collectors.toList()); return new SimpleListConnection<>(datedTrips).get(environment); From 184e7e2ca27a1e5534db0f6f11af313c4b489fe8 Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Wed, 4 Oct 2023 15:07:53 +0300 Subject: [PATCH 06/48] More efficient iteration over all trips --- .../service/DefaultTransitService.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 21521024384..787a501adfe 100644 --- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -260,22 +260,21 @@ public Collection getCancelledTrips() { } var calendarService = getCalendarService(); var patternMap = transitModelIndex.getPatternForTrip(); - - transitModelIndex - .getTripForId() - .values() - .forEach(trip -> { - Set serviceDates = calendarService.getServiceDatesForServiceId( - trip.getServiceId() - ); - var pattern = patternMap.get(trip); - for (LocalDate date : serviceDates) { - var tt = timetableSnapshot.resolve(pattern, date); - if (tt.getTripTimes(trip).getRealTimeState() == RealTimeState.CANCELED) { - cancelledTrips.add(new DatedTrip(trip, date)); - } + var trips = transitModelIndex.getTripForId(); + + for (Map.Entry entry : trips.entrySet()) { + var trip = entry.getValue(); + Set serviceDates = calendarService.getServiceDatesForServiceId( + trip.getServiceId() + ); + var pattern = patternMap.get(trip); + for (LocalDate date : serviceDates) { + var tt = timetableSnapshot.resolve(pattern, date); + if (tt.getTripTimes(trip).getRealTimeState() == RealTimeState.CANCELED) { + cancelledTrips.add(new DatedTrip(trip, date)); } - }); + } + } return cancelledTrips; } From 2787b7e2e6f68d501280354362596e294e9e424d Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Wed, 4 Oct 2023 16:12:08 +0300 Subject: [PATCH 07/48] Sort cancelled trips by ascending time --- .../service/DefaultTransitService.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 787a501adfe..05424da9208 100644 --- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -10,6 +10,7 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -254,6 +255,8 @@ public Trip getTripForId(FeedScopedId id) { public Collection getCancelledTrips() { OTPRequestTimeoutException.checkForTimeout(); List cancelledTrips = new ArrayList<>(); + Map departures = new HashMap<>(); + var timetableSnapshot = lazyGetTimeTableSnapShot(); if (timetableSnapshot == null) { return cancelledTrips; @@ -269,12 +272,32 @@ public Collection getCancelledTrips() { ); var pattern = patternMap.get(trip); for (LocalDate date : serviceDates) { - var tt = timetableSnapshot.resolve(pattern, date); - if (tt.getTripTimes(trip).getRealTimeState() == RealTimeState.CANCELED) { + var timetable = timetableSnapshot.resolve(pattern, date); + var tripTimes = timetable.getTripTimes(trip); + if (tripTimes.getRealTimeState() == RealTimeState.CANCELED) { // use UPDATED for faked testing cancelledTrips.add(new DatedTrip(trip, date)); + // store departure time from first stop + departures.put(trip, tripTimes.sortIndex()); } } } + cancelledTrips.sort((t1, t2) -> { + if (t1.serviceDate().isBefore(t2.serviceDate())) { + return -1; + } else if (t2.serviceDate().isBefore(t1.serviceDate())) { + return 1; + } + var departure1 = departures.get(t1.trip()); + var departure2 = departures.get(t2.trip()); + if (departure1 < departure2) { + return -1; + } else if (departure1 > departure2) { + return 1; + } else { + // identical departure day and time, so sort by unique feedscope id + return t1.trip().getId().compareTo(t2.trip().getId()); + } + }); return cancelledTrips; } From 58f0387ef867cd6061d2311dde41e644d2850ddc Mon Sep 17 00:00:00 2001 From: Vesa Meskanen Date: Wed, 4 Oct 2023 16:44:31 +0300 Subject: [PATCH 08/48] Move filtering by feed into transit service It is much more efficient to filter trips in early stage --- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 14 ++++---------- .../transit/service/DefaultTransitService.java | 9 ++++++--- .../transit/service/TransitService.java | 2 +- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 19acfcaaef2..cf1f6c87f0f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -799,16 +799,10 @@ public DataFetcher> trips() { public DataFetcher> cancelledTrips() { return environment -> { var args = new GraphQLTypes.GraphQLQueryTypeCancelledTripsArgs(environment.getArguments()); - - Stream tripStream = getTransitService(environment).getCancelledTrips().stream(); - - List feeds = args.getGraphQLFeeds(); - if (feeds != null) { - tripStream = - tripStream.filter(datedTrip -> feeds.contains(datedTrip.trip().getId().getFeedId())); - } - - var datedTrips = tripStream.collect(Collectors.toList()); + var datedTrips = getTransitService(environment) + .getCancelledTrips(args.getGraphQLFeeds()) + .stream() + .collect(Collectors.toList()); return new SimpleListConnection<>(datedTrips).get(environment); }; } diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 05424da9208..cecb62d7635 100644 --- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -252,7 +252,7 @@ public Trip getTripForId(FeedScopedId id) { } @Override - public Collection getCancelledTrips() { + public Collection getCancelledTrips(List feeds) { OTPRequestTimeoutException.checkForTimeout(); List cancelledTrips = new ArrayList<>(); Map departures = new HashMap<>(); @@ -267,6 +267,9 @@ public Collection getCancelledTrips() { for (Map.Entry entry : trips.entrySet()) { var trip = entry.getValue(); + if (feeds != null && !feeds.contains(trip.getId().getFeedId())) { + continue; + } Set serviceDates = calendarService.getServiceDatesForServiceId( trip.getServiceId() ); @@ -276,7 +279,7 @@ public Collection getCancelledTrips() { var tripTimes = timetable.getTripTimes(trip); if (tripTimes.getRealTimeState() == RealTimeState.CANCELED) { // use UPDATED for faked testing cancelledTrips.add(new DatedTrip(trip, date)); - // store departure time from first stop + // store departure time from first stop departures.put(trip, tripTimes.sortIndex()); } } @@ -294,7 +297,7 @@ public Collection getCancelledTrips() { } else if (departure1 > departure2) { return 1; } else { - // identical departure day and time, so sort by unique feedscope id + // identical departure day and time, so sort by unique feedscope id return t1.trip().getId().compareTo(t2.trip().getId()); } }); diff --git a/src/main/java/org/opentripplanner/transit/service/TransitService.java b/src/main/java/org/opentripplanner/transit/service/TransitService.java index b612462fbca..bb3b1b54ab1 100644 --- a/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -109,7 +109,7 @@ public interface TransitService { Collection getAllTrips(); - Collection getCancelledTrips(); + Collection getCancelledTrips(List feeds); Collection getAllRoutes(); From 20df02b87e3598524100587dc9fbe30ee87117e8 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Wed, 7 Aug 2024 19:52:54 +0300 Subject: [PATCH 09/48] Use LocalDate for date and include trip's fields instead of trip --- .../apis/gtfs/datafetchers/DatedTripImpl.java | 88 +++++++++++++++++-- .../gtfs/generated/GraphQLDataFetchers.java | 14 ++- .../apis/gtfs/generated/GraphQLTypes.java | 41 ++++++--- .../transit/model/timetable/DatedTrip.java | 2 +- .../opentripplanner/apis/gtfs/schema.graphqls | 28 +++++- 5 files changed, 150 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java index 599f4038190..f8bdf40dbc2 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java @@ -3,21 +3,26 @@ import graphql.relay.Relay; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.Instant; +import java.time.LocalDate; +import java.util.List; +import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.ext.restapi.mapping.LocalDateMapper; +import org.opentripplanner.framework.time.ServiceDateUtils; +import org.opentripplanner.model.Timetable; +import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.service.TransitService; public class DatedTripImpl implements GraphQLDataFetchers.GraphQLDatedTrip { @Override - public DataFetcher date() { - return env -> LocalDateMapper.mapToApi(getSource(env).serviceDate()); - } - - @Override - public DataFetcher trip() { - return env -> getSource(env).trip(); + public DataFetcher date() { + return env -> getSource(env).serviceDate(); } @Override @@ -31,6 +36,75 @@ public DataFetcher id() { ); } + @Override + public DataFetcher pattern() { + return this::getTripPattern; + } + + @Override + public DataFetcher route() { + return environment -> getSource(environment).trip().getRoute(); + } + + @Override + public DataFetcher> stops() { + return this::getStops; + } + + @Override + public DataFetcher> stoptimes() { + return environment -> { + TransitService transitService = getTransitService(environment); + Trip trip = getSource(environment).trip(); + + var serviceDate = getSource(environment).serviceDate(); + TripPattern tripPattern = transitService.getPatternForTrip(trip, serviceDate); + // no matching pattern found + if (tripPattern == null) { + return List.of(); + } + + Instant midnight = ServiceDateUtils + .asStartOfService(serviceDate, transitService.getTimeZone()) + .toInstant(); + Timetable timetable = transitService.getTimetableForTripPattern(tripPattern, serviceDate); + if (timetable == null) { + return List.of(); + } + return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); + }; + } + + @Override + public DataFetcher tripHeadsign() { + return environment -> + org.opentripplanner.framework.graphql.GraphQLUtils.getTranslation( + getSource(environment).trip().getHeadsign(), + environment + ); + } + + @Override + public DataFetcher tripShortName() { + return environment -> getSource(environment).trip().getShortName(); + } + + private List getStops(DataFetchingEnvironment environment) { + TripPattern tripPattern = getTripPattern(environment); + if (tripPattern == null) { + return List.of(); + } + return List.copyOf(tripPattern.getStops()); + } + + private TripPattern getTripPattern(DataFetchingEnvironment environment) { + return getTransitService(environment).getPatternForTrip(getSource(environment).trip()); + } + + private TransitService getTransitService(DataFetchingEnvironment environment) { + return environment.getContext().transitService(); + } + private DatedTrip getSource(DataFetchingEnvironment environment) { return environment.getSource(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index b23a3273518..5c11022cac2 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -317,11 +317,21 @@ public interface GraphQLCurrency { /** Trip on a specific date */ public interface GraphQLDatedTrip { - public DataFetcher date(); + public DataFetcher date(); public DataFetcher id(); - public DataFetcher trip(); + public DataFetcher pattern(); + + public DataFetcher route(); + + public DataFetcher> stops(); + + public DataFetcher> stoptimes(); + + public DataFetcher tripHeadsign(); + + public DataFetcher tripShortName(); } /** A connection to a list of dated trips */ diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 96212d00b39..acac4d61969 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -601,8 +601,8 @@ public void setGraphQLType(GraphQLCyclingOptimizationType type) { } /** - * Predefined optimization alternatives for bicycling routing. For more customization, one can use - * the triangle factors. + * Predefined optimization alternatives for bicycling routing. For more customization, + * one can use the triangle factors. */ public enum GraphQLCyclingOptimizationType { FLAT_STREETS, @@ -611,6 +611,25 @@ public enum GraphQLCyclingOptimizationType { SHORTEST_DURATION, } + public static class GraphQLDatedTripTripHeadsignArgs { + + private String language; + + public GraphQLDatedTripTripHeadsignArgs(Map args) { + if (args != null) { + this.language = (String) args.get("language"); + } + } + + public String getGraphQLLanguage() { + return this.language; + } + + public void setGraphQLLanguage(String language) { + this.language = language; + } + } + public static class GraphQLDepartureRowStoptimesArgs { private Integer numberOfDepartures; @@ -2007,8 +2026,8 @@ public enum GraphQLPropulsionType { } /** - * Additional qualifier for a transport mode. Note that qualifiers can only be used with certain - * transport modes. + * Additional qualifier for a transport mode. + * Note that qualifiers can only be used with certain transport modes. */ public enum GraphQLQualifier { ACCESS, @@ -4118,8 +4137,8 @@ public void setGraphQLType(GraphQLScooterOptimizationType type) { } /** - * Predefined optimization alternatives for scooter routing. For more customization, one can use - * the triangle factors. + * Predefined optimization alternatives for scooter routing. For more customization, + * one can use the triangle factors. */ public enum GraphQLScooterOptimizationType { FLAT_STREETS, @@ -4673,9 +4692,9 @@ public void setGraphQLSlack(java.time.Duration slack) { } /** - * Transit modes include modes that are used within organized transportation networks run by - * public transportation authorities, taxi companies etc. Equivalent to GTFS route_type or to - * NeTEx TransportMode. + * Transit modes include modes that are used within organized transportation networks + * run by public transportation authorities, taxi companies etc. + * Equivalent to GTFS route_type or to NeTEx TransportMode. */ public enum GraphQLTransitMode { AIRPLANE, @@ -5076,8 +5095,8 @@ public void setGraphQLUnpreferredCost(Integer unpreferredCost) { } /** - * The state of the vehicle parking. TEMPORARILY_CLOSED and CLOSED are distinct states so that - * they may be represented differently to the user. + * The state of the vehicle parking. TEMPORARILY_CLOSED and CLOSED are distinct states so that they + * may be represented differently to the user. */ public enum GraphQLVehicleParkingState { CLOSED, diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java b/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java index 0d544bb0c72..2227421ed0e 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java @@ -3,6 +3,6 @@ import java.time.LocalDate; /** - * Class which represents a trin on a specific date + * Class which represents a trip on a specific date */ public record DatedTrip(Trip trip, LocalDate serviceDate) {} diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 6725126fe9d..5dbbc397b29 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -386,9 +386,33 @@ type Currency { "Trip on a specific date" type DatedTrip implements Node { - date: String! + """ + The service date when the trip occurs. + + **Note**: A service date is a technical term useful for transit planning purposes and might not + correspond to a how a passenger thinks of a calendar date. For example, a night bus running + on Sunday morning at 1am to 3am, might have the previous Saturday's service date. + """ + date: LocalDate! + "Global object ID provided by Relay. This value can be used to refetch this object using **node** query." id: ID! - trip: Trip! + "The pattern the trip is running on" + pattern: Pattern + "The route the trip is running on" + route: Route! + "List of stops this trip passes through" + stops: [Stop!]! + "List of times when this trip arrives to or departs from a stop" + stoptimes: [Stoptime] + "Headsign of the vehicle when running on this trip" + tripHeadsign( + """ + If a translated headsign is found from GTFS translation.txt and wanted language is not same as + feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. + """ + language: String + ): String + tripShortName: String } "A connection to a list of dated trips" From 2a9df2aaff1a4789b8fd2c1a190bfb7d65020a8c Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Thu, 8 Aug 2024 11:31:48 +0300 Subject: [PATCH 10/48] Improve documentation and mark cancelledTripTimes as deprecated --- .../gtfs/generated/GraphQLDataFetchers.java | 10 ++++-- .../opentripplanner/apis/gtfs/schema.graphqls | 35 ++++++++++++++++--- 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 5c11022cac2..2239c61d6cb 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -334,14 +334,20 @@ public interface GraphQLDatedTrip { public DataFetcher tripShortName(); } - /** A connection to a list of dated trips */ + /** + * A connection to a list of dated trips that follows + * [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + */ public interface GraphQLDatedTripConnection { public DataFetcher>> edges(); public DataFetcher pageInfo(); } - /** An edge for DatedTrip connection */ + /** + * An edge for DatedTrip connection. Part of the + * [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + */ public interface GraphQLDatedTripEdge { public DataFetcher cursor(); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 5dbbc397b29..7072ef4b376 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -388,7 +388,7 @@ type Currency { type DatedTrip implements Node { """ The service date when the trip occurs. - + **Note**: A service date is a technical term useful for transit planning purposes and might not correspond to a how a passenger thinks of a calendar date. For example, a night bus running on Sunday morning at 1am to 3am, might have the previous Saturday's service date. @@ -415,15 +415,37 @@ type DatedTrip implements Node { tripShortName: String } -"A connection to a list of dated trips" +""" +A connection to a list of dated trips that follows +[GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). +""" type DatedTripConnection { + """ + Edges which contain the trips. Part of the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ edges: [DatedTripEdge] + """ + Contains cursors to fetch more pages of trips. + Part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ pageInfo: PageInfo! } -"An edge for DatedTrip connection" +""" +An edge for DatedTrip connection. Part of the +[GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). +""" type DatedTripEdge { + """ + The cursor of the edge. Part of the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ cursor: String! + """ + Dated trip as a node. Part of the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ node: DatedTrip } @@ -1170,8 +1192,11 @@ type QueryType { routes: [String], "Trip gtfsIds (e.g. [\"HSL:1098_20190405_Ma_2_1455\"])." trips: [String] - ): [Stoptime] - "Get cancelled Trips" + ): [Stoptime] @deprecated(reason : "`cancelledTripTimes` is deprecated. Use `cancelledTrips` instead.") + """ + Get pages of cancelled Trips. Follows the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ cancelledTrips( after: String, before: String, From b142bdf06d08eebb40f76d9ef043424bf24fe46e Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Thu, 8 Aug 2024 15:59:27 +0300 Subject: [PATCH 11/48] Add start and end to schema --- .../apis/gtfs/GraphQLUtils.java | 15 ++++ .../apis/gtfs/datafetchers/DatedTripImpl.java | 86 +++++++++++++++++-- .../apis/gtfs/datafetchers/StoptimeImpl.java | 25 ++---- .../gtfs/generated/GraphQLDataFetchers.java | 15 ++++ .../apis/gtfs/generated/graphql-codegen.yml | 1 + .../apis/gtfs/model/DatedTripTime.java | 31 +++++++ .../model/plan/ScheduledTransitLeg.java | 7 +- .../model/timetable/RealTimeTripTimes.java | 7 ++ .../model/timetable/ScheduledTripTimes.java | 5 ++ .../transit/model/timetable/TripTimes.java | 5 ++ .../opentripplanner/apis/gtfs/schema.graphqls | 15 ++++ 11 files changed, 182 insertions(+), 30 deletions(-) create mode 100644 src/main/java/org/opentripplanner/apis/gtfs/model/DatedTripTime.java diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java index 3fb339daa32..fe63add7d49 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLUtils.java @@ -2,6 +2,7 @@ import java.time.Instant; import java.util.Locale; +import javax.annotation.Nullable; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLFilterPlaceType; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLFormFactor; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField; @@ -9,6 +10,7 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLWheelchairBoarding; import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.model.StopTime; import org.opentripplanner.routing.api.response.InputField; import org.opentripplanner.routing.api.response.RoutingErrorCode; import org.opentripplanner.routing.graphfinder.PlaceType; @@ -109,4 +111,17 @@ public static boolean startsWith(String str, String name, Locale locale) { public static boolean startsWith(I18NString str, String name, Locale locale) { return str != null && str.toString(locale).toLowerCase(locale).startsWith(name); } + + /** + * Generally the missing values are removed during the graph build. However, for flex trips they + * are not and have to be converted to null here. + */ + @Nullable + public static Integer stopTimeToInt(int value) { + if (value == StopTime.MISSING_VALUE) { + return null; + } else { + return value; + } + } } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java index f8bdf40dbc2..eb820fc06c5 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java @@ -1,13 +1,18 @@ package org.opentripplanner.apis.gtfs.datafetchers; +import static org.opentripplanner.apis.gtfs.GraphQLUtils.stopTimeToInt; + import graphql.relay.Relay; import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import java.time.Instant; import java.time.LocalDate; +import java.time.ZonedDateTime; import java.util.List; +import javax.annotation.Nullable; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.apis.gtfs.model.DatedTripTime; import org.opentripplanner.ext.restapi.mapping.LocalDateMapper; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.model.Timetable; @@ -16,6 +21,7 @@ import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.transit.service.TransitService; public class DatedTripImpl implements GraphQLDataFetchers.GraphQLDatedTrip { @@ -25,6 +31,24 @@ public DataFetcher date() { return env -> getSource(env).serviceDate(); } + @Override + public DataFetcher end() { + return env -> { + var tripTimes = getTripTimes(env); + if (tripTimes == null) { + return null; + } + var stopIndex = tripTimes.getNumStops() - 1; + var scheduledTime = getZonedDateTime(env, tripTimes.getScheduledArrivalTime(stopIndex)); + if (scheduledTime == null) { + return null; + } + return tripTimes.isRealtimeUpdated(stopIndex) + ? DatedTripTime.of(scheduledTime, tripTimes.getArrivalDelay(stopIndex)) + : DatedTripTime.ofStatic(scheduledTime); + }; + } + @Override public DataFetcher id() { return env -> @@ -46,6 +70,23 @@ public DataFetcher route() { return environment -> getSource(environment).trip().getRoute(); } + @Override + public DataFetcher start() { + return env -> { + var tripTimes = getTripTimes(env); + if (tripTimes == null) { + return null; + } + var scheduledTime = getZonedDateTime(env, tripTimes.getScheduledDepartureTime(0)); + if (scheduledTime == null) { + return null; + } + return tripTimes.isRealtimeUpdated(0) + ? DatedTripTime.of(scheduledTime, tripTimes.getDepartureDelay(0)) + : DatedTripTime.ofStatic(scheduledTime); + }; + } + @Override public DataFetcher> stops() { return this::getStops; @@ -56,18 +97,12 @@ public DataFetcher> stoptimes() { return environment -> { TransitService transitService = getTransitService(environment); Trip trip = getSource(environment).trip(); - var serviceDate = getSource(environment).serviceDate(); - TripPattern tripPattern = transitService.getPatternForTrip(trip, serviceDate); - // no matching pattern found - if (tripPattern == null) { - return List.of(); - } Instant midnight = ServiceDateUtils .asStartOfService(serviceDate, transitService.getTimeZone()) .toInstant(); - Timetable timetable = transitService.getTimetableForTripPattern(tripPattern, serviceDate); + Timetable timetable = getTimetable(environment, trip, serviceDate); if (timetable == null) { return List.of(); } @@ -101,6 +136,43 @@ private TripPattern getTripPattern(DataFetchingEnvironment environment) { return getTransitService(environment).getPatternForTrip(getSource(environment).trip()); } + @Nullable + private Timetable getTimetable( + DataFetchingEnvironment environment, + Trip trip, + LocalDate serviceDate + ) { + TransitService transitService = getTransitService(environment); + TripPattern tripPattern = transitService.getPatternForTrip(trip, serviceDate); + // no matching pattern found + if (tripPattern == null) { + return null; + } + + return transitService.getTimetableForTripPattern(tripPattern, serviceDate); + } + + @Nullable + private TripTimes getTripTimes(DataFetchingEnvironment environment) { + Trip trip = getSource(environment).trip(); + var serviceDate = getSource(environment).serviceDate(); + var timetable = getTimetable(environment, trip, serviceDate); + if (timetable == null) { + return null; + } + return timetable.getTripTimes(trip); + } + + private ZonedDateTime getZonedDateTime(DataFetchingEnvironment environment, int time) { + var fixedTime = stopTimeToInt(time); + if (fixedTime == null) { + return null; + } + var serviceDate = getSource(environment).serviceDate(); + TransitService transitService = getTransitService(environment); + return ServiceDateUtils.toZonedDateTime(serviceDate, transitService.getTimeZone(), fixedTime); + } + private TransitService getTransitService(DataFetchingEnvironment environment) { return environment.getContext().transitService(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java index faf59ef9d6e..706c5a4fd5e 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -1,10 +1,11 @@ package org.opentripplanner.apis.gtfs.datafetchers; +import static org.opentripplanner.apis.gtfs.GraphQLUtils.stopTimeToInt; + import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.framework.graphql.GraphQLUtils; -import org.opentripplanner.model.StopTime; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; @@ -13,7 +14,7 @@ public class StoptimeImpl implements GraphQLDataFetchers.GraphQLStoptime { @Override public DataFetcher arrivalDelay() { - return environment -> missingValueToNull(getSource(environment).getArrivalDelay()); + return environment -> stopTimeToInt(getSource(environment).getArrivalDelay()); } @Override @@ -58,12 +59,12 @@ public DataFetcher realtime() { @Override public DataFetcher realtimeArrival() { - return environment -> missingValueToNull(getSource(environment).getRealtimeArrival()); + return environment -> stopTimeToInt(getSource(environment).getRealtimeArrival()); } @Override public DataFetcher realtimeDeparture() { - return environment -> missingValueToNull(getSource(environment).getRealtimeDeparture()); + return environment -> stopTimeToInt(getSource(environment).getRealtimeDeparture()); } @Override @@ -76,12 +77,12 @@ public DataFetcher realtimeState() { @Override public DataFetcher scheduledArrival() { - return environment -> missingValueToNull(getSource(environment).getScheduledArrival()); + return environment -> stopTimeToInt(getSource(environment).getScheduledArrival()); } @Override public DataFetcher scheduledDeparture() { - return environment -> missingValueToNull(getSource(environment).getScheduledDeparture()); + return environment -> stopTimeToInt(getSource(environment).getScheduledDeparture()); } @Override @@ -112,16 +113,4 @@ public DataFetcher trip() { private TripTimeOnDate getSource(DataFetchingEnvironment environment) { return environment.getSource(); } - - /** - * Generally the missing values are removed during the graph build. However, for flex trips they - * are not and have to be converted to null here. - */ - private Integer missingValueToNull(int value) { - if (value == StopTime.MISSING_VALUE) { - return null; - } else { - return value; - } - } } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 2239c61d6cb..259d6db86b0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -21,6 +21,7 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRelativeDirection; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRoutingErrorCode; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; +import org.opentripplanner.apis.gtfs.model.DatedTripTime; import org.opentripplanner.apis.gtfs.model.FeedPublisher; import org.opentripplanner.apis.gtfs.model.PlanPageInfo; import org.opentripplanner.apis.gtfs.model.RideHailingProvider; @@ -319,12 +320,16 @@ public interface GraphQLCurrency { public interface GraphQLDatedTrip { public DataFetcher date(); + public DataFetcher end(); + public DataFetcher id(); public DataFetcher pattern(); public DataFetcher route(); + public DataFetcher start(); + public DataFetcher> stops(); public DataFetcher> stoptimes(); @@ -354,6 +359,16 @@ public interface GraphQLDatedTripEdge { public DataFetcher node(); } + /** + * Information about a dated trip's start or end times. May contain real-time information if + * available. + */ + public interface GraphQLDatedTripTime { + public DataFetcher estimated(); + + public DataFetcher scheduledTime(); + } + /** * The standard case of a fare product: it only has a single price to be paid by the passenger * and no discounts are applied. diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 465321a58e3..6eb98a7f95b 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -62,6 +62,7 @@ config: DatedTrip: org.opentripplanner.transit.model.timetable.DatedTrip#DatedTrip DatedTripConnection: graphql.relay.Connection#Connection DatedTripEdge: graphql.relay.Edge#Edge + DatedTripTime: org.opentripplanner.apis.gtfs.model.DatedTripTime#DatedTripTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step diff --git a/src/main/java/org/opentripplanner/apis/gtfs/model/DatedTripTime.java b/src/main/java/org/opentripplanner/apis/gtfs/model/DatedTripTime.java new file mode 100644 index 00000000000..a83eb50fe1d --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/gtfs/model/DatedTripTime.java @@ -0,0 +1,31 @@ +package org.opentripplanner.apis.gtfs.model; + +import java.time.Duration; +import java.time.ZonedDateTime; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * A scheduled time of a trip's start or end with an optional realtime information. + */ +public record DatedTripTime( + @Nonnull ZonedDateTime scheduledTime, + @Nullable RealTimeEstimate estimated +) { + @Nonnull + public static DatedTripTime of(ZonedDateTime realtime, int delaySecs) { + var delay = Duration.ofSeconds(delaySecs); + return new DatedTripTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); + } + + @Nonnull + public static DatedTripTime ofStatic(ZonedDateTime staticTime) { + return new DatedTripTime(staticTime, null); + } + + /** + * Realtime information about a vehicle at a certain place. + * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. + */ + record RealTimeEstimate(ZonedDateTime time, Duration delay) {} +} diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index d94ec1895c2..4a84ac6e799 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -219,11 +219,8 @@ public int getArrivalDelay() { @Override public boolean getRealTime() { return ( - !tripTimes.isScheduled() && - ( - !tripTimes.isNoDataStop(boardStopPosInPattern) || - !tripTimes.isNoDataStop(alightStopPosInPattern) - ) + tripTimes.isRealtimeUpdated(boardStopPosInPattern) || + tripTimes.isRealtimeUpdated(alightStopPosInPattern) ); } diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java b/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java index 711eb1c221c..ca5897b7b24 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java @@ -198,6 +198,13 @@ public boolean isPredictionInaccurate(int stop) { return isStopRealTimeStates(stop, StopRealTimeState.INACCURATE_PREDICTIONS); } + public boolean isRealtimeUpdated(int stop) { + return ( + realTimeState != RealTimeState.SCHEDULED && + !isStopRealTimeStates(stop, StopRealTimeState.NO_DATA) + ); + } + public void setOccupancyStatus(int stop, OccupancyStatus occupancyStatus) { prepareForRealTimeUpdates(); this.occupancyStatus[stop] = occupancyStatus; diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java b/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java index d367932d24d..3799fd7b140 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java @@ -234,6 +234,11 @@ public boolean isPredictionInaccurate(int stop) { return false; } + @Override + public boolean isRealtimeUpdated(int stop) { + return false; + } + @Override public I18NString getTripHeadsign() { return trip.getHeadsign(); diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java b/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java index e5cd1f1ff28..ea1a3f8ab2b 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java @@ -123,6 +123,11 @@ default int compareTo(TripTimes other) { boolean isPredictionInaccurate(int stop); + /** + * Return if trip has been updated and stop has not been given a NO_DATA update. + */ + boolean isRealtimeUpdated(int stop); + /** * @return the whole trip's headsign. Individual stops can have different headsigns. */ diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 7072ef4b376..fb287c5c117 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -394,12 +394,16 @@ type DatedTrip implements Node { on Sunday morning at 1am to 3am, might have the previous Saturday's service date. """ date: LocalDate! + "The time when the trip ends including real-time information, if available." + end: DatedTripTime "Global object ID provided by Relay. This value can be used to refetch this object using **node** query." id: ID! "The pattern the trip is running on" pattern: Pattern "The route the trip is running on" route: Route! + "The time when the trip starts including real-time information, if available." + start: DatedTripTime "List of stops this trip passes through" stops: [Stop!]! "List of times when this trip arrives to or departs from a stop" @@ -449,6 +453,17 @@ type DatedTripEdge { node: DatedTrip } +""" +Information about a dated trip's start or end times. May contain real-time information if +available. +""" +type DatedTripTime { + "The estimated time of the event. If no real-time information is available, this is null." + estimated: RealTimeEstimate + "The scheduled time of the event." + scheduledTime: OffsetDateTime +} + """ The standard case of a fare product: it only has a single price to be paid by the passenger and no discounts are applied. From 8e12d3a626c5d7c685be9c89c3f1977eece7c9d4 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 9 Aug 2024 16:08:11 +0300 Subject: [PATCH 12/48] Create DatedStopTime type and use it in DatedTrip --- .../apis/gtfs/GtfsGraphQLIndex.java | 2 + .../gtfs/datafetchers/DatedStopTimeImpl.java | 117 ++++++++++++++++++ .../apis/gtfs/datafetchers/DatedTripImpl.java | 14 +-- .../apis/gtfs/datafetchers/StoptimeImpl.java | 19 +-- .../gtfs/generated/GraphQLDataFetchers.java | 48 +++++-- .../apis/gtfs/generated/GraphQLTypes.java | 29 +++++ .../apis/gtfs/generated/graphql-codegen.yml | 4 +- .../apis/gtfs/mapping/PickDropMapper.java | 18 +++ ...ripTime.java => ArrivalDepartureTime.java} | 13 +- .../opentripplanner/model/TripTimeOnDate.java | 8 ++ .../opentripplanner/apis/gtfs/schema.graphqls | 96 +++++++++++--- 11 files changed, 311 insertions(+), 57 deletions(-) create mode 100644 src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeImpl.java create mode 100644 src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java rename src/main/java/org/opentripplanner/apis/gtfs/model/{DatedTripTime.java => ArrivalDepartureTime.java} (56%) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 163b32de751..a160e197611 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -35,6 +35,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.CoordinatesImpl; import org.opentripplanner.apis.gtfs.datafetchers.CurrencyImpl; +import org.opentripplanner.apis.gtfs.datafetchers.DatedStopTimeImpl; import org.opentripplanner.apis.gtfs.datafetchers.DatedTripImpl; import org.opentripplanner.apis.gtfs.datafetchers.DefaultFareProductImpl; import org.opentripplanner.apis.gtfs.datafetchers.DepartureRowImpl; @@ -180,6 +181,7 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) .type(typeWiring.build(DatedTripImpl.class)) + .type(typeWiring.build(DatedStopTimeImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeImpl.java new file mode 100644 index 00000000000..3ed12ac4fb6 --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeImpl.java @@ -0,0 +1,117 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import static org.opentripplanner.apis.gtfs.GraphQLUtils.stopTimeToInt; + +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import java.time.ZonedDateTime; +import org.opentripplanner.apis.gtfs.GraphQLRequestContext; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; +import org.opentripplanner.apis.gtfs.mapping.PickDropMapper; +import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; +import org.opentripplanner.framework.graphql.GraphQLUtils; +import org.opentripplanner.framework.time.ServiceDateUtils; +import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.transit.service.TransitService; + +public class DatedStopTimeImpl implements GraphQLDataFetchers.GraphQLDatedStopTime { + + @Override + public DataFetcher arrival() { + return environment -> { + var tripTime = getSource(environment); + var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledArrival()); + if (scheduledTime == null) { + return null; + } + return tripTime.isRealtime() + ? ArrivalDepartureTime.of(scheduledTime, tripTime.getArrivalDelay()) + : ArrivalDepartureTime.ofStatic(scheduledTime); + }; + } + + @Override + public DataFetcher departure() { + return environment -> { + var tripTime = getSource(environment); + var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledDeparture()); + if (scheduledTime == null) { + return null; + } + return tripTime.isRealtime() + ? ArrivalDepartureTime.of(scheduledTime, tripTime.getDepartureDelay()) + : ArrivalDepartureTime.ofStatic(scheduledTime); + }; + } + + @Override + public DataFetcher dropoffType() { + return environment -> PickDropMapper.map(getSource(environment).getDropoffType()); + } + + @Override + public DataFetcher headsign() { + return environment -> + GraphQLUtils.getTranslation(getSource(environment).getHeadsign(), environment); + } + + @Override + public DataFetcher pickupType() { + return environment -> PickDropMapper.map(getSource(environment).getPickupType()); + } + + @Override + public DataFetcher realtimeState() { + return environment -> { + var tripTime = getSource(environment); + // TODO support ADDED state + if (tripTime.isCanceledEffectively()) { + return GraphQLTypes.GraphQLStopRealTimeState.CANCELED; + } + if (tripTime.isNoDataStop()) { + return GraphQLTypes.GraphQLStopRealTimeState.NO_DATA; + } + if (tripTime.isRecordedStop()) { + return GraphQLTypes.GraphQLStopRealTimeState.RECORDED; + } + if (tripTime.isRealtime()) { + return GraphQLTypes.GraphQLStopRealTimeState.UPDATED; + } + return GraphQLTypes.GraphQLStopRealTimeState.UNUPDATED; + }; + } + + @Override + public DataFetcher stopPosition() { + return environment -> getSource(environment).getGtfsSequence(); + } + + @Override + public DataFetcher stop() { + return environment -> getSource(environment).getStop(); + } + + @Override + public DataFetcher timepoint() { + return environment -> getSource(environment).isTimepoint(); + } + + private TransitService getTransitService(DataFetchingEnvironment environment) { + return environment.getContext().transitService(); + } + + private ZonedDateTime getZonedDateTime(DataFetchingEnvironment environment, int time) { + var fixedTime = stopTimeToInt(time); + if (fixedTime == null) { + return null; + } + var serviceDate = getSource(environment).getServiceDay(); + TransitService transitService = getTransitService(environment); + return ServiceDateUtils.toZonedDateTime(serviceDate, transitService.getTimeZone(), fixedTime); + } + + private TripTimeOnDate getSource(DataFetchingEnvironment environment) { + return environment.getSource(); + } +} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java index eb820fc06c5..5d567d83264 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java @@ -12,7 +12,7 @@ import javax.annotation.Nullable; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.apis.gtfs.model.DatedTripTime; +import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; import org.opentripplanner.ext.restapi.mapping.LocalDateMapper; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.model.Timetable; @@ -32,7 +32,7 @@ public DataFetcher date() { } @Override - public DataFetcher end() { + public DataFetcher end() { return env -> { var tripTimes = getTripTimes(env); if (tripTimes == null) { @@ -44,8 +44,8 @@ public DataFetcher end() { return null; } return tripTimes.isRealtimeUpdated(stopIndex) - ? DatedTripTime.of(scheduledTime, tripTimes.getArrivalDelay(stopIndex)) - : DatedTripTime.ofStatic(scheduledTime); + ? ArrivalDepartureTime.of(scheduledTime, tripTimes.getArrivalDelay(stopIndex)) + : ArrivalDepartureTime.ofStatic(scheduledTime); }; } @@ -71,7 +71,7 @@ public DataFetcher route() { } @Override - public DataFetcher start() { + public DataFetcher start() { return env -> { var tripTimes = getTripTimes(env); if (tripTimes == null) { @@ -82,8 +82,8 @@ public DataFetcher start() { return null; } return tripTimes.isRealtimeUpdated(0) - ? DatedTripTime.of(scheduledTime, tripTimes.getDepartureDelay(0)) - : DatedTripTime.ofStatic(scheduledTime); + ? ArrivalDepartureTime.of(scheduledTime, tripTimes.getDepartureDelay(0)) + : ArrivalDepartureTime.ofStatic(scheduledTime); }; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java index 706c5a4fd5e..2a433fadee0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -5,6 +5,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.apis.gtfs.mapping.PickDropMapper; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.model.timetable.RealTimeState; @@ -24,14 +25,7 @@ public DataFetcher departureDelay() { @Override public DataFetcher dropoffType() { - return environment -> - switch (getSource(environment).getDropoffType()) { - case SCHEDULED -> "SCHEDULED"; - case NONE -> "NONE"; - case CALL_AGENCY -> "CALL_AGENCY"; - case COORDINATE_WITH_DRIVER -> "COORDINATE_WITH_DRIVER"; - case CANCELLED -> null; - }; + return environment -> PickDropMapper.map(getSource(environment).getDropoffType()); } @Override @@ -42,14 +36,7 @@ public DataFetcher headsign() { @Override public DataFetcher pickupType() { - return environment -> - switch (getSource(environment).getPickupType()) { - case SCHEDULED -> "SCHEDULED"; - case NONE -> "NONE"; - case CALL_AGENCY -> "CALL_AGENCY"; - case COORDINATE_WITH_DRIVER -> "COORDINATE_WITH_DRIVER"; - case CANCELLED -> null; - }; + return environment -> PickDropMapper.map(getSource(environment).getPickupType()); } @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 259d6db86b0..ff12746df68 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -20,8 +20,9 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRelativeDirection; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRoutingErrorCode; +import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLStopRealTimeState; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; -import org.opentripplanner.apis.gtfs.model.DatedTripTime; +import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; import org.opentripplanner.apis.gtfs.model.FeedPublisher; import org.opentripplanner.apis.gtfs.model.PlanPageInfo; import org.opentripplanner.apis.gtfs.model.RideHailingProvider; @@ -141,6 +142,16 @@ public interface GraphQLAlert { /** Entity related to an alert */ public interface GraphQLAlertEntity extends TypeResolver {} + /** + * Timing of an arrival or a departure to or from a stop. May contain real-time information if + * available. + */ + public interface GraphQLArrivalDepartureTime { + public DataFetcher estimated(); + + public DataFetcher scheduledTime(); + } + /** Bike park represents a location where bicycles can be parked. */ public interface GraphQLBikePark { public DataFetcher bikeParkId(); @@ -316,11 +327,32 @@ public interface GraphQLCurrency { public DataFetcher digits(); } + /** Stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. */ + public interface GraphQLDatedStopTime { + public DataFetcher arrival(); + + public DataFetcher departure(); + + public DataFetcher dropoffType(); + + public DataFetcher headsign(); + + public DataFetcher pickupType(); + + public DataFetcher realtimeState(); + + public DataFetcher stop(); + + public DataFetcher stopPosition(); + + public DataFetcher timepoint(); + } + /** Trip on a specific date */ public interface GraphQLDatedTrip { public DataFetcher date(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher id(); @@ -328,7 +360,7 @@ public interface GraphQLDatedTrip { public DataFetcher route(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher> stops(); @@ -359,16 +391,6 @@ public interface GraphQLDatedTripEdge { public DataFetcher node(); } - /** - * Information about a dated trip's start or end times. May contain real-time information if - * available. - */ - public interface GraphQLDatedTripTime { - public DataFetcher estimated(); - - public DataFetcher scheduledTime(); - } - /** * The standard case of a fare product: it only has a single price to be paid by the passenger * and no discounts are applied. diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index acac4d61969..3d9b627154a 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -611,6 +611,25 @@ public enum GraphQLCyclingOptimizationType { SHORTEST_DURATION, } + public static class GraphQLDatedStopTimeHeadsignArgs { + + private String language; + + public GraphQLDatedStopTimeHeadsignArgs(Map args) { + if (args != null) { + this.language = (String) args.get("language"); + } + } + + public String getGraphQLLanguage() { + return this.language; + } + + public void setGraphQLLanguage(String language) { + this.language = language; + } + } + public static class GraphQLDatedTripTripHeadsignArgs { private String language; @@ -4584,6 +4603,16 @@ public enum GraphQLStopAlertType { TRIPS, } + /** Whether stop has been updated through a realtime update and if so, how. */ + public enum GraphQLStopRealTimeState { + ADDED, + CANCELED, + NO_DATA, + RECORDED, + UNUPDATED, + UPDATED, + } + public static class GraphQLStoptimeHeadsignArgs { private String language; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 6eb98a7f95b..1d5ebd31a4f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -59,10 +59,11 @@ config: ContactInfo: org.opentripplanner.transit.model.organization.ContactInfo Cluster: Object Coordinates: org.locationtech.jts.geom.Coordinate#Coordinate + DatedStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate DatedTrip: org.opentripplanner.transit.model.timetable.DatedTrip#DatedTrip DatedTripConnection: graphql.relay.Connection#Connection DatedTripEdge: graphql.relay.Edge#Edge - DatedTripTime: org.opentripplanner.apis.gtfs.model.DatedTripTime#DatedTripTime + ArrivalDepartureTime: org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime#ArrivalDepartureTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step @@ -101,6 +102,7 @@ config: stopAtDistanceEdge: graphql.relay.Edge#Edge StopOnRoute: org.opentripplanner.apis.gtfs.model.StopOnRouteModel#StopOnRouteModel StopOnTrip: org.opentripplanner.apis.gtfs.model.StopOnTripModel#StopOnTripModel + StopRealTimeState: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLStopRealTimeState#GraphQLStopRealTimeState Stoptime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate StoptimesInPattern: org.opentripplanner.model.StopTimesInPattern#StopTimesInPattern TicketType: org.opentripplanner.ext.fares.model.FareRuleSet#FareRuleSet diff --git a/src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java b/src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java new file mode 100644 index 00000000000..c8e4d212999 --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java @@ -0,0 +1,18 @@ +package org.opentripplanner.apis.gtfs.mapping; + +import javax.annotation.Nullable; +import org.opentripplanner.model.PickDrop; + +public final class PickDropMapper { + + @Nullable + public static String map(PickDrop pickDrop) { + return switch (pickDrop) { + case SCHEDULED -> "SCHEDULED"; + case NONE -> "NONE"; + case CALL_AGENCY -> "CALL_AGENCY"; + case COORDINATE_WITH_DRIVER -> "COORDINATE_WITH_DRIVER"; + case CANCELLED -> null; + }; + } +} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/model/DatedTripTime.java b/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java similarity index 56% rename from src/main/java/org/opentripplanner/apis/gtfs/model/DatedTripTime.java rename to src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java index a83eb50fe1d..529d83c7459 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/model/DatedTripTime.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java @@ -6,21 +6,22 @@ import javax.annotation.Nullable; /** - * A scheduled time of a trip's start or end with an optional realtime information. + * Timing of an arrival or a departure to or from a stop. May contain real-time information + * if available. */ -public record DatedTripTime( +public record ArrivalDepartureTime( @Nonnull ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated ) { @Nonnull - public static DatedTripTime of(ZonedDateTime realtime, int delaySecs) { + public static ArrivalDepartureTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new DatedTripTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); + return new ArrivalDepartureTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); } @Nonnull - public static DatedTripTime ofStatic(ZonedDateTime staticTime) { - return new DatedTripTime(staticTime, null); + public static ArrivalDepartureTime ofStatic(ZonedDateTime staticTime) { + return new ArrivalDepartureTime(staticTime, null); } /** diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 1bfb0184138..8128c36e4db 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -190,6 +190,14 @@ public boolean isNoDataStop() { return tripTimes.isNoDataStop(stopIndex); } + /** + * Is the real-time time a recorded time (i.e. has the vehicle already passed the stop). + * This information is currently only available from SIRI feeds. + */ + public boolean isRecordedStop() { + return tripTimes.isRecordedStop(stopIndex); + } + public RealTimeState getRealTimeState() { return tripTimes.isNoDataStop(stopIndex) ? RealTimeState.SCHEDULED diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index fb287c5c117..dcef5f67096 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -154,6 +154,17 @@ type Alert implements Node { trip: Trip @deprecated(reason : "Alert can have multiple affected entities now instead of there being duplicate alerts\nfor different entities. This will return only one of the affected trips.\nUse entities instead.") } +""" +Timing of an arrival or a departure to or from a stop. May contain real-time information if +available. +""" +type ArrivalDepartureTime { + "The estimated time of the event. If no real-time information is available, this is null." + estimated: RealTimeEstimate + "The scheduled time of the event." + scheduledTime: OffsetDateTime +} + "Bike park represents a location where bicycles can be parked." type BikePark implements Node & PlaceInterface { "ID of the bike park" @@ -384,6 +395,55 @@ type Currency { digits: Int! } +"Stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop." +type DatedStopTime { + "Scheduled arrival time to the stop and a realtime estimate, if one exists." + arrival: ArrivalDepartureTime + "Scheduled departure time from the stop and a realtime estimate, if one exists." + departure: ArrivalDepartureTime + """ + Whether the vehicle can be disembarked at this stop. This field can also be + used to indicate if disembarkation is possible only with special arrangements. + """ + dropoffType: PickupDropoffType + """ + Vehicle headsign of the trip on this stop. Trip headsigns can change during + the trip (e.g. on routes which run on loops), so this value should be used + instead of `tripHeadsign` to display the headsign relevant to the user. + """ + headsign( + """ + If translated headsign is found from gtfs translation.txt and wanted language is not same as + feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. + """ + language: String + ): String + """ + Whether the vehicle can be boarded at this stop. This field can also be used + to indicate if boarding is possible only with special arrangements. + """ + pickupType: PickupDropoffType + "Whether stop has been updated through a realtime update and if so, how." + realtimeState: StopRealTimeState! + "The stop where this arrival/departure happens" + stop: Stop + """ + The sequence of the stop in the pattern. This is not required to start from 0 or be consecutive - any + increasing integer sequence along the stops is valid. + + The purpose of this field is to identify the stop within the pattern so it can be cross-referenced + between it and the itinerary. It is safe to cross-reference when done quickly, i.e. within seconds. + However, it should be noted that real-time updates can change the values, so don't store it for + longer amounts of time. + + Depending on the source data, this might not be the GTFS `stop_sequence` but another value, perhaps + even generated. + """ + stopPosition: Int + "true, if this stop is used as a time equalization stop. false otherwise." + timepoint: Boolean +} + "Trip on a specific date" type DatedTrip implements Node { """ @@ -395,7 +455,7 @@ type DatedTrip implements Node { """ date: LocalDate! "The time when the trip ends including real-time information, if available." - end: DatedTripTime + end: ArrivalDepartureTime "Global object ID provided by Relay. This value can be used to refetch this object using **node** query." id: ID! "The pattern the trip is running on" @@ -403,11 +463,11 @@ type DatedTrip implements Node { "The route the trip is running on" route: Route! "The time when the trip starts including real-time information, if available." - start: DatedTripTime + start: ArrivalDepartureTime "List of stops this trip passes through" stops: [Stop!]! "List of times when this trip arrives to or departs from a stop" - stoptimes: [Stoptime] + stoptimes: [DatedStopTime] "Headsign of the vehicle when running on this trip" tripHeadsign( """ @@ -453,17 +513,6 @@ type DatedTripEdge { node: DatedTrip } -""" -Information about a dated trip's start or end times. May contain real-time information if -available. -""" -type DatedTripTime { - "The estimated time of the event. If no real-time information is available, this is null." - estimated: RealTimeEstimate - "The scheduled time of the event." - scheduledTime: OffsetDateTime -} - """ The standard case of a fare product: it only has a single price to be paid by the passenger and no discounts are applied. @@ -3517,6 +3566,25 @@ enum StopAlertType { TRIPS } +"Whether stop has been updated through a realtime update and if so, how." +enum StopRealTimeState { + "The stop has been added through a realtime update." + ADDED + "The stop has been cancelled through a realtime update." + CANCELED + "The realtime feed has indicated that there is no data available for this stop." + NO_DATA + """ + The vehicle has arrived to the stop or already visited it and the times are no longer estimates. + Note, not all realtime feeds indicate this information even if the vehicle has already passed the stop. + """ + RECORDED + "There have been no realtime updates." + UNUPDATED + "The trip's arrival and/or departure time has been updated." + UPDATED +} + """ Transit modes include modes that are used within organized transportation networks run by public transportation authorities, taxi companies etc. From 53ff5d56d991bb3ea39998f454d0c12abaab772e Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 9 Aug 2024 16:40:24 +0300 Subject: [PATCH 13/48] cancelled -> canceled --- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 6 +- .../gtfs/generated/GraphQLDataFetchers.java | 4 +- .../apis/gtfs/generated/GraphQLTypes.java | 118 +++++++++--------- .../service/DefaultTransitService.java | 12 +- .../transit/service/TransitService.java | 7 +- .../opentripplanner/apis/gtfs/schema.graphqls | 54 ++++---- 6 files changed, 103 insertions(+), 98 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 7cac038a165..4d893802d02 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -814,11 +814,11 @@ public DataFetcher> trips() { } @Override - public DataFetcher> cancelledTrips() { + public DataFetcher> canceledTrips() { return environment -> { - var args = new GraphQLTypes.GraphQLQueryTypeCancelledTripsArgs(environment.getArguments()); + var args = new GraphQLTypes.GraphQLQueryTypeCanceledTripsArgs(environment.getArguments()); var datedTrips = getTransitService(environment) - .getCancelledTrips(args.getGraphQLFeeds()) + .getCanceledTrips(args.getGraphQLFeeds()) .stream() .collect(Collectors.toList()); return new SimpleListConnection<>(datedTrips).get(environment); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index ff12746df68..3f6f7df22a0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -840,9 +840,9 @@ public interface GraphQLQueryType { public DataFetcher> bikeRentalStations(); - public DataFetcher> cancelledTripTimes(); + public DataFetcher> canceledTrips(); - public DataFetcher> cancelledTrips(); + public DataFetcher> cancelledTripTimes(); public DataFetcher carPark(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 3d9b627154a..70e98ab17a0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -2236,6 +2236,65 @@ public void setGraphQLIds(List ids) { } } + public static class GraphQLQueryTypeCanceledTripsArgs { + + private String after; + private String before; + private List feeds; + private Integer first; + private Integer last; + + public GraphQLQueryTypeCanceledTripsArgs(Map args) { + if (args != null) { + this.after = (String) args.get("after"); + this.before = (String) args.get("before"); + this.feeds = (List) args.get("feeds"); + this.first = (Integer) args.get("first"); + this.last = (Integer) args.get("last"); + } + } + + public String getGraphQLAfter() { + return this.after; + } + + public String getGraphQLBefore() { + return this.before; + } + + public List getGraphQLFeeds() { + return this.feeds; + } + + public Integer getGraphQLFirst() { + return this.first; + } + + public Integer getGraphQLLast() { + return this.last; + } + + public void setGraphQLAfter(String after) { + this.after = after; + } + + public void setGraphQLBefore(String before) { + this.before = before; + } + + public void setGraphQLFeeds(List feeds) { + this.feeds = feeds; + } + + public void setGraphQLFirst(Integer first) { + this.first = first; + } + + public void setGraphQLLast(Integer last) { + this.last = last; + } + } + public static class GraphQLQueryTypeCancelledTripTimesArgs { private List feeds; @@ -2345,65 +2404,6 @@ public void setGraphQLTrips(List trips) { } } - public static class GraphQLQueryTypeCancelledTripsArgs { - - private String after; - private String before; - private List feeds; - private Integer first; - private Integer last; - - public GraphQLQueryTypeCancelledTripsArgs(Map args) { - if (args != null) { - this.after = (String) args.get("after"); - this.before = (String) args.get("before"); - this.feeds = (List) args.get("feeds"); - this.first = (Integer) args.get("first"); - this.last = (Integer) args.get("last"); - } - } - - public String getGraphQLAfter() { - return this.after; - } - - public String getGraphQLBefore() { - return this.before; - } - - public List getGraphQLFeeds() { - return this.feeds; - } - - public Integer getGraphQLFirst() { - return this.first; - } - - public Integer getGraphQLLast() { - return this.last; - } - - public void setGraphQLAfter(String after) { - this.after = after; - } - - public void setGraphQLBefore(String before) { - this.before = before; - } - - public void setGraphQLFeeds(List feeds) { - this.feeds = feeds; - } - - public void setGraphQLFirst(Integer first) { - this.first = first; - } - - public void setGraphQLLast(Integer last) { - this.last = last; - } - } - public static class GraphQLQueryTypeCarParkArgs { private String id; diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 4d7ce68218c..8f5b86ad24e 100644 --- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -289,14 +289,14 @@ public void addTripForId(FeedScopedId tripId, Trip trip) { } @Override - public Collection getCancelledTrips(List feeds) { + public Collection getCanceledTrips(List feeds) { OTPRequestTimeoutException.checkForTimeout(); - List cancelledTrips = new ArrayList<>(); + List canceledTrips = new ArrayList<>(); Map departures = new HashMap<>(); var timetableSnapshot = lazyGetTimeTableSnapShot(); if (timetableSnapshot == null) { - return cancelledTrips; + return canceledTrips; } var calendarService = getCalendarService(); var patternMap = transitModelIndex.getPatternForTrip(); @@ -315,13 +315,13 @@ public Collection getCancelledTrips(List feeds) { var timetable = timetableSnapshot.resolve(pattern, date); var tripTimes = timetable.getTripTimes(trip); if (tripTimes.getRealTimeState() == RealTimeState.CANCELED) { // use UPDATED for faked testing - cancelledTrips.add(new DatedTrip(trip, date)); + canceledTrips.add(new DatedTrip(trip, date)); // store departure time from first stop departures.put(trip, tripTimes.sortIndex()); } } } - cancelledTrips.sort((t1, t2) -> { + canceledTrips.sort((t1, t2) -> { if (t1.serviceDate().isBefore(t2.serviceDate())) { return -1; } else if (t2.serviceDate().isBefore(t1.serviceDate())) { @@ -338,7 +338,7 @@ public Collection getCancelledTrips(List feeds) { return t1.trip().getId().compareTo(t2.trip().getId()); } }); - return cancelledTrips; + return canceledTrips; } @Override diff --git a/src/main/java/org/opentripplanner/transit/service/TransitService.java b/src/main/java/org/opentripplanner/transit/service/TransitService.java index f867a22deff..c2edd0b2751 100644 --- a/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -137,7 +137,12 @@ public interface TransitService { Collection getAllTrips(); - Collection getCancelledTrips(List feeds); + /** + * Get canceled trips. + * + * @param feeds If not null, used for filtering. + */ + Collection getCanceledTrips(List feeds); Collection getAllRoutes(); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index dcef5f67096..3be30ece04f 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1222,31 +1222,43 @@ type QueryType { """ ids: [String] ): [BikeRentalStation] @deprecated(reason : "Use rentalVehicles or vehicleRentalStations instead") - "Get cancelled TripTimes." + """ + Get pages of canceled Trips. Follows the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ + canceledTrips( + after: String, + before: String, + "Feed feedIds (e.g. [\"HSL\"])." + feeds: [String], + first: Int, + last: Int + ): DatedTripConnection + "Get canceled TripTimes." cancelledTripTimes( "Feed feedIds (e.g. [\"HSL\"])." feeds: [String], """ - Only cancelled trip times that have last stop arrival time at maxArrivalTime + Only canceled trip times that have last stop arrival time at maxArrivalTime or before are returned. Format: seconds since midnight of maxDate. """ maxArrivalTime: Int, - "Only cancelled trip times scheduled to run on maxDate or before are returned. Format: \"2019-12-23\" or \"20191223\"." + "Only canceled trip times scheduled to run on maxDate or before are returned. Format: \"2019-12-23\" or \"20191223\"." maxDate: String, """ - Only cancelled trip times that have first stop departure time at + Only canceled trip times that have first stop departure time at maxDepartureTime or before are returned. Format: seconds since midnight of maxDate. """ maxDepartureTime: Int, """ - Only cancelled trip times that have last stop arrival time at minArrivalTime + Only canceled trip times that have last stop arrival time at minArrivalTime or after are returned. Format: seconds since midnight of minDate. """ minArrivalTime: Int, - "Only cancelled trip times scheduled to run on minDate or after are returned. Format: \"2019-12-23\" or \"20191223\"." + "Only canceled trip times scheduled to run on minDate or after are returned. Format: \"2019-12-23\" or \"20191223\"." minDate: String, """ - Only cancelled trip times that have first stop departure time at + Only canceled trip times that have first stop departure time at minDepartureTime or after are returned. Format: seconds since midnight of minDate. """ minDepartureTime: Int, @@ -1256,19 +1268,7 @@ type QueryType { routes: [String], "Trip gtfsIds (e.g. [\"HSL:1098_20190405_Ma_2_1455\"])." trips: [String] - ): [Stoptime] @deprecated(reason : "`cancelledTripTimes` is deprecated. Use `cancelledTrips` instead.") - """ - Get pages of cancelled Trips. Follows the - [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). - """ - cancelledTrips( - after: String, - before: String, - "Feed feedIds (e.g. [\"HSL\"])." - feeds: [String], - first: Int, - last: Int - ): DatedTripConnection + ): [Stoptime] @deprecated(reason : "`cancelledTripTimes` is deprecated. Use `canceledTrips` instead.") "Get a single car park based on its ID, i.e. value of field `carParkId`" carPark(id: String!): CarPark @deprecated(reason : "carPark is deprecated. Use vehicleParking instead.") "Get all car parks" @@ -2893,7 +2893,7 @@ enum AlertSeverityLevelType { INFO """ Severe alerts are used when a significant part of public transport services is - affected, for example: All train services are cancelled due to technical problems. + affected, for example: All train services are canceled due to technical problems. """ SEVERE "Severity of alert is unknown" @@ -3570,7 +3570,7 @@ enum StopAlertType { enum StopRealTimeState { "The stop has been added through a realtime update." ADDED - "The stop has been cancelled through a realtime update." + "The stop has been canceled through a realtime update." CANCELED "The realtime feed has indicated that there is no data available for this stop." NO_DATA @@ -4342,21 +4342,21 @@ input TimetablePreferencesInput { When false, real-time updates are considered during the routing. In practice, when this option is set as true, some of the suggestions might not be realistic as the transfers could be invalid due to delays, - trips can be cancelled or stops can be skipped. + trips can be canceled or stops can be skipped. """ excludeRealTimeUpdates: Boolean """ - When true, departures that have been cancelled ahead of time will be + When true, departures that have been canceled ahead of time will be included during the routing. This means that an itinerary can include - a cancelled departure while some other alternative that contains no cancellations + a canceled departure while some other alternative that contains no cancellations could be filtered out as the alternative containing a cancellation would normally be better. """ includePlannedCancellations: Boolean """ - When true, departures that have been cancelled through a real-time feed will be + When true, departures that have been canceled through a real-time feed will be included during the routing. This means that an itinerary can include - a cancelled departure while some other alternative that contains no cancellations + a canceled departure while some other alternative that contains no cancellations could be filtered out as the alternative containing a cancellation would normally be better. This option can't be set to true while `includeRealTimeUpdates` is false. """ From 0469361d24a711bc2cc8b13750e05e4f0d6bcc8f Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 9 Aug 2024 18:09:32 +0300 Subject: [PATCH 14/48] Add graphql test --- .../apis/gtfs/GraphQLIntegrationTest.java | 30 +++- .../gtfs/expectations/canceled-trips.json | 129 ++++++++++++++++++ .../apis/gtfs/queries/canceled-trips.graphql | 80 +++++++++++ 3 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json create mode 100644 src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 79590ca2775..adbb05ddcbf 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -22,6 +22,7 @@ import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.time.Instant; +import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.Arrays; @@ -43,7 +44,10 @@ import org.opentripplanner.framework.i18n.I18NString; import org.opentripplanner.framework.i18n.NonLocalizedString; import org.opentripplanner.framework.model.Grams; +import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.model.FeedInfo; +import org.opentripplanner.model.TimetableSnapshot; +import org.opentripplanner.model.calendar.CalendarServiceData; import org.opentripplanner.model.fare.FareMedium; import org.opentripplanner.model.fare.FareProduct; import org.opentripplanner.model.fare.ItineraryFares; @@ -161,7 +165,12 @@ static void setup() { var transitModel = new TransitModel(model, DEDUPLICATOR); final TripPattern pattern = TEST_MODEL.pattern(BUS).build(); - var trip = TransitModelForTest.trip("123").withHeadsign(I18NString.of("Trip Headsign")).build(); + var cal_id = TransitModelForTest.id("CAL_1"); + var trip = TransitModelForTest + .trip("123") + .withHeadsign(I18NString.of("Trip Headsign")) + .withServiceId(cal_id) + .build(); var stopTimes = TEST_MODEL.stopTimesEvery5Minutes(3, trip, T11_00); var tripTimes = TripTimesFactory.tripTimes(trip, stopTimes, DEDUPLICATOR); pattern.add(tripTimes); @@ -212,6 +221,25 @@ public TransitAlertService getTransitAlertService() { }; routes.forEach(transitService::addRoutes); + // Crate a calendar (needed for testing cancelled trips) + CalendarServiceData calendarServiceData = new CalendarServiceData(); + calendarServiceData.putServiceDatesForServiceId( + cal_id, + List.of(LocalDate.of(2024, 8, 8), LocalDate.of(2024, 8, 9)) + ); + transitModel.getServiceCodes().put(cal_id, 0); + transitModel.updateCalendarServiceData(true, calendarServiceData, DataImportIssueStore.NOOP); + transitModel.initTimetableSnapshotProvider(() -> { + TimetableSnapshot timetableSnapshot = new TimetableSnapshot(); + var canceledStopTimes = TEST_MODEL.stopTimesEvery5Minutes(3, trip, T11_30); + var canceledTripTimes = TripTimesFactory.tripTimes(trip, canceledStopTimes, DEDUPLICATOR); + pattern.add(canceledTripTimes); + canceledTripTimes.cancelTrip(); + timetableSnapshot.update(pattern, canceledTripTimes, LocalDate.now()); + + return timetableSnapshot.commit(); + }); + var step1 = walkStep("street") .withRelativeDirection(RelativeDirection.DEPART) .withAbsoluteDirection(20) diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json new file mode 100644 index 00000000000..98da1d79bae --- /dev/null +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json @@ -0,0 +1,129 @@ +{ + "data": { + "canceledTrips": { + "pageInfo" : { + "hasNextPage" : false, + "hasPreviousPage" : false, + "startCursor" : "c2ltcGxlLWN1cnNvcjA=", + "endCursor" : "c2ltcGxlLWN1cnNvcjA=" + }, + "edges": [ + { + "node": { + "date": "2024-08-09", + "end": { + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:40:00+02:00" + }, + "scheduledTime": "2024-08-09T11:40:00+02:00" + }, + "start": { + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:30:00+02:00" + }, + "scheduledTime": "2024-08-09T11:30:00+02:00" + }, + "pattern": { + "code": "F:BUS" + }, + "route": { + "gtfsId": "F:R123" + }, + "stops": [ + { + "gtfsId": "F:Stop_0" + }, + { + "gtfsId": "F:Stop_1" + }, + { + "gtfsId": "F:Stop_2" + } + ], + "tripHeadsign": "Trip Headsign", + "tripShortName": null, + "stoptimes": [ + { + "dropoffType": null, + "headsign": "Stop headsign at stop 10", + "pickupType": null, + "realtimeState": "CANCELED", + "stop": { + "gtfsId": "F:Stop_0" + }, + "stopPosition": 10, + "timepoint": false, + "arrival": { + "scheduledTime": "2024-08-09T11:30:00+02:00", + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:30:00+02:00" + } + }, + "departure": { + "scheduledTime": "2024-08-09T11:30:00+02:00", + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:30:00+02:00" + } + } + }, + { + "dropoffType": null, + "headsign": "Stop headsign at stop 20", + "pickupType": null, + "realtimeState": "CANCELED", + "stop": { + "gtfsId": "F:Stop_1" + }, + "stopPosition": 20, + "timepoint": false, + "arrival": { + "scheduledTime": "2024-08-09T11:35:00+02:00", + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:35:00+02:00" + } + }, + "departure": { + "scheduledTime": "2024-08-09T11:35:00+02:00", + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:35:00+02:00" + } + } + }, + { + "dropoffType": null, + "headsign": "Stop headsign at stop 30", + "pickupType": null, + "realtimeState": "CANCELED", + "stop": { + "gtfsId": "F:Stop_2" + }, + "stopPosition": 30, + "timepoint": false, + "arrival": { + "scheduledTime": "2024-08-09T11:40:00+02:00", + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:40:00+02:00" + } + }, + "departure": { + "scheduledTime": "2024-08-09T11:40:00+02:00", + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:40:00+02:00" + } + } + } + ] + } + } + ] + } + } +} \ No newline at end of file diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql new file mode 100644 index 00000000000..a92a710c540 --- /dev/null +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -0,0 +1,80 @@ +{ + canceledTrips(feeds: "F") { + pageInfo { + hasNextPage + hasPreviousPage + startCursor + endCursor + } + edges { + node { + date + end { + estimated { + delay + time + } + scheduledTime + } + start { + estimated { + delay + time + } + scheduledTime + } + pattern { + code + } + route { + gtfsId + } + stops { + gtfsId + } + tripHeadsign + tripShortName + stoptimes { + dropoffType + headsign + pickupType + realtimeState + stop { + gtfsId + } + stopPosition + timepoint + arrival { + scheduledTime + estimated { + delay + time + } + } + departure { + scheduledTime + estimated { + delay + time + } + } + } + date + start { + estimated { + time + delay + } + scheduledTime + } + end { + estimated { + time + delay + } + scheduledTime + } + } + } + } +} From c0648b799b63d08965d5ce1a5bae518328be8f9d Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 9 Aug 2024 18:11:43 +0300 Subject: [PATCH 15/48] Rename method --- .../opentripplanner/ext/restapi/mapping/LegMapper.java | 2 +- .../apis/gtfs/datafetchers/LegImpl.java | 2 +- .../apis/transmodel/model/plan/LegType.java | 2 +- src/main/java/org/opentripplanner/model/plan/Leg.java | 2 +- .../model/plan/ScheduledTransitLeg.java | 10 +++++----- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/restapi/mapping/LegMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/mapping/LegMapper.java index b642426cd6d..f274a87ebd3 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/mapping/LegMapper.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/mapping/LegMapper.java @@ -87,7 +87,7 @@ public ApiLeg mapLeg( api.departureDelay = domain.getDepartureDelay(); api.arrivalDelay = domain.getArrivalDelay(); - api.realTime = domain.getRealTime(); + api.realTime = domain.isRealTimeUpdated(); api.isNonExactFrequency = domain.getNonExactFrequency(); api.headway = domain.getHeadway(); api.distance = round3Decimals(domain.getDistanceMeters()); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 9ec83a4bf67..3e3e39b6340 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -186,7 +186,7 @@ public DataFetcher pickupType() { @Override public DataFetcher realTime() { - return environment -> getSource(environment).getRealTime(); + return environment -> getSource(environment).isRealTimeUpdated(); } // TODO diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java index be05d00e16d..b794fc4703f 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/plan/LegType.java @@ -198,7 +198,7 @@ public static GraphQLObjectType create( .name("realtime") .description("Whether there is real-time data about this leg") .type(new GraphQLNonNull(Scalars.GraphQLBoolean)) - .dataFetcher(env -> leg(env).getRealTime()) + .dataFetcher(env -> leg(env).isRealTimeUpdated()) .build() ) .field( diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 2a0b6726560..2cd8db0fc2f 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -240,7 +240,7 @@ default int getArrivalDelay() { /** * Whether there is real-time data about this Leg */ - default boolean getRealTime() { + default boolean isRealTimeUpdated() { return false; } diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 4a84ac6e799..c8358e19155 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -164,7 +164,7 @@ public Accessibility getTripWheelchairAccessibility() { @Override public LegTime start() { - if (getRealTime()) { + if (isRealTimeUpdated()) { return LegTime.of(startTime, getDepartureDelay()); } else { return LegTime.ofStatic(startTime); @@ -173,7 +173,7 @@ public LegTime start() { @Override public LegTime end() { - if (getRealTime()) { + if (isRealTimeUpdated()) { return LegTime.of(endTime, getArrivalDelay()); } else { return LegTime.ofStatic(endTime); @@ -217,7 +217,7 @@ public int getArrivalDelay() { } @Override - public boolean getRealTime() { + public boolean isRealTimeUpdated() { return ( tripTimes.isRealtimeUpdated(boardStopPosInPattern) || tripTimes.isRealtimeUpdated(alightStopPosInPattern) @@ -276,7 +276,7 @@ public List getIntermediateStops() { for (int i = boardStopPosInPattern + 1; i < alightStopPosInPattern; i++) { StopLocation stop = tripPattern.getStop(i); - final StopArrival visit = mapper.map(i, stop, getRealTime()); + final StopArrival visit = mapper.map(i, stop, isRealTimeUpdated()); visits.add(visit); } return visits; @@ -410,7 +410,7 @@ public String toString() { .addObj("to", getTo()) .addTime("startTime", startTime) .addTime("endTime", endTime) - .addBool("realTime", getRealTime()) + .addBool("realTime", isRealTimeUpdated()) .addNum("distance", distanceMeters, "m") .addNum("cost", generalizedCost) .addNum("routeType", getRouteType()) From 6437bd727d83535950365be2a9d694dfd7910646 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 9 Aug 2024 18:13:38 +0300 Subject: [PATCH 16/48] Add small tests --- .../model/TripTimeOnDateTest.java | 21 +++++++++++++++++++ .../model/plan/ScheduledTransitLegTest.java | 4 ++++ 2 files changed, 25 insertions(+) diff --git a/src/test/java/org/opentripplanner/model/TripTimeOnDateTest.java b/src/test/java/org/opentripplanner/model/TripTimeOnDateTest.java index 78002e46eae..82e0f1a63f0 100644 --- a/src/test/java/org/opentripplanner/model/TripTimeOnDateTest.java +++ b/src/test/java/org/opentripplanner/model/TripTimeOnDateTest.java @@ -1,6 +1,8 @@ package org.opentripplanner.model; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.time.LocalTime; import org.junit.jupiter.api.Test; @@ -29,4 +31,23 @@ void gtfsSequence() { var departure = LocalTime.ofSecondOfDay(subject.getScheduledDeparture()); assertEquals(LocalTime.of(11, 10), departure); } + + @Test + void isRecordedStop() { + var testModel = TransitModelForTest.of(); + var pattern = testModel.pattern(TransitMode.BUS).build(); + var trip = TransitModelForTest.trip("123").build(); + var stopTimes = testModel.stopTimesEvery5Minutes(3, trip, T11_00); + + var tripTimes = TripTimesFactory.tripTimes(trip, stopTimes, new Deduplicator()); + tripTimes.setRecorded(1); + + var subject = new TripTimeOnDate(tripTimes, 0, pattern); + + assertFalse(subject.isRecordedStop()); + + subject = new TripTimeOnDate(tripTimes, 1, pattern); + + assertTrue(subject.isRecordedStop()); + } } diff --git a/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java b/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java index b41ace81e8d..af497f97bfb 100644 --- a/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java +++ b/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java @@ -1,8 +1,10 @@ package org.opentripplanner.model.plan; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.opentripplanner.transit.model._data.TransitModelForTest.id; import java.time.OffsetDateTime; @@ -49,6 +51,7 @@ void legTimesWithoutRealTime() { assertNull(leg.start().estimated()); assertNull(leg.end().estimated()); + assertFalse(leg.isRealTimeUpdated()); } @Test @@ -67,6 +70,7 @@ void legTimesWithRealTime() { assertNotNull(leg.start().estimated()); assertNotNull(leg.end().estimated()); + assertTrue(leg.isRealTimeUpdated()); } private static ScheduledTransitLegBuilder builder() { From 6e143d9a41751ade4e24f9a7a7e80e4baeb7ca4c Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 9 Aug 2024 18:39:04 +0300 Subject: [PATCH 17/48] Realtime -> RealTime --- .../opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java | 4 ++-- .../org/opentripplanner/model/plan/ScheduledTransitLeg.java | 4 ++-- .../transit/model/timetable/RealTimeTripTimes.java | 2 +- .../transit/model/timetable/ScheduledTripTimes.java | 2 +- .../opentripplanner/transit/model/timetable/TripTimes.java | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java index 5d567d83264..9046fa6807c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java @@ -43,7 +43,7 @@ public DataFetcher end() { if (scheduledTime == null) { return null; } - return tripTimes.isRealtimeUpdated(stopIndex) + return tripTimes.isRealTimeUpdated(stopIndex) ? ArrivalDepartureTime.of(scheduledTime, tripTimes.getArrivalDelay(stopIndex)) : ArrivalDepartureTime.ofStatic(scheduledTime); }; @@ -81,7 +81,7 @@ public DataFetcher start() { if (scheduledTime == null) { return null; } - return tripTimes.isRealtimeUpdated(0) + return tripTimes.isRealTimeUpdated(0) ? ArrivalDepartureTime.of(scheduledTime, tripTimes.getDepartureDelay(0)) : ArrivalDepartureTime.ofStatic(scheduledTime); }; diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index c8358e19155..df0a84d6aaa 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -219,8 +219,8 @@ public int getArrivalDelay() { @Override public boolean isRealTimeUpdated() { return ( - tripTimes.isRealtimeUpdated(boardStopPosInPattern) || - tripTimes.isRealtimeUpdated(alightStopPosInPattern) + tripTimes.isRealTimeUpdated(boardStopPosInPattern) || + tripTimes.isRealTimeUpdated(alightStopPosInPattern) ); } diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java b/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java index ca5897b7b24..b9159cb4fd7 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimes.java @@ -198,7 +198,7 @@ public boolean isPredictionInaccurate(int stop) { return isStopRealTimeStates(stop, StopRealTimeState.INACCURATE_PREDICTIONS); } - public boolean isRealtimeUpdated(int stop) { + public boolean isRealTimeUpdated(int stop) { return ( realTimeState != RealTimeState.SCHEDULED && !isStopRealTimeStates(stop, StopRealTimeState.NO_DATA) diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java b/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java index 3799fd7b140..423b0f8d9c7 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/ScheduledTripTimes.java @@ -235,7 +235,7 @@ public boolean isPredictionInaccurate(int stop) { } @Override - public boolean isRealtimeUpdated(int stop) { + public boolean isRealTimeUpdated(int stop) { return false; } diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java b/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java index ea1a3f8ab2b..c1065256700 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/TripTimes.java @@ -126,7 +126,7 @@ default int compareTo(TripTimes other) { /** * Return if trip has been updated and stop has not been given a NO_DATA update. */ - boolean isRealtimeUpdated(int stop); + boolean isRealTimeUpdated(int stop); /** * @return the whole trip's headsign. Individual stops can have different headsigns. From 1de24b2713794efcee5610da9be9f98600543145 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 9 Aug 2024 21:05:05 +0300 Subject: [PATCH 18/48] Add more tests --- .../timetable/RealTimeTripTimesTest.java | 11 +++++ .../service/DefaultTransitServiceTest.java | 42 ++++++++++++++++++- 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimesTest.java b/src/test/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimesTest.java index 5b3a8f76052..a47a7d61141 100644 --- a/src/test/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimesTest.java +++ b/src/test/java/org/opentripplanner/transit/model/timetable/RealTimeTripTimesTest.java @@ -402,6 +402,17 @@ public void testNoData() { assertFalse(updatedTripTimesA.isNoDataStop(2)); } + @Test + public void testRealTimeUpdated() { + RealTimeTripTimes updatedTripTimesA = createInitialTripTimes().copyScheduledTimes(); + assertFalse(updatedTripTimesA.isRealTimeUpdated(1)); + updatedTripTimesA.setRealTimeState(RealTimeState.UPDATED); + assertTrue(updatedTripTimesA.isRealTimeUpdated(1)); + updatedTripTimesA.setNoData(1); + assertTrue(updatedTripTimesA.isRealTimeUpdated(0)); + assertFalse(updatedTripTimesA.isRealTimeUpdated(1)); + } + @Nested class GtfsStopSequence { diff --git a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 54733f084d6..6f0591b1a2c 100644 --- a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -1,6 +1,7 @@ package org.opentripplanner.transit.service; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.model.plan.PlanTestConstants.T11_30; import static org.opentripplanner.transit.model.basic.TransitMode.BUS; import static org.opentripplanner.transit.model.basic.TransitMode.FERRY; import static org.opentripplanner.transit.model.basic.TransitMode.RAIL; @@ -12,16 +13,23 @@ import java.util.Set; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.graph_builder.issue.api.DataImportIssueStore; import org.opentripplanner.model.TimetableSnapshot; +import org.opentripplanner.model.calendar.CalendarServiceData; import org.opentripplanner.transit.model._data.TransitModelForTest; import org.opentripplanner.transit.model.framework.Deduplicator; +import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.network.StopPattern; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; import org.opentripplanner.transit.model.timetable.ScheduledTripTimes; +import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.model.timetable.TripTimesFactory; class DefaultTransitServiceTest { @@ -46,6 +54,13 @@ class DefaultTransitServiceTest { .withCreatedByRealtimeUpdater(true) .build(); + static FeedScopedId CALENDAR_ID = TransitModelForTest.id("CAL_1"); + static Trip TRIP = TransitModelForTest + .trip("123") + .withHeadsign(I18NString.of("Trip Headsign")) + .withServiceId(CALENDAR_ID) + .build(); + @BeforeAll static void setup() { var stopModel = TEST_MODEL @@ -55,8 +70,23 @@ static void setup() { .withStation(STATION) .build(); - var transitModel = new TransitModel(stopModel, new Deduplicator()); + var deduplicator = new Deduplicator(); + var transitModel = new TransitModel(stopModel, deduplicator); + var canceledStopTimes = TEST_MODEL.stopTimesEvery5Minutes(3, TRIP, T11_30); + var canceledTripTimes = TripTimesFactory.tripTimes(TRIP, canceledStopTimes, deduplicator); + RAIL_PATTERN.add(canceledTripTimes); + canceledTripTimes.cancelTrip(); transitModel.addTripPattern(RAIL_PATTERN.getId(), RAIL_PATTERN); + + // Crate a calendar (needed for testing cancelled trips) + CalendarServiceData calendarServiceData = new CalendarServiceData(); + calendarServiceData.putServiceDatesForServiceId( + CALENDAR_ID, + List.of(LocalDate.of(2024, 8, 8), LocalDate.of(2024, 8, 9)) + ); + transitModel.getServiceCodes().put(CALENDAR_ID, 0); + transitModel.updateCalendarServiceData(true, calendarServiceData, DataImportIssueStore.NOOP); + transitModel.index(); transitModel.initTimetableSnapshotProvider(() -> { @@ -69,6 +99,7 @@ static void setup() { .build() ); timetableSnapshot.update(REAL_TIME_PATTERN, tripTimes, LocalDate.now()); + timetableSnapshot.update(RAIL_PATTERN, canceledTripTimes, LocalDate.now()); return timetableSnapshot.commit(); }); @@ -115,4 +146,13 @@ void getPatternForStopsWithRealTime() { Collection patternsForStop = service.getPatternsForStop(STOP_B, true); assertEquals(Set.of(FERRY_PATTERN, RAIL_PATTERN, REAL_TIME_PATTERN), patternsForStop); } + + @Test + void getCanceledTrips() { + Collection canceledTrips = service.getCanceledTrips(null); + assertEquals( + "[DatedTrip[trip=Trip{F:123 RR123}, serviceDate=2024-08-08], DatedTrip[trip=Trip{F:123 RR123}, serviceDate=2024-08-09]]", + canceledTrips.toString() + ); + } } From 7251391e55c2ba5b7d52652fc9369ad82aed9544 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 9 Sep 2024 16:03:00 +0300 Subject: [PATCH 19/48] Refactor canceled trips fetching to be more efficient --- .../model/TimetableSnapshot.java | 30 +++++++++++++ .../service/DefaultTransitService.java | 45 ++++++------------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/main/java/org/opentripplanner/model/TimetableSnapshot.java b/src/main/java/org/opentripplanner/model/TimetableSnapshot.java index c0a7737abce..f92a16ecc56 100644 --- a/src/main/java/org/opentripplanner/model/TimetableSnapshot.java +++ b/src/main/java/org/opentripplanner/model/TimetableSnapshot.java @@ -5,24 +5,28 @@ import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.SetMultimap; import java.time.LocalDate; +import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.ConcurrentModificationException; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.stream.Collectors; import javax.annotation.Nullable; import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerUpdater; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.model.framework.Result; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.updater.spi.UpdateError; @@ -176,6 +180,32 @@ public TripPattern getRealtimeAddedTripPattern(FeedScopedId tripId, LocalDate se return realtimeAddedTripPattern.get(tripIdAndServiceDate); } + /** + * Get trips which have been canceled. + * + * @param feeds if not null, only return trips from these feeds + */ + public ArrayList getCanceledTrips(List feeds) { + return timetables + .values() + .stream() + .flatMap(timetables -> + timetables + .stream() + .flatMap(timetable -> + timetable + .getTripTimes() + .stream() + .filter(tripTimes -> + tripTimes.isCanceled() && + (feeds == null || feeds.contains(tripTimes.getTrip().getId().getFeedId())) + ) + .map(tripTimes -> new DatedTrip(tripTimes.getTrip(), timetable.getServiceDate())) + ) + ) + .collect(Collectors.toCollection(ArrayList::new)); + } + /** * @return if any trip patterns were added. */ diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 8f5b86ad24e..7eb28e50c7c 100644 --- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -8,10 +8,8 @@ import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -54,7 +52,6 @@ import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.site.StopLocationsGroup; import org.opentripplanner.transit.model.timetable.DatedTrip; -import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -288,47 +285,25 @@ public void addTripForId(FeedScopedId tripId, Trip trip) { transitModelIndex.getTripForId().put(tripId, trip); } + /** + * TODO This only supports realtime cancelled trips for now. + */ @Override public Collection getCanceledTrips(List feeds) { OTPRequestTimeoutException.checkForTimeout(); - List canceledTrips = new ArrayList<>(); - Map departures = new HashMap<>(); - var timetableSnapshot = lazyGetTimeTableSnapShot(); if (timetableSnapshot == null) { - return canceledTrips; - } - var calendarService = getCalendarService(); - var patternMap = transitModelIndex.getPatternForTrip(); - var trips = transitModelIndex.getTripForId(); - - for (Map.Entry entry : trips.entrySet()) { - var trip = entry.getValue(); - if (feeds != null && !feeds.contains(trip.getId().getFeedId())) { - continue; - } - Set serviceDates = calendarService.getServiceDatesForServiceId( - trip.getServiceId() - ); - var pattern = patternMap.get(trip); - for (LocalDate date : serviceDates) { - var timetable = timetableSnapshot.resolve(pattern, date); - var tripTimes = timetable.getTripTimes(trip); - if (tripTimes.getRealTimeState() == RealTimeState.CANCELED) { // use UPDATED for faked testing - canceledTrips.add(new DatedTrip(trip, date)); - // store departure time from first stop - departures.put(trip, tripTimes.sortIndex()); - } - } + return List.of(); } + List canceledTrips = timetableSnapshot.getCanceledTrips(feeds); canceledTrips.sort((t1, t2) -> { if (t1.serviceDate().isBefore(t2.serviceDate())) { return -1; } else if (t2.serviceDate().isBefore(t1.serviceDate())) { return 1; } - var departure1 = departures.get(t1.trip()); - var departure2 = departures.get(t2.trip()); + var departure1 = getDepartureTime(t1); + var departure2 = getDepartureTime(t2); if (departure1 < departure2) { return -1; } else if (departure1 > departure2) { @@ -780,4 +755,10 @@ private static Stream sortByOccurrenceAndReduce(Stream input) { .sorted(Map.Entry.comparingByValue().reversed()) .map(Map.Entry::getKey); } + + private int getDepartureTime(DatedTrip datedTrip) { + var pattern = getPatternForTrip(datedTrip.trip()); + var timetable = timetableSnapshot.resolve(pattern, datedTrip.serviceDate()); + return timetable.getTripTimes(datedTrip.trip()).getDepartureTime(0); + } } From bedee96dd764c458844df0ff849721fcfeea2cf3 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 9 Sep 2024 16:03:15 +0300 Subject: [PATCH 20/48] Update and fix tests --- .../apis/gtfs/GraphQLIntegrationTest.java | 24 ++- .../service/DefaultTransitServiceTest.java | 9 +- .../gtfs/expectations/canceled-trips.json | 14 +- .../apis/gtfs/expectations/patterns.json | 175 +++++++++++------- 4 files changed, 140 insertions(+), 82 deletions(-) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index adbb05ddcbf..25bb4f88eeb 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; +import static org.opentripplanner._support.time.ZoneIds.BERLIN; import static org.opentripplanner.model.plan.PlanTestConstants.D10m; import static org.opentripplanner.model.plan.PlanTestConstants.T11_00; import static org.opentripplanner.model.plan.PlanTestConstants.T11_01; @@ -36,7 +37,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.locationtech.jts.geom.Coordinate; import org.opentripplanner._support.text.I18NStrings; -import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.ext.fares.FaresToItineraryMapper; import org.opentripplanner.ext.fares.impl.DefaultFareService; import org.opentripplanner.framework.collection.ListUtils; @@ -175,6 +175,15 @@ static void setup() { var tripTimes = TripTimesFactory.tripTimes(trip, stopTimes, DEDUPLICATOR); pattern.add(tripTimes); + var trip2 = TransitModelForTest + .trip("321Canceled") + .withHeadsign(I18NString.of("Trip Headsign")) + .withServiceId(cal_id) + .build(); + var stopTimes2 = TEST_MODEL.stopTimesEvery5Minutes(3, trip2, T11_30); + var tripTimes2 = TripTimesFactory.tripTimes(trip2, stopTimes2, DEDUPLICATOR); + pattern.add(tripTimes2); + transitModel.addTripPattern(id("pattern-1"), pattern); var feedId = "testfeed"; @@ -189,7 +198,7 @@ static void setup() { .build(); transitModel.addAgency(agency); - transitModel.initTimeZone(ZoneIds.BERLIN); + transitModel.initTimeZone(BERLIN); transitModel.index(); var routes = Arrays .stream(TransitMode.values()) @@ -223,19 +232,18 @@ public TransitAlertService getTransitAlertService() { // Crate a calendar (needed for testing cancelled trips) CalendarServiceData calendarServiceData = new CalendarServiceData(); + var firstDate = LocalDate.of(2024, 8, 8); + var secondDate = LocalDate.of(2024, 8, 9); calendarServiceData.putServiceDatesForServiceId( cal_id, - List.of(LocalDate.of(2024, 8, 8), LocalDate.of(2024, 8, 9)) + List.of(firstDate, secondDate) ); transitModel.getServiceCodes().put(cal_id, 0); transitModel.updateCalendarServiceData(true, calendarServiceData, DataImportIssueStore.NOOP); transitModel.initTimetableSnapshotProvider(() -> { TimetableSnapshot timetableSnapshot = new TimetableSnapshot(); - var canceledStopTimes = TEST_MODEL.stopTimesEvery5Minutes(3, trip, T11_30); - var canceledTripTimes = TripTimesFactory.tripTimes(trip, canceledStopTimes, DEDUPLICATOR); - pattern.add(canceledTripTimes); - canceledTripTimes.cancelTrip(); - timetableSnapshot.update(pattern, canceledTripTimes, LocalDate.now()); + tripTimes2.cancelTrip(); + timetableSnapshot.update(pattern, tripTimes2, secondDate); return timetableSnapshot.commit(); }); diff --git a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 6f0591b1a2c..060632be28a 100644 --- a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -80,9 +80,11 @@ static void setup() { // Crate a calendar (needed for testing cancelled trips) CalendarServiceData calendarServiceData = new CalendarServiceData(); + var firstDate = LocalDate.of(2024, 8, 8); + var secondDate = LocalDate.of(2024, 8, 9); calendarServiceData.putServiceDatesForServiceId( CALENDAR_ID, - List.of(LocalDate.of(2024, 8, 8), LocalDate.of(2024, 8, 9)) + List.of(firstDate, secondDate) ); transitModel.getServiceCodes().put(CALENDAR_ID, 0); transitModel.updateCalendarServiceData(true, calendarServiceData, DataImportIssueStore.NOOP); @@ -98,8 +100,9 @@ static void setup() { .withDepartureTimes(new int[] { 0, 1 }) .build() ); - timetableSnapshot.update(REAL_TIME_PATTERN, tripTimes, LocalDate.now()); - timetableSnapshot.update(RAIL_PATTERN, canceledTripTimes, LocalDate.now()); + timetableSnapshot.update(REAL_TIME_PATTERN, tripTimes, firstDate); + timetableSnapshot.update(RAIL_PATTERN, canceledTripTimes, firstDate); + timetableSnapshot.update(RAIL_PATTERN, canceledTripTimes, secondDate); return timetableSnapshot.commit(); }); diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json index 98da1d79bae..5208a38fb01 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json @@ -1,11 +1,11 @@ { "data": { "canceledTrips": { - "pageInfo" : { - "hasNextPage" : false, - "hasPreviousPage" : false, - "startCursor" : "c2ltcGxlLWN1cnNvcjA=", - "endCursor" : "c2ltcGxlLWN1cnNvcjA=" + "pageInfo": { + "hasNextPage": false, + "hasPreviousPage": false, + "startCursor": "c2ltcGxlLWN1cnNvcjA=", + "endCursor": "c2ltcGxlLWN1cnNvcjA=" }, "edges": [ { @@ -29,7 +29,7 @@ "code": "F:BUS" }, "route": { - "gtfsId": "F:R123" + "gtfsId": "F:R321Canceled" }, "stops": [ { @@ -126,4 +126,4 @@ ] } } -} \ No newline at end of file +} diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json index b23ced4f954..d1f363fea5d 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json @@ -1,92 +1,139 @@ { - "data" : { - "patterns" : [ + "data": { + "patterns": [ { - "code" : "F:BUS", - "headsign" : "Trip Headsign", - "trips" : [ + "code": "F:BUS", + "headsign": "Trip Headsign", + "trips": [ { - "gtfsId" : "F:123", - "stoptimes" : [ + "gtfsId": "F:123", + "stoptimes": [ { - "stop" : { - "gtfsId" : "F:Stop_0", - "name" : "Stop_0" + "stop": { + "gtfsId": "F:Stop_0", + "name": "Stop_0" }, - "headsign" : "Stop headsign at stop 10", - "scheduledArrival" : 39600, - "scheduledDeparture" : 39600, - "stopPosition" : 10, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 10", + "scheduledArrival": 39600, + "scheduledDeparture": 39600, + "stopPosition": 10, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" }, { - "stop" : { - "gtfsId" : "F:Stop_1", - "name" : "Stop_1" + "stop": { + "gtfsId": "F:Stop_1", + "name": "Stop_1" }, - "headsign" : "Stop headsign at stop 20", - "scheduledArrival" : 39900, - "scheduledDeparture" : 39900, - "stopPosition" : 20, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 20", + "scheduledArrival": 39900, + "scheduledDeparture": 39900, + "stopPosition": 20, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" }, { - "stop" : { - "gtfsId" : "F:Stop_2", - "name" : "Stop_2" + "stop": { + "gtfsId": "F:Stop_2", + "name": "Stop_2" }, - "headsign" : "Stop headsign at stop 30", - "scheduledArrival" : 40200, - "scheduledDeparture" : 40200, - "stopPosition" : 30, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 30", + "scheduledArrival": 40200, + "scheduledDeparture": 40200, + "stopPosition": 30, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" } ], - "occupancy" : { - "occupancyStatus" : "FEW_SEATS_AVAILABLE" + "occupancy": { + "occupancyStatus": "FEW_SEATS_AVAILABLE" + } + }, + { + "gtfsId": "F:321Canceled", + "stoptimes": [ + { + "stop": { + "gtfsId": "F:Stop_0", + "name": "Stop_0" + }, + "headsign": "Stop headsign at stop 10", + "scheduledArrival": 41400, + "scheduledDeparture": 41400, + "stopPosition": 10, + "realtimeState": "CANCELED", + "pickupType": null, + "dropoffType": null + }, + { + "stop": { + "gtfsId": "F:Stop_1", + "name": "Stop_1" + }, + "headsign": "Stop headsign at stop 20", + "scheduledArrival": 41700, + "scheduledDeparture": 41700, + "stopPosition": 20, + "realtimeState": "CANCELED", + "pickupType": null, + "dropoffType": null + }, + { + "stop": { + "gtfsId": "F:Stop_2", + "name": "Stop_2" + }, + "headsign": "Stop headsign at stop 30", + "scheduledArrival": 42000, + "scheduledDeparture": 42000, + "stopPosition": 30, + "realtimeState": "CANCELED", + "pickupType": null, + "dropoffType": null + } + ], + "occupancy": { + "occupancyStatus": "NO_DATA_AVAILABLE" } } ], - "vehiclePositions" : [ + "vehiclePositions": [ { - "vehicleId" : "F:vehicle-1", - "label" : null, - "lat" : null, - "lon" : null, - "stopRelationship" : null, - "speed" : null, - "heading" : null, - "lastUpdated" : 31556889864403199, - "trip" : { - "gtfsId" : "F:123" + "vehicleId": "F:vehicle-1", + "label": null, + "lat": null, + "lon": null, + "stopRelationship": null, + "speed": null, + "heading": null, + "lastUpdated": 31556889864403199, + "trip": { + "gtfsId": "F:123" } }, { - "vehicleId" : "F:vehicle-2", - "label" : "vehicle2", - "lat" : 60.0, - "lon" : 80.0, - "stopRelationship" : { - "status" : "IN_TRANSIT_TO", - "stop" : { - "gtfsId" : "F:Stop_0" + "vehicleId": "F:vehicle-2", + "label": "vehicle2", + "lat": 60.0, + "lon": 80.0, + "stopRelationship": { + "status": "IN_TRANSIT_TO", + "stop": { + "gtfsId": "F:Stop_0" } }, - "speed" : 10.2, - "heading" : 80.0, - "lastUpdated" : -31557014167219200, - "trip" : { - "gtfsId" : "F:123" + "speed": 10.2, + "heading": 80.0, + "lastUpdated": -31557014167219200, + "trip": { + "gtfsId": "F:123" } } ] } ] } -} \ No newline at end of file +} From c0768e07c89f6d0b1d2a8d7d18852d5d02f09fe8 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 9 Sep 2024 16:19:28 +0300 Subject: [PATCH 21/48] Create an union for dated stoptimes --- .../apis/gtfs/GtfsGraphQLIndex.java | 6 +- .../DatedStopTimeTypeResolver.java | 21 ++++ .../apis/gtfs/datafetchers/DatedTripImpl.java | 10 +- ...eImpl.java => ExactDatedStopTimeImpl.java} | 2 +- .../gtfs/generated/GraphQLDataFetchers.java | 48 ++++---- .../apis/gtfs/generated/GraphQLTypes.java | 38 +++---- .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../opentripplanner/apis/gtfs/schema.graphqls | 106 +++++++++--------- .../apis/gtfs/GraphQLIntegrationTest.java | 5 +- .../service/DefaultTransitServiceTest.java | 5 +- .../apis/gtfs/queries/canceled-trips.graphql | 42 +++---- 11 files changed, 161 insertions(+), 124 deletions(-) create mode 100644 src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeTypeResolver.java rename src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{DatedStopTimeImpl.java => ExactDatedStopTimeImpl.java} (97%) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index a160e197611..83a41e8af5c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -35,10 +35,11 @@ import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.CoordinatesImpl; import org.opentripplanner.apis.gtfs.datafetchers.CurrencyImpl; -import org.opentripplanner.apis.gtfs.datafetchers.DatedStopTimeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.DatedStopTimeTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.DatedTripImpl; import org.opentripplanner.apis.gtfs.datafetchers.DefaultFareProductImpl; import org.opentripplanner.apis.gtfs.datafetchers.DepartureRowImpl; +import org.opentripplanner.apis.gtfs.datafetchers.ExactDatedStopTimeImpl; import org.opentripplanner.apis.gtfs.datafetchers.FareProductTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.FareProductUseImpl; import org.opentripplanner.apis.gtfs.datafetchers.FeedImpl; @@ -128,6 +129,7 @@ protected static GraphQLSchema buildSchema() { .type("StopPosition", type -> type.typeResolver(new StopPosition() {})) .type("FareProduct", type -> type.typeResolver(new FareProductTypeResolver())) .type("AlertEntity", type -> type.typeResolver(new AlertEntityTypeResolver())) + .type("DatedStopTime", type -> type.typeResolver(new DatedStopTimeTypeResolver())) .type(typeWiring.build(AgencyImpl.class)) .type(typeWiring.build(AlertImpl.class)) .type(typeWiring.build(BikeParkImpl.class)) @@ -181,7 +183,7 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) .type(typeWiring.build(DatedTripImpl.class)) - .type(typeWiring.build(DatedStopTimeImpl.class)) + .type(typeWiring.build(ExactDatedStopTimeImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeTypeResolver.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeTypeResolver.java new file mode 100644 index 00000000000..10ea6056792 --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeTypeResolver.java @@ -0,0 +1,21 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.TypeResolutionEnvironment; +import graphql.schema.GraphQLObjectType; +import graphql.schema.GraphQLSchema; +import graphql.schema.TypeResolver; +import org.opentripplanner.model.TripTimeOnDate; + +public class DatedStopTimeTypeResolver implements TypeResolver { + + @Override + public GraphQLObjectType getType(TypeResolutionEnvironment environment) { + Object o = environment.getObject(); + GraphQLSchema schema = environment.getSchema(); + + if (o instanceof TripTimeOnDate) { + return schema.getObjectType("ExactDatedStopTime"); + } + return null; + } +} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java index 9046fa6807c..f33026b0e1d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java @@ -92,8 +92,9 @@ public DataFetcher> stops() { return this::getStops; } + @SuppressWarnings("unchecked") @Override - public DataFetcher> stoptimes() { + public DataFetcher> stoptimes() { return environment -> { TransitService transitService = getTransitService(environment); Trip trip = getSource(environment).trip(); @@ -106,7 +107,12 @@ public DataFetcher> stoptimes() { if (timetable == null) { return List.of(); } - return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); + return (Iterable) (List) TripTimeOnDate.fromTripTimes( + timetable, + trip, + serviceDate, + midnight + ); }; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ExactDatedStopTimeImpl.java similarity index 97% rename from src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeImpl.java rename to src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ExactDatedStopTimeImpl.java index 3ed12ac4fb6..21ec9b6e92f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ExactDatedStopTimeImpl.java @@ -15,7 +15,7 @@ import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.service.TransitService; -public class DatedStopTimeImpl implements GraphQLDataFetchers.GraphQLDatedStopTime { +public class ExactDatedStopTimeImpl implements GraphQLDataFetchers.GraphQLExactDatedStopTime { @Override public DataFetcher arrival() { diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 3f6f7df22a0..31da847eaf5 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -327,26 +327,8 @@ public interface GraphQLCurrency { public DataFetcher digits(); } - /** Stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. */ - public interface GraphQLDatedStopTime { - public DataFetcher arrival(); - - public DataFetcher departure(); - - public DataFetcher dropoffType(); - - public DataFetcher headsign(); - - public DataFetcher pickupType(); - - public DataFetcher realtimeState(); - - public DataFetcher stop(); - - public DataFetcher stopPosition(); - - public DataFetcher timepoint(); - } + /** Departure and/or arrival times to or from a stop on a specific date. */ + public interface GraphQLDatedStopTime extends TypeResolver {} /** Trip on a specific date */ public interface GraphQLDatedTrip { @@ -364,7 +346,7 @@ public interface GraphQLDatedTrip { public DataFetcher> stops(); - public DataFetcher> stoptimes(); + public DataFetcher> stoptimes(); public DataFetcher tripHeadsign(); @@ -433,6 +415,30 @@ public interface GraphQLEmissions { public DataFetcher co2(); } + /** + * Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. + * This can include realtime estimates. + */ + public interface GraphQLExactDatedStopTime { + public DataFetcher arrival(); + + public DataFetcher departure(); + + public DataFetcher dropoffType(); + + public DataFetcher headsign(); + + public DataFetcher pickupType(); + + public DataFetcher realtimeState(); + + public DataFetcher stop(); + + public DataFetcher stopPosition(); + + public DataFetcher timepoint(); + } + /** A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'. */ public interface GraphQLFareMedium { public DataFetcher id(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 70e98ab17a0..2796cbc7cad 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -611,25 +611,6 @@ public enum GraphQLCyclingOptimizationType { SHORTEST_DURATION, } - public static class GraphQLDatedStopTimeHeadsignArgs { - - private String language; - - public GraphQLDatedStopTimeHeadsignArgs(Map args) { - if (args != null) { - this.language = (String) args.get("language"); - } - } - - public String getGraphQLLanguage() { - return this.language; - } - - public void setGraphQLLanguage(String language) { - this.language = language; - } - } - public static class GraphQLDatedTripTripHeadsignArgs { private String language; @@ -766,6 +747,25 @@ public void setGraphQLKeepingCost(org.opentripplanner.framework.model.Cost keepi } } + public static class GraphQLExactDatedStopTimeHeadsignArgs { + + private String language; + + public GraphQLExactDatedStopTimeHeadsignArgs(Map args) { + if (args != null) { + this.language = (String) args.get("language"); + } + } + + public String getGraphQLLanguage() { + return this.language; + } + + public void setGraphQLLanguage(String language) { + this.language = language; + } + } + public static class GraphQLFeedAlertsArgs { private List types; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 1d5ebd31a4f..64effddf651 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -59,7 +59,7 @@ config: ContactInfo: org.opentripplanner.transit.model.organization.ContactInfo Cluster: Object Coordinates: org.locationtech.jts.geom.Coordinate#Coordinate - DatedStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate + ExactDatedStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate DatedTrip: org.opentripplanner.transit.model.timetable.DatedTrip#DatedTrip DatedTripConnection: graphql.relay.Connection#Connection DatedTripEdge: graphql.relay.Edge#Edge diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 3be30ece04f..e493e6ac46a 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -73,6 +73,9 @@ interface PlaceInterface { "Entity related to an alert" union AlertEntity = Agency | Pattern | Route | RouteType | Stop | StopOnRoute | StopOnTrip | Trip | Unknown +"Departure and/or arrival times to or from a stop on a specific date." +union DatedStopTime = ExactDatedStopTime + union StopPosition = PositionAtStop | PositionBetweenStops "A public transport agency" @@ -395,55 +398,6 @@ type Currency { digits: Int! } -"Stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop." -type DatedStopTime { - "Scheduled arrival time to the stop and a realtime estimate, if one exists." - arrival: ArrivalDepartureTime - "Scheduled departure time from the stop and a realtime estimate, if one exists." - departure: ArrivalDepartureTime - """ - Whether the vehicle can be disembarked at this stop. This field can also be - used to indicate if disembarkation is possible only with special arrangements. - """ - dropoffType: PickupDropoffType - """ - Vehicle headsign of the trip on this stop. Trip headsigns can change during - the trip (e.g. on routes which run on loops), so this value should be used - instead of `tripHeadsign` to display the headsign relevant to the user. - """ - headsign( - """ - If translated headsign is found from gtfs translation.txt and wanted language is not same as - feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. - """ - language: String - ): String - """ - Whether the vehicle can be boarded at this stop. This field can also be used - to indicate if boarding is possible only with special arrangements. - """ - pickupType: PickupDropoffType - "Whether stop has been updated through a realtime update and if so, how." - realtimeState: StopRealTimeState! - "The stop where this arrival/departure happens" - stop: Stop - """ - The sequence of the stop in the pattern. This is not required to start from 0 or be consecutive - any - increasing integer sequence along the stops is valid. - - The purpose of this field is to identify the stop within the pattern so it can be cross-referenced - between it and the itinerary. It is safe to cross-reference when done quickly, i.e. within seconds. - However, it should be noted that real-time updates can change the values, so don't store it for - longer amounts of time. - - Depending on the source data, this might not be the GTFS `stop_sequence` but another value, perhaps - even generated. - """ - stopPosition: Int - "true, if this stop is used as a time equalization stop. false otherwise." - timepoint: Boolean -} - "Trip on a specific date" type DatedTrip implements Node { """ @@ -467,7 +421,7 @@ type DatedTrip implements Node { "List of stops this trip passes through" stops: [Stop!]! "List of times when this trip arrives to or departs from a stop" - stoptimes: [DatedStopTime] + stoptimes: [DatedStopTime!] "Headsign of the vehicle when running on this trip" tripHeadsign( """ @@ -573,6 +527,58 @@ type Emissions { co2: Grams } +""" +Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. +This can include realtime estimates. +""" +type ExactDatedStopTime { + "Scheduled arrival time to the stop and a realtime estimate, if one exists." + arrival: ArrivalDepartureTime + "Scheduled departure time from the stop and a realtime estimate, if one exists." + departure: ArrivalDepartureTime + """ + Whether the vehicle can be disembarked at this stop. This field can also be + used to indicate if disembarkation is possible only with special arrangements. + """ + dropoffType: PickupDropoffType + """ + Vehicle headsign of the trip on this stop. Trip headsigns can change during + the trip (e.g. on routes which run on loops), so this value should be used + instead of `tripHeadsign` to display the headsign relevant to the user. + """ + headsign( + """ + If translated headsign is found from gtfs translation.txt and wanted language is not same as + feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. + """ + language: String + ): String + """ + Whether the vehicle can be boarded at this stop. This field can also be used + to indicate if boarding is possible only with special arrangements. + """ + pickupType: PickupDropoffType + "Whether stop has been updated through a realtime update and if so, how." + realtimeState: StopRealTimeState! + "The stop where this arrival/departure happens" + stop: Stop + """ + The sequence of the stop in the pattern. This is not required to start from 0 or be consecutive - any + increasing integer sequence along the stops is valid. + + The purpose of this field is to identify the stop within the pattern so it can be cross-referenced + between it and the itinerary. It is safe to cross-reference when done quickly, i.e. within seconds. + However, it should be noted that real-time updates can change the values, so don't store it for + longer amounts of time. + + Depending on the source data, this might not be the GTFS `stop_sequence` but another value, perhaps + even generated. + """ + stopPosition: Int + "true, if this stop is used as a time equalization stop. false otherwise." + timepoint: Boolean +} + "A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'." type FareMedium { "ID of the medium" diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 25bb4f88eeb..594900997d9 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -234,10 +234,7 @@ public TransitAlertService getTransitAlertService() { CalendarServiceData calendarServiceData = new CalendarServiceData(); var firstDate = LocalDate.of(2024, 8, 8); var secondDate = LocalDate.of(2024, 8, 9); - calendarServiceData.putServiceDatesForServiceId( - cal_id, - List.of(firstDate, secondDate) - ); + calendarServiceData.putServiceDatesForServiceId(cal_id, List.of(firstDate, secondDate)); transitModel.getServiceCodes().put(cal_id, 0); transitModel.updateCalendarServiceData(true, calendarServiceData, DataImportIssueStore.NOOP); transitModel.initTimetableSnapshotProvider(() -> { diff --git a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 060632be28a..bdf9bbb73f0 100644 --- a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -82,10 +82,7 @@ static void setup() { CalendarServiceData calendarServiceData = new CalendarServiceData(); var firstDate = LocalDate.of(2024, 8, 8); var secondDate = LocalDate.of(2024, 8, 9); - calendarServiceData.putServiceDatesForServiceId( - CALENDAR_ID, - List.of(firstDate, secondDate) - ); + calendarServiceData.putServiceDatesForServiceId(CALENDAR_ID, List.of(firstDate, secondDate)); transitModel.getServiceCodes().put(CALENDAR_ID, 0); transitModel.updateCalendarServiceData(true, calendarServiceData, DataImportIssueStore.NOOP); diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index a92a710c540..84452fd04b3 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -35,27 +35,29 @@ tripHeadsign tripShortName stoptimes { - dropoffType - headsign - pickupType - realtimeState - stop { - gtfsId - } - stopPosition - timepoint - arrival { - scheduledTime - estimated { - delay - time + ... on ExactDatedStopTime { + dropoffType + headsign + pickupType + realtimeState + stop { + gtfsId } - } - departure { - scheduledTime - estimated { - delay - time + stopPosition + timepoint + arrival { + scheduledTime + estimated { + delay + time + } + } + departure { + scheduledTime + estimated { + delay + time + } } } } From 66100b9a0f2f092594517f1a5461c178be6fb644 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 18 Oct 2024 16:37:00 +0300 Subject: [PATCH 22/48] Use TripOnServiceDate and redesign schema --- .../apis/gtfs/GtfsGraphQLIndex.java | 12 +- .../apis/gtfs/datafetchers/DatedTripImpl.java | 189 -------------- ...eImpl.java => FixedDatedStopTimeImpl.java} | 4 +- .../FixedTripOnServiceDateImpl.java | 113 +++++++++ .../gtfs/datafetchers/NodeTypeResolver.java | 4 - .../apis/gtfs/datafetchers/QueryTypeImpl.java | 25 +- ...ava => TripOnServiceDateTypeResolver.java} | 8 +- .../gtfs/generated/GraphQLDataFetchers.java | 134 +++++----- .../apis/gtfs/generated/GraphQLTypes.java | 57 ++--- .../apis/gtfs/generated/graphql-codegen.yml | 8 +- .../model/TimetableSnapshot.java | 12 +- .../opentripplanner/model/TripTimeOnDate.java | 32 +++ .../transit/model/timetable/DatedTrip.java | 8 - .../model/timetable/TripOnServiceDate.java | 3 +- .../service/DefaultTransitService.java | 19 +- .../transit/service/TransitService.java | 3 +- .../opentripplanner/apis/gtfs/schema.graphqls | 235 ++++++++---------- .../service/DefaultTransitServiceTest.java | 8 +- .../gtfs/expectations/canceled-trips.json | 54 ++-- .../apis/gtfs/queries/canceled-trips.graphql | 64 ++--- 20 files changed, 429 insertions(+), 563 deletions(-) delete mode 100644 src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java rename src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{ExactDatedStopTimeImpl.java => FixedDatedStopTimeImpl.java} (96%) create mode 100644 src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java rename src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{DatedStopTimeTypeResolver.java => TripOnServiceDateTypeResolver.java} (63%) delete mode 100644 src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 83a41e8af5c..c8587e5851a 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -35,14 +35,13 @@ import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.CoordinatesImpl; import org.opentripplanner.apis.gtfs.datafetchers.CurrencyImpl; -import org.opentripplanner.apis.gtfs.datafetchers.DatedStopTimeTypeResolver; -import org.opentripplanner.apis.gtfs.datafetchers.DatedTripImpl; import org.opentripplanner.apis.gtfs.datafetchers.DefaultFareProductImpl; import org.opentripplanner.apis.gtfs.datafetchers.DepartureRowImpl; -import org.opentripplanner.apis.gtfs.datafetchers.ExactDatedStopTimeImpl; import org.opentripplanner.apis.gtfs.datafetchers.FareProductTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.FareProductUseImpl; import org.opentripplanner.apis.gtfs.datafetchers.FeedImpl; +import org.opentripplanner.apis.gtfs.datafetchers.FixedDatedStopTimeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.FixedTripOnServiceDateImpl; import org.opentripplanner.apis.gtfs.datafetchers.GeometryImpl; import org.opentripplanner.apis.gtfs.datafetchers.ItineraryImpl; import org.opentripplanner.apis.gtfs.datafetchers.LegImpl; @@ -73,6 +72,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.TranslatedStringImpl; import org.opentripplanner.apis.gtfs.datafetchers.TripImpl; import org.opentripplanner.apis.gtfs.datafetchers.TripOccupancyImpl; +import org.opentripplanner.apis.gtfs.datafetchers.TripOnServiceDateTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.UnknownImpl; import org.opentripplanner.apis.gtfs.datafetchers.VehicleParkingImpl; import org.opentripplanner.apis.gtfs.datafetchers.VehiclePositionImpl; @@ -129,7 +129,7 @@ protected static GraphQLSchema buildSchema() { .type("StopPosition", type -> type.typeResolver(new StopPosition() {})) .type("FareProduct", type -> type.typeResolver(new FareProductTypeResolver())) .type("AlertEntity", type -> type.typeResolver(new AlertEntityTypeResolver())) - .type("DatedStopTime", type -> type.typeResolver(new DatedStopTimeTypeResolver())) + .type("TripOnServiceDate", type -> type.typeResolver(new TripOnServiceDateTypeResolver())) .type(typeWiring.build(AgencyImpl.class)) .type(typeWiring.build(AlertImpl.class)) .type(typeWiring.build(BikeParkImpl.class)) @@ -182,8 +182,8 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(CurrencyImpl.class)) .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) - .type(typeWiring.build(DatedTripImpl.class)) - .type(typeWiring.build(ExactDatedStopTimeImpl.class)) + .type(typeWiring.build(FixedTripOnServiceDateImpl.class)) + .type(typeWiring.build(FixedDatedStopTimeImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java deleted file mode 100644 index f33026b0e1d..00000000000 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedTripImpl.java +++ /dev/null @@ -1,189 +0,0 @@ -package org.opentripplanner.apis.gtfs.datafetchers; - -import static org.opentripplanner.apis.gtfs.GraphQLUtils.stopTimeToInt; - -import graphql.relay.Relay; -import graphql.schema.DataFetcher; -import graphql.schema.DataFetchingEnvironment; -import java.time.Instant; -import java.time.LocalDate; -import java.time.ZonedDateTime; -import java.util.List; -import javax.annotation.Nullable; -import org.opentripplanner.apis.gtfs.GraphQLRequestContext; -import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; -import org.opentripplanner.ext.restapi.mapping.LocalDateMapper; -import org.opentripplanner.framework.time.ServiceDateUtils; -import org.opentripplanner.model.Timetable; -import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.transit.model.network.Route; -import org.opentripplanner.transit.model.network.TripPattern; -import org.opentripplanner.transit.model.timetable.DatedTrip; -import org.opentripplanner.transit.model.timetable.Trip; -import org.opentripplanner.transit.model.timetable.TripTimes; -import org.opentripplanner.transit.service.TransitService; - -public class DatedTripImpl implements GraphQLDataFetchers.GraphQLDatedTrip { - - @Override - public DataFetcher date() { - return env -> getSource(env).serviceDate(); - } - - @Override - public DataFetcher end() { - return env -> { - var tripTimes = getTripTimes(env); - if (tripTimes == null) { - return null; - } - var stopIndex = tripTimes.getNumStops() - 1; - var scheduledTime = getZonedDateTime(env, tripTimes.getScheduledArrivalTime(stopIndex)); - if (scheduledTime == null) { - return null; - } - return tripTimes.isRealTimeUpdated(stopIndex) - ? ArrivalDepartureTime.of(scheduledTime, tripTimes.getArrivalDelay(stopIndex)) - : ArrivalDepartureTime.ofStatic(scheduledTime); - }; - } - - @Override - public DataFetcher id() { - return env -> - new Relay.ResolvedGlobalId( - "DatedTrip", - getSource(env).trip().getId().toString() + - ';' + - LocalDateMapper.mapToApi(getSource(env).serviceDate()) - ); - } - - @Override - public DataFetcher pattern() { - return this::getTripPattern; - } - - @Override - public DataFetcher route() { - return environment -> getSource(environment).trip().getRoute(); - } - - @Override - public DataFetcher start() { - return env -> { - var tripTimes = getTripTimes(env); - if (tripTimes == null) { - return null; - } - var scheduledTime = getZonedDateTime(env, tripTimes.getScheduledDepartureTime(0)); - if (scheduledTime == null) { - return null; - } - return tripTimes.isRealTimeUpdated(0) - ? ArrivalDepartureTime.of(scheduledTime, tripTimes.getDepartureDelay(0)) - : ArrivalDepartureTime.ofStatic(scheduledTime); - }; - } - - @Override - public DataFetcher> stops() { - return this::getStops; - } - - @SuppressWarnings("unchecked") - @Override - public DataFetcher> stoptimes() { - return environment -> { - TransitService transitService = getTransitService(environment); - Trip trip = getSource(environment).trip(); - var serviceDate = getSource(environment).serviceDate(); - - Instant midnight = ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); - Timetable timetable = getTimetable(environment, trip, serviceDate); - if (timetable == null) { - return List.of(); - } - return (Iterable) (List) TripTimeOnDate.fromTripTimes( - timetable, - trip, - serviceDate, - midnight - ); - }; - } - - @Override - public DataFetcher tripHeadsign() { - return environment -> - org.opentripplanner.framework.graphql.GraphQLUtils.getTranslation( - getSource(environment).trip().getHeadsign(), - environment - ); - } - - @Override - public DataFetcher tripShortName() { - return environment -> getSource(environment).trip().getShortName(); - } - - private List getStops(DataFetchingEnvironment environment) { - TripPattern tripPattern = getTripPattern(environment); - if (tripPattern == null) { - return List.of(); - } - return List.copyOf(tripPattern.getStops()); - } - - private TripPattern getTripPattern(DataFetchingEnvironment environment) { - return getTransitService(environment).getPatternForTrip(getSource(environment).trip()); - } - - @Nullable - private Timetable getTimetable( - DataFetchingEnvironment environment, - Trip trip, - LocalDate serviceDate - ) { - TransitService transitService = getTransitService(environment); - TripPattern tripPattern = transitService.getPatternForTrip(trip, serviceDate); - // no matching pattern found - if (tripPattern == null) { - return null; - } - - return transitService.getTimetableForTripPattern(tripPattern, serviceDate); - } - - @Nullable - private TripTimes getTripTimes(DataFetchingEnvironment environment) { - Trip trip = getSource(environment).trip(); - var serviceDate = getSource(environment).serviceDate(); - var timetable = getTimetable(environment, trip, serviceDate); - if (timetable == null) { - return null; - } - return timetable.getTripTimes(trip); - } - - private ZonedDateTime getZonedDateTime(DataFetchingEnvironment environment, int time) { - var fixedTime = stopTimeToInt(time); - if (fixedTime == null) { - return null; - } - var serviceDate = getSource(environment).serviceDate(); - TransitService transitService = getTransitService(environment); - return ServiceDateUtils.toZonedDateTime(serviceDate, transitService.getTimeZone(), fixedTime); - } - - private TransitService getTransitService(DataFetchingEnvironment environment) { - return environment.getContext().transitService(); - } - - private DatedTrip getSource(DataFetchingEnvironment environment) { - return environment.getSource(); - } -} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ExactDatedStopTimeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java similarity index 96% rename from src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ExactDatedStopTimeImpl.java rename to src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java index 21ec9b6e92f..df2864f8580 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ExactDatedStopTimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java @@ -15,7 +15,7 @@ import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.service.TransitService; -public class ExactDatedStopTimeImpl implements GraphQLDataFetchers.GraphQLExactDatedStopTime { +public class FixedDatedStopTimeImpl implements GraphQLDataFetchers.GraphQLFixedDatedStopTime { @Override public DataFetcher arrival() { @@ -46,7 +46,7 @@ public DataFetcher departure() { } @Override - public DataFetcher dropoffType() { + public DataFetcher dropOffType() { return environment -> PickDropMapper.map(getSource(environment).getDropoffType()); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java new file mode 100644 index 00000000000..6b78bc0d13d --- /dev/null +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java @@ -0,0 +1,113 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import java.time.Instant; +import java.time.LocalDate; +import java.util.List; +import javax.annotation.Nullable; +import org.opentripplanner.apis.gtfs.GraphQLRequestContext; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.framework.time.ServiceDateUtils; +import org.opentripplanner.model.Timetable; +import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.model.timetable.TripOnServiceDate; +import org.opentripplanner.transit.service.TransitService; + +public class FixedTripOnServiceDateImpl + implements GraphQLDataFetchers.GraphQLFixedTripOnServiceDate { + + @Override + public DataFetcher date() { + return env -> getSource(env).getServiceDate(); + } + + @Override + public DataFetcher end() { + return environment -> { + TransitService transitService = getTransitService(environment); + Trip trip = getTrip(environment); + var serviceDate = getSource(environment).getServiceDate(); + + Instant midnight = ServiceDateUtils + .asStartOfService(serviceDate, transitService.getTimeZone()) + .toInstant(); + Timetable timetable = getTimetable(environment, trip, serviceDate); + if (timetable == null) { + return null; + } + return TripTimeOnDate.lastFromTripTimes(timetable, trip, serviceDate, midnight); + }; + } + + @Override + public DataFetcher start() { + return environment -> { + TransitService transitService = getTransitService(environment); + Trip trip = getTrip(environment); + var serviceDate = getSource(environment).getServiceDate(); + + Instant midnight = ServiceDateUtils + .asStartOfService(serviceDate, transitService.getTimeZone()) + .toInstant(); + Timetable timetable = getTimetable(environment, trip, serviceDate); + if (timetable == null) { + return null; + } + return TripTimeOnDate.firstFromTripTimes(timetable, trip, serviceDate, midnight); + }; + } + + @Override + public DataFetcher> stoptimes() { + return environment -> { + TransitService transitService = getTransitService(environment); + Trip trip = getTrip(environment); + var serviceDate = getSource(environment).getServiceDate(); + + Instant midnight = ServiceDateUtils + .asStartOfService(serviceDate, transitService.getTimeZone()) + .toInstant(); + Timetable timetable = getTimetable(environment, trip, serviceDate); + if (timetable == null) { + return List.of(); + } + return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); + }; + } + + @Override + public DataFetcher trip() { + return this::getTrip; + } + + @Nullable + private Timetable getTimetable( + DataFetchingEnvironment environment, + Trip trip, + LocalDate serviceDate + ) { + TransitService transitService = getTransitService(environment); + TripPattern tripPattern = transitService.getPatternForTrip(trip, serviceDate); + // no matching pattern found + if (tripPattern == null) { + return null; + } + + return transitService.getTimetableForTripPattern(tripPattern, serviceDate); + } + + private TransitService getTransitService(DataFetchingEnvironment environment) { + return environment.getContext().transitService(); + } + + private Trip getTrip(DataFetchingEnvironment environment) { + return getSource(environment).getTrip(); + } + + private TripOnServiceDate getSource(DataFetchingEnvironment environment) { + return environment.getSource(); + } +} diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java index 63f80fb643f..437d75e03e9 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/NodeTypeResolver.java @@ -20,7 +20,6 @@ import org.opentripplanner.transit.model.organization.Agency; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.Station; -import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; public class NodeTypeResolver implements TypeResolver { @@ -86,9 +85,6 @@ public GraphQLObjectType getType(TypeResolutionEnvironment environment) { if (o instanceof Trip) { return schema.getObjectType("Trip"); } - if (o instanceof DatedTrip) { - return schema.getObjectType("DatedTrip"); - } return null; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 4d893802d02..83818a3094d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -13,7 +13,6 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; import graphql.schema.DataFetchingEnvironmentImpl; -import java.time.LocalDate; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -69,8 +68,8 @@ import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; -import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.model.timetable.TripOnServiceDate; import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.updater.GtfsRealtimeFuzzyTripMatcher; @@ -193,7 +192,10 @@ public DataFetcher> bikeRentalStations() { }; } - // TODO + /** + * @deprecated Replaced by {@link #canceledTrips()}. + */ + @Deprecated @Override public DataFetcher> cancelledTripTimes() { return environment -> null; @@ -433,12 +435,6 @@ public DataFetcher node() { return new PlaceAtDistance(place, Double.parseDouble(parts[0])); } - case "DatedTrip": - { - String[] parts = id.split(";"); - var trip = transitService.getTripForId(FeedScopedId.parse(parts[0])); - return new DatedTrip(trip, LocalDate.parse(parts[1])); - } case "Route": return transitService.getRouteForId(FeedScopedId.parse(id)); case "Stop": @@ -814,14 +810,13 @@ public DataFetcher> trips() { } @Override - public DataFetcher> canceledTrips() { + public DataFetcher> canceledTrips() { return environment -> { var args = new GraphQLTypes.GraphQLQueryTypeCanceledTripsArgs(environment.getArguments()); - var datedTrips = getTransitService(environment) - .getCanceledTrips(args.getGraphQLFeeds()) - .stream() - .collect(Collectors.toList()); - return new SimpleListConnection<>(datedTrips).get(environment); + var trips = new ArrayList<>( + getTransitService(environment).getCanceledTrips(args.getGraphQLFeeds()) + ); + return new SimpleListConnection<>(trips).get(environment); }; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeTypeResolver.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java similarity index 63% rename from src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeTypeResolver.java rename to src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java index 10ea6056792..aaf8d6dae14 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/DatedStopTimeTypeResolver.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java @@ -4,17 +4,17 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; import graphql.schema.TypeResolver; -import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.transit.model.timetable.TripOnServiceDate; -public class DatedStopTimeTypeResolver implements TypeResolver { +public class TripOnServiceDateTypeResolver implements TypeResolver { @Override public GraphQLObjectType getType(TypeResolutionEnvironment environment) { Object o = environment.getObject(); GraphQLSchema schema = environment.getSchema(); - if (o instanceof TripTimeOnDate) { - return schema.getObjectType("ExactDatedStopTime"); + if (o instanceof TripOnServiceDate) { + return schema.getObjectType("FixedTripOnServiceDate"); } return null; } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 31da847eaf5..e324e4d2494 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -66,8 +66,8 @@ import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.organization.Agency; -import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; +import org.opentripplanner.transit.model.timetable.TripOnServiceDate; import org.opentripplanner.transit.model.timetable.booking.BookingInfo; import org.opentripplanner.transit.model.timetable.booking.BookingTime; @@ -327,52 +327,6 @@ public interface GraphQLCurrency { public DataFetcher digits(); } - /** Departure and/or arrival times to or from a stop on a specific date. */ - public interface GraphQLDatedStopTime extends TypeResolver {} - - /** Trip on a specific date */ - public interface GraphQLDatedTrip { - public DataFetcher date(); - - public DataFetcher end(); - - public DataFetcher id(); - - public DataFetcher pattern(); - - public DataFetcher route(); - - public DataFetcher start(); - - public DataFetcher> stops(); - - public DataFetcher> stoptimes(); - - public DataFetcher tripHeadsign(); - - public DataFetcher tripShortName(); - } - - /** - * A connection to a list of dated trips that follows - * [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). - */ - public interface GraphQLDatedTripConnection { - public DataFetcher>> edges(); - - public DataFetcher pageInfo(); - } - - /** - * An edge for DatedTrip connection. Part of the - * [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). - */ - public interface GraphQLDatedTripEdge { - public DataFetcher cursor(); - - public DataFetcher node(); - } - /** * The standard case of a fare product: it only has a single price to be paid by the passenger * and no discounts are applied. @@ -415,30 +369,6 @@ public interface GraphQLEmissions { public DataFetcher co2(); } - /** - * Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. - * This can include realtime estimates. - */ - public interface GraphQLExactDatedStopTime { - public DataFetcher arrival(); - - public DataFetcher departure(); - - public DataFetcher dropoffType(); - - public DataFetcher headsign(); - - public DataFetcher pickupType(); - - public DataFetcher realtimeState(); - - public DataFetcher stop(); - - public DataFetcher stopPosition(); - - public DataFetcher timepoint(); - } - /** A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'. */ public interface GraphQLFareMedium { public DataFetcher id(); @@ -490,6 +420,43 @@ public interface GraphQLFeedPublisher { public DataFetcher url(); } + /** + * Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. + * This can include realtime estimates. + */ + public interface GraphQLFixedDatedStopTime { + public DataFetcher arrival(); + + public DataFetcher departure(); + + public DataFetcher dropOffType(); + + public DataFetcher headsign(); + + public DataFetcher pickupType(); + + public DataFetcher realtimeState(); + + public DataFetcher stop(); + + public DataFetcher stopPosition(); + + public DataFetcher timepoint(); + } + + /** A fixed (i.e. not flexible or frequency based) trip on a specific service date */ + public interface GraphQLFixedTripOnServiceDate { + public DataFetcher date(); + + public DataFetcher end(); + + public DataFetcher start(); + + public DataFetcher> stoptimes(); + + public DataFetcher trip(); + } + public interface GraphQLGeometry { public DataFetcher length(); @@ -846,7 +813,7 @@ public interface GraphQLQueryType { public DataFetcher> bikeRentalStations(); - public DataFetcher> canceledTrips(); + public DataFetcher> canceledTrips(); public DataFetcher> cancelledTripTimes(); @@ -1280,6 +1247,29 @@ public interface GraphQLTripOccupancy { public DataFetcher occupancyStatus(); } + /** An instance of a trip on a service date. */ + public interface GraphQLTripOnServiceDate extends TypeResolver {} + + /** + * A connection to a list of trips on service dates that follows + * [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + */ + public interface GraphQLTripOnServiceDateConnection { + public DataFetcher>> edges(); + + public DataFetcher pageInfo(); + } + + /** + * An edge for TripOnServiceDate connection. Part of the + * [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + */ + public interface GraphQLTripOnServiceDateEdge { + public DataFetcher cursor(); + + public DataFetcher node(); + } + /** This is used for alert entities that we don't explicitly handle or they are missing. */ public interface GraphQLUnknown { public DataFetcher description(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 2796cbc7cad..5ab7e0d4017 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -611,25 +611,6 @@ public enum GraphQLCyclingOptimizationType { SHORTEST_DURATION, } - public static class GraphQLDatedTripTripHeadsignArgs { - - private String language; - - public GraphQLDatedTripTripHeadsignArgs(Map args) { - if (args != null) { - this.language = (String) args.get("language"); - } - } - - public String getGraphQLLanguage() { - return this.language; - } - - public void setGraphQLLanguage(String language) { - this.language = language; - } - } - public static class GraphQLDepartureRowStoptimesArgs { private Integer numberOfDepartures; @@ -747,25 +728,6 @@ public void setGraphQLKeepingCost(org.opentripplanner.framework.model.Cost keepi } } - public static class GraphQLExactDatedStopTimeHeadsignArgs { - - private String language; - - public GraphQLExactDatedStopTimeHeadsignArgs(Map args) { - if (args != null) { - this.language = (String) args.get("language"); - } - } - - public String getGraphQLLanguage() { - return this.language; - } - - public void setGraphQLLanguage(String language) { - this.language = language; - } - } - public static class GraphQLFeedAlertsArgs { private List types; @@ -811,6 +773,25 @@ public enum GraphQLFilterPlaceType { VEHICLE_RENT, } + public static class GraphQLFixedDatedStopTimeHeadsignArgs { + + private String language; + + public GraphQLFixedDatedStopTimeHeadsignArgs(Map args) { + if (args != null) { + this.language = (String) args.get("language"); + } + } + + public String getGraphQLLanguage() { + return this.language; + } + + public void setGraphQLLanguage(String language) { + this.language = language; + } + } + public enum GraphQLFormFactor { BICYCLE, CAR, diff --git a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 64effddf651..28c556238f0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -59,10 +59,10 @@ config: ContactInfo: org.opentripplanner.transit.model.organization.ContactInfo Cluster: Object Coordinates: org.locationtech.jts.geom.Coordinate#Coordinate - ExactDatedStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate - DatedTrip: org.opentripplanner.transit.model.timetable.DatedTrip#DatedTrip - DatedTripConnection: graphql.relay.Connection#Connection - DatedTripEdge: graphql.relay.Edge#Edge + FixedDatedStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate + FixedTripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate + TripOnServiceDateConnection: graphql.relay.Connection#Connection + TripOnServiceDateEdge: graphql.relay.Edge#Edge ArrivalDepartureTime: org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime#ArrivalDepartureTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop diff --git a/src/main/java/org/opentripplanner/model/TimetableSnapshot.java b/src/main/java/org/opentripplanner/model/TimetableSnapshot.java index f92a16ecc56..3dc68bb6968 100644 --- a/src/main/java/org/opentripplanner/model/TimetableSnapshot.java +++ b/src/main/java/org/opentripplanner/model/TimetableSnapshot.java @@ -26,8 +26,8 @@ import org.opentripplanner.transit.model.framework.Result; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; -import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; +import org.opentripplanner.transit.model.timetable.TripOnServiceDate; import org.opentripplanner.transit.model.timetable.TripTimes; import org.opentripplanner.updater.spi.UpdateError; import org.opentripplanner.updater.spi.UpdateSuccess; @@ -185,7 +185,7 @@ public TripPattern getRealtimeAddedTripPattern(FeedScopedId tripId, LocalDate se * * @param feeds if not null, only return trips from these feeds */ - public ArrayList getCanceledTrips(List feeds) { + public ArrayList getCanceledTrips(List feeds) { return timetables .values() .stream() @@ -200,7 +200,13 @@ public ArrayList getCanceledTrips(List feeds) { tripTimes.isCanceled() && (feeds == null || feeds.contains(tripTimes.getTrip().getId().getFeedId())) ) - .map(tripTimes -> new DatedTrip(tripTimes.getTrip(), timetable.getServiceDate())) + .map(tripTimes -> + TripOnServiceDate + .of(tripTimes.getTrip().getId()) + .withServiceDate(timetable.getServiceDate()) + .withTrip(tripTimes.getTrip()) + .build() + ) ) ) .collect(Collectors.toCollection(ArrayList::new)); diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 8128c36e4db..ef62fa23507 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -89,6 +89,38 @@ public static List fromTripTimes( return out; } + /** + * Get first stop TripTimeOnDate from Timetable. + */ + public static TripTimeOnDate firstFromTripTimes( + Timetable table, + Trip trip, + LocalDate serviceDate, + Instant midnight + ) { + TripTimes times = table.getTripTimes(trip); + return new TripTimeOnDate(times, 0, table.getPattern(), serviceDate, midnight); + } + + /** + * Get last stop TripTimeOnDate from Timetable. + */ + public static TripTimeOnDate lastFromTripTimes( + Timetable table, + Trip trip, + LocalDate serviceDate, + Instant midnight + ) { + TripTimes times = table.getTripTimes(trip); + return new TripTimeOnDate( + times, + times.getNumStops() - 1, + table.getPattern(), + serviceDate, + midnight + ); + } + public static Comparator compareByDeparture() { return Comparator.comparing(t -> t.getServiceDayMidnight() + t.getRealtimeDeparture()); } diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java b/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java deleted file mode 100644 index 2227421ed0e..00000000000 --- a/src/main/java/org/opentripplanner/transit/model/timetable/DatedTrip.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.opentripplanner.transit.model.timetable; - -import java.time.LocalDate; - -/** - * Class which represents a trip on a specific date - */ -public record DatedTrip(Trip trip, LocalDate serviceDate) {} diff --git a/src/main/java/org/opentripplanner/transit/model/timetable/TripOnServiceDate.java b/src/main/java/org/opentripplanner/transit/model/timetable/TripOnServiceDate.java index 1b4ecc964cf..68b442d0f49 100644 --- a/src/main/java/org/opentripplanner/transit/model/timetable/TripOnServiceDate.java +++ b/src/main/java/org/opentripplanner/transit/model/timetable/TripOnServiceDate.java @@ -8,7 +8,8 @@ import org.opentripplanner.transit.model.framework.FeedScopedId; /** - * Class for holding data about a certain trip on a certain day. Essentially a DatedServiceJourney. + * Class for holding data about a certain trip on a certain day. Essentially a DatedServiceJourney + * or an instance of a generic trip on a certain service date. */ public class TripOnServiceDate extends AbstractTransitEntity { diff --git a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 7eb28e50c7c..d57951fdba6 100644 --- a/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -51,7 +51,6 @@ import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.site.StopLocationsGroup; -import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -289,17 +288,17 @@ public void addTripForId(FeedScopedId tripId, Trip trip) { * TODO This only supports realtime cancelled trips for now. */ @Override - public Collection getCanceledTrips(List feeds) { + public Collection getCanceledTrips(List feeds) { OTPRequestTimeoutException.checkForTimeout(); var timetableSnapshot = lazyGetTimeTableSnapShot(); if (timetableSnapshot == null) { return List.of(); } - List canceledTrips = timetableSnapshot.getCanceledTrips(feeds); + List canceledTrips = timetableSnapshot.getCanceledTrips(feeds); canceledTrips.sort((t1, t2) -> { - if (t1.serviceDate().isBefore(t2.serviceDate())) { + if (t1.getServiceDate().isBefore(t2.getServiceDate())) { return -1; - } else if (t2.serviceDate().isBefore(t1.serviceDate())) { + } else if (t2.getServiceDate().isBefore(t1.getServiceDate())) { return 1; } var departure1 = getDepartureTime(t1); @@ -310,7 +309,7 @@ public Collection getCanceledTrips(List feeds) { return 1; } else { // identical departure day and time, so sort by unique feedscope id - return t1.trip().getId().compareTo(t2.trip().getId()); + return t1.getTrip().getId().compareTo(t2.getTrip().getId()); } }); return canceledTrips; @@ -756,9 +755,9 @@ private static Stream sortByOccurrenceAndReduce(Stream input) { .map(Map.Entry::getKey); } - private int getDepartureTime(DatedTrip datedTrip) { - var pattern = getPatternForTrip(datedTrip.trip()); - var timetable = timetableSnapshot.resolve(pattern, datedTrip.serviceDate()); - return timetable.getTripTimes(datedTrip.trip()).getDepartureTime(0); + private int getDepartureTime(TripOnServiceDate trip) { + var pattern = getPatternForTrip(trip.getTrip()); + var timetable = timetableSnapshot.resolve(pattern, trip.getServiceDate()); + return timetable.getTripTimes(trip.getTrip()).getDepartureTime(0); } } diff --git a/src/main/java/org/opentripplanner/transit/service/TransitService.java b/src/main/java/org/opentripplanner/transit/service/TransitService.java index c2edd0b2751..139df44647b 100644 --- a/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -41,7 +41,6 @@ import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.site.StopLocationsGroup; -import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripIdAndServiceDate; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -142,7 +141,7 @@ public interface TransitService { * * @param feeds If not null, used for filtering. */ - Collection getCanceledTrips(List feeds); + Collection getCanceledTrips(List feeds); Collection getAllRoutes(); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index e493e6ac46a..18822b6802f 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -73,11 +73,11 @@ interface PlaceInterface { "Entity related to an alert" union AlertEntity = Agency | Pattern | Route | RouteType | Stop | StopOnRoute | StopOnTrip | Trip | Unknown -"Departure and/or arrival times to or from a stop on a specific date." -union DatedStopTime = ExactDatedStopTime - union StopPosition = PositionAtStop | PositionBetweenStops +"An instance of a trip on a service date." +union TripOnServiceDate = FixedTripOnServiceDate + "A public transport agency" type Agency implements Node { """ @@ -398,75 +398,6 @@ type Currency { digits: Int! } -"Trip on a specific date" -type DatedTrip implements Node { - """ - The service date when the trip occurs. - - **Note**: A service date is a technical term useful for transit planning purposes and might not - correspond to a how a passenger thinks of a calendar date. For example, a night bus running - on Sunday morning at 1am to 3am, might have the previous Saturday's service date. - """ - date: LocalDate! - "The time when the trip ends including real-time information, if available." - end: ArrivalDepartureTime - "Global object ID provided by Relay. This value can be used to refetch this object using **node** query." - id: ID! - "The pattern the trip is running on" - pattern: Pattern - "The route the trip is running on" - route: Route! - "The time when the trip starts including real-time information, if available." - start: ArrivalDepartureTime - "List of stops this trip passes through" - stops: [Stop!]! - "List of times when this trip arrives to or departs from a stop" - stoptimes: [DatedStopTime!] - "Headsign of the vehicle when running on this trip" - tripHeadsign( - """ - If a translated headsign is found from GTFS translation.txt and wanted language is not same as - feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. - """ - language: String - ): String - tripShortName: String -} - -""" -A connection to a list of dated trips that follows -[GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). -""" -type DatedTripConnection { - """ - Edges which contain the trips. Part of the - [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). - """ - edges: [DatedTripEdge] - """ - Contains cursors to fetch more pages of trips. - Part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). - """ - pageInfo: PageInfo! -} - -""" -An edge for DatedTrip connection. Part of the -[GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). -""" -type DatedTripEdge { - """ - The cursor of the edge. Part of the - [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). - """ - cursor: String! - """ - Dated trip as a node. Part of the - [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). - """ - node: DatedTrip -} - """ The standard case of a fare product: it only has a single price to be paid by the passenger and no discounts are applied. @@ -527,58 +458,6 @@ type Emissions { co2: Grams } -""" -Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. -This can include realtime estimates. -""" -type ExactDatedStopTime { - "Scheduled arrival time to the stop and a realtime estimate, if one exists." - arrival: ArrivalDepartureTime - "Scheduled departure time from the stop and a realtime estimate, if one exists." - departure: ArrivalDepartureTime - """ - Whether the vehicle can be disembarked at this stop. This field can also be - used to indicate if disembarkation is possible only with special arrangements. - """ - dropoffType: PickupDropoffType - """ - Vehicle headsign of the trip on this stop. Trip headsigns can change during - the trip (e.g. on routes which run on loops), so this value should be used - instead of `tripHeadsign` to display the headsign relevant to the user. - """ - headsign( - """ - If translated headsign is found from gtfs translation.txt and wanted language is not same as - feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. - """ - language: String - ): String - """ - Whether the vehicle can be boarded at this stop. This field can also be used - to indicate if boarding is possible only with special arrangements. - """ - pickupType: PickupDropoffType - "Whether stop has been updated through a realtime update and if so, how." - realtimeState: StopRealTimeState! - "The stop where this arrival/departure happens" - stop: Stop - """ - The sequence of the stop in the pattern. This is not required to start from 0 or be consecutive - any - increasing integer sequence along the stops is valid. - - The purpose of this field is to identify the stop within the pattern so it can be cross-referenced - between it and the itinerary. It is safe to cross-reference when done quickly, i.e. within seconds. - However, it should be noted that real-time updates can change the values, so don't store it for - longer amounts of time. - - Depending on the source data, this might not be the GTFS `stop_sequence` but another value, perhaps - even generated. - """ - stopPosition: Int - "true, if this stop is used as a time equalization stop. false otherwise." - timepoint: Boolean -} - "A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'." type FareMedium { "ID of the medium" @@ -671,6 +550,78 @@ type FeedPublisher { url: String! } +""" +Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. +This can include realtime estimates. +""" +type FixedDatedStopTime { + "Scheduled arrival time to the stop and a realtime estimate, if one exists." + arrival: ArrivalDepartureTime + "Scheduled departure time from the stop and a realtime estimate, if one exists." + departure: ArrivalDepartureTime + """ + Whether the vehicle can be disembarked at this stop. This field can also be + used to indicate if disembarkation is possible only with special arrangements. + """ + dropOffType: PickupDropoffType + """ + Vehicle headsign of the trip on this stop. Trip headsigns can change during + the trip (e.g. on routes which run on loops), so this value should be used + instead of `tripHeadsign` to display the headsign relevant to the user. + """ + headsign( + """ + If translated headsign is found from gtfs translation.txt and wanted language is not same as + feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. + """ + language: String + ): String + """ + Whether the vehicle can be boarded at this stop. This field can also be used + to indicate if boarding is possible only with special arrangements. + """ + pickupType: PickupDropoffType + "Whether stop has been updated through a realtime update and if so, how." + realtimeState: StopRealTimeState! + "The stop where this arrival/departure happens" + stop: Stop + """ + The sequence of the stop in the pattern. This is not required to start from 0 or be consecutive - any + increasing integer sequence along the stops is valid. + + The purpose of this field is to identify the stop within the pattern so it can be cross-referenced + between it and the itinerary. It is safe to cross-reference when done quickly, i.e. within seconds. + However, it should be noted that real-time updates can change the values, so don't store it for + longer amounts of time. + + Depending on the source data, this might not be the GTFS `stop_sequence` but another value, perhaps + even generated. + """ + stopPosition: Int + "true, if this stop is used as a time equalization stop. false otherwise." + timepoint: Boolean +} + +"A fixed (i.e. not flexible or frequency based) trip on a specific service date" +type FixedTripOnServiceDate { + """ + The service date when the trip occurs. + + **Note**: A service date is a technical term useful for transit planning purposes and might not + correspond to a how a passenger thinks of a calendar date. For example, a night bus running + on Sunday morning at 1am to 3am, might have the previous Saturday's service date. + """ + date: LocalDate! + "The time when the trip ends at a stop and information related to the stop." + end: FixedDatedStopTime + "The time when the trip starts from a stop and information related to the stop." + start: FixedDatedStopTime + "List of times when this trip arrives to or departs from a stop and information related to the stop" + stoptimes: [FixedDatedStopTime!] + "This trip on service date is an instance of this trip." + trip: Trip +} + type Geometry { "The number of points in the string" length: Int @@ -1239,7 +1190,7 @@ type QueryType { feeds: [String], first: Int, last: Int - ): DatedTripConnection + ): TripOnServiceDateConnection "Get canceled TripTimes." cancelledTripTimes( "Feed feedIds (e.g. [\"HSL\"])." @@ -2482,6 +2433,40 @@ type TripOccupancy { occupancyStatus: OccupancyStatus } +""" +A connection to a list of trips on service dates that follows +[GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). +""" +type TripOnServiceDateConnection { + """ + Edges which contain the trips. Part of the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ + edges: [TripOnServiceDateEdge] + """ + Contains cursors to fetch more pages of trips. + Part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ + pageInfo: PageInfo! +} + +""" +An edge for TripOnServiceDate connection. Part of the +[GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). +""" +type TripOnServiceDateEdge { + """ + The cursor of the edge. Part of the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ + cursor: String! + """ + Trip on a service date as a node. Part of the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). + """ + node: TripOnServiceDate +} + "This is used for alert entities that we don't explicitly handle or they are missing." type Unknown { "Entity's description" diff --git a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index bdf9bbb73f0..fedcb3fe884 100644 --- a/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -25,7 +25,6 @@ import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.Station; import org.opentripplanner.transit.model.site.StopLocation; -import org.opentripplanner.transit.model.timetable.DatedTrip; import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; import org.opentripplanner.transit.model.timetable.ScheduledTripTimes; import org.opentripplanner.transit.model.timetable.Trip; @@ -149,10 +148,7 @@ void getPatternForStopsWithRealTime() { @Test void getCanceledTrips() { - Collection canceledTrips = service.getCanceledTrips(null); - assertEquals( - "[DatedTrip[trip=Trip{F:123 RR123}, serviceDate=2024-08-08], DatedTrip[trip=Trip{F:123 RR123}, serviceDate=2024-08-09]]", - canceledTrips.toString() - ); + var canceledTrips = service.getCanceledTrips(null); + assertEquals("[TripOnServiceDate{F:123}, TripOnServiceDate{F:123}]", canceledTrips.toString()); } } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json index 5208a38fb01..1f3285d9e7d 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json @@ -12,41 +12,26 @@ "node": { "date": "2024-08-09", "end": { - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:40:00+02:00" - }, - "scheduledTime": "2024-08-09T11:40:00+02:00" + "arrival": { + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:40:00+02:00" + }, + "scheduledTime": "2024-08-09T11:40:00+02:00" + } }, "start": { - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:30:00+02:00" - }, - "scheduledTime": "2024-08-09T11:30:00+02:00" - }, - "pattern": { - "code": "F:BUS" - }, - "route": { - "gtfsId": "F:R321Canceled" - }, - "stops": [ - { - "gtfsId": "F:Stop_0" - }, - { - "gtfsId": "F:Stop_1" - }, - { - "gtfsId": "F:Stop_2" + "departure": { + "estimated": { + "delay": "PT0S", + "time": "2024-08-09T11:30:00+02:00" + }, + "scheduledTime": "2024-08-09T11:30:00+02:00" } - ], - "tripHeadsign": "Trip Headsign", - "tripShortName": null, + }, "stoptimes": [ { - "dropoffType": null, + "dropOffType": null, "headsign": "Stop headsign at stop 10", "pickupType": null, "realtimeState": "CANCELED", @@ -71,7 +56,7 @@ } }, { - "dropoffType": null, + "dropOffType": null, "headsign": "Stop headsign at stop 20", "pickupType": null, "realtimeState": "CANCELED", @@ -96,7 +81,7 @@ } }, { - "dropoffType": null, + "dropOffType": null, "headsign": "Stop headsign at stop 30", "pickupType": null, "realtimeState": "CANCELED", @@ -120,7 +105,10 @@ } } } - ] + ], + "trip": { + "gtfsId": "F:321Canceled" + } } } ] diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index 84452fd04b3..80b1dd089bd 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -8,35 +8,28 @@ } edges { node { - date - end { - estimated { - delay - time + ... on FixedTripOnServiceDate { + date + end { + arrival { + estimated { + delay + time + } + scheduledTime + } } - scheduledTime - } - start { - estimated { - delay - time + start { + departure { + estimated { + delay + time + } + scheduledTime + } } - scheduledTime - } - pattern { - code - } - route { - gtfsId - } - stops { - gtfsId - } - tripHeadsign - tripShortName - stoptimes { - ... on ExactDatedStopTime { - dropoffType + stoptimes { + dropOffType headsign pickupType realtimeState @@ -60,21 +53,10 @@ } } } - } - date - start { - estimated { - time - delay - } - scheduledTime - } - end { - estimated { - time - delay + date + trip { + gtfsId } - scheduledTime } } } From 079485ed16fdd5f24c5f394f813d9d419e541249 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 25 Oct 2024 21:25:44 +0300 Subject: [PATCH 23/48] Remove stuff from new stoptime type --- .../datafetchers/FixedDatedStopTimeImpl.java | 50 ---------------- .../FixedTripOnServiceDateImpl.java | 2 +- .../gtfs/generated/GraphQLDataFetchers.java | 15 +---- .../apis/gtfs/generated/GraphQLTypes.java | 29 --------- .../apis/gtfs/generated/graphql-codegen.yml | 1 - .../opentripplanner/apis/gtfs/schema.graphqls | 60 +------------------ .../gtfs/expectations/canceled-trips.json | 20 +------ .../apis/gtfs/queries/canceled-trips.graphql | 8 +-- 8 files changed, 5 insertions(+), 180 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java index df2864f8580..ea53804298a 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java @@ -7,10 +7,7 @@ import java.time.ZonedDateTime; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; -import org.opentripplanner.apis.gtfs.mapping.PickDropMapper; import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; -import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.service.TransitService; @@ -45,58 +42,11 @@ public DataFetcher departure() { }; } - @Override - public DataFetcher dropOffType() { - return environment -> PickDropMapper.map(getSource(environment).getDropoffType()); - } - - @Override - public DataFetcher headsign() { - return environment -> - GraphQLUtils.getTranslation(getSource(environment).getHeadsign(), environment); - } - - @Override - public DataFetcher pickupType() { - return environment -> PickDropMapper.map(getSource(environment).getPickupType()); - } - - @Override - public DataFetcher realtimeState() { - return environment -> { - var tripTime = getSource(environment); - // TODO support ADDED state - if (tripTime.isCanceledEffectively()) { - return GraphQLTypes.GraphQLStopRealTimeState.CANCELED; - } - if (tripTime.isNoDataStop()) { - return GraphQLTypes.GraphQLStopRealTimeState.NO_DATA; - } - if (tripTime.isRecordedStop()) { - return GraphQLTypes.GraphQLStopRealTimeState.RECORDED; - } - if (tripTime.isRealtime()) { - return GraphQLTypes.GraphQLStopRealTimeState.UPDATED; - } - return GraphQLTypes.GraphQLStopRealTimeState.UNUPDATED; - }; - } - - @Override - public DataFetcher stopPosition() { - return environment -> getSource(environment).getGtfsSequence(); - } - @Override public DataFetcher stop() { return environment -> getSource(environment).getStop(); } - @Override - public DataFetcher timepoint() { - return environment -> getSource(environment).isTimepoint(); - } - private TransitService getTransitService(DataFetchingEnvironment environment) { return environment.getContext().transitService(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java index 6b78bc0d13d..f6923cdc394 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java @@ -61,7 +61,7 @@ public DataFetcher start() { } @Override - public DataFetcher> stoptimes() { + public DataFetcher> stopTimes() { return environment -> { TransitService transitService = getTransitService(environment); Trip trip = getTrip(environment); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index e058705442c..f57a732dadb 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -21,7 +21,6 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRealtimeState; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRelativeDirection; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRoutingErrorCode; -import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLStopRealTimeState; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; import org.opentripplanner.apis.gtfs.model.FeedPublisher; @@ -430,19 +429,7 @@ public interface GraphQLFixedDatedStopTime { public DataFetcher departure(); - public DataFetcher dropOffType(); - - public DataFetcher headsign(); - - public DataFetcher pickupType(); - - public DataFetcher realtimeState(); - public DataFetcher stop(); - - public DataFetcher stopPosition(); - - public DataFetcher timepoint(); } /** A fixed (i.e. not flexible or frequency based) trip on a specific service date */ @@ -453,7 +440,7 @@ public interface GraphQLFixedTripOnServiceDate { public DataFetcher start(); - public DataFetcher> stoptimes(); + public DataFetcher> stopTimes(); public DataFetcher trip(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 693e613cea3..ee51eaa4e83 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -773,25 +773,6 @@ public enum GraphQLFilterPlaceType { VEHICLE_RENT, } - public static class GraphQLFixedDatedStopTimeHeadsignArgs { - - private String language; - - public GraphQLFixedDatedStopTimeHeadsignArgs(Map args) { - if (args != null) { - this.language = (String) args.get("language"); - } - } - - public String getGraphQLLanguage() { - return this.language; - } - - public void setGraphQLLanguage(String language) { - this.language = language; - } - } - public enum GraphQLFormFactor { BICYCLE, CAR, @@ -4623,16 +4604,6 @@ public enum GraphQLStopAlertType { TRIPS, } - /** Whether stop has been updated through a realtime update and if so, how. */ - public enum GraphQLStopRealTimeState { - ADDED, - CANCELED, - NO_DATA, - RECORDED, - UNUPDATED, - UPDATED, - } - public static class GraphQLStoptimeHeadsignArgs { private String language; diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index e3316e1d423..2c7fb9735f4 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -102,7 +102,6 @@ config: stopAtDistanceEdge: graphql.relay.Edge#Edge StopOnRoute: org.opentripplanner.apis.gtfs.model.StopOnRouteModel#StopOnRouteModel StopOnTrip: org.opentripplanner.apis.gtfs.model.StopOnTripModel#StopOnTripModel - StopRealTimeState: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLStopRealTimeState#GraphQLStopRealTimeState Stoptime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate StoptimesInPattern: org.opentripplanner.model.StopTimesInPattern#StopTimesInPattern TicketType: org.opentripplanner.ext.fares.model.FareRuleSet#FareRuleSet diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 212319455f3..2b15423fbc0 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -559,47 +559,8 @@ type FixedDatedStopTime { arrival: ArrivalDepartureTime "Scheduled departure time from the stop and a realtime estimate, if one exists." departure: ArrivalDepartureTime - """ - Whether the vehicle can be disembarked at this stop. This field can also be - used to indicate if disembarkation is possible only with special arrangements. - """ - dropOffType: PickupDropoffType - """ - Vehicle headsign of the trip on this stop. Trip headsigns can change during - the trip (e.g. on routes which run on loops), so this value should be used - instead of `tripHeadsign` to display the headsign relevant to the user. - """ - headsign( - """ - If translated headsign is found from gtfs translation.txt and wanted language is not same as - feed's language then returns wanted translation. Otherwise uses name from trip_headsign.txt. - """ - language: String - ): String - """ - Whether the vehicle can be boarded at this stop. This field can also be used - to indicate if boarding is possible only with special arrangements. - """ - pickupType: PickupDropoffType - "Whether stop has been updated through a realtime update and if so, how." - realtimeState: StopRealTimeState! "The stop where this arrival/departure happens" stop: Stop - """ - The sequence of the stop in the pattern. This is not required to start from 0 or be consecutive - any - increasing integer sequence along the stops is valid. - - The purpose of this field is to identify the stop within the pattern so it can be cross-referenced - between it and the itinerary. It is safe to cross-reference when done quickly, i.e. within seconds. - However, it should be noted that real-time updates can change the values, so don't store it for - longer amounts of time. - - Depending on the source data, this might not be the GTFS `stop_sequence` but another value, perhaps - even generated. - """ - stopPosition: Int - "true, if this stop is used as a time equalization stop. false otherwise." - timepoint: Boolean } "A fixed (i.e. not flexible or frequency based) trip on a specific service date" @@ -617,7 +578,7 @@ type FixedTripOnServiceDate { "The time when the trip starts from a stop and information related to the stop." start: FixedDatedStopTime "List of times when this trip arrives to or departs from a stop and information related to the stop" - stoptimes: [FixedDatedStopTime!] + stopTimes: [FixedDatedStopTime!] "This trip on service date is an instance of this trip." trip: Trip } @@ -3576,25 +3537,6 @@ enum StopAlertType { TRIPS } -"Whether stop has been updated through a realtime update and if so, how." -enum StopRealTimeState { - "The stop has been added through a realtime update." - ADDED - "The stop has been canceled through a realtime update." - CANCELED - "The realtime feed has indicated that there is no data available for this stop." - NO_DATA - """ - The vehicle has arrived to the stop or already visited it and the times are no longer estimates. - Note, not all realtime feeds indicate this information even if the vehicle has already passed the stop. - """ - RECORDED - "There have been no realtime updates." - UNUPDATED - "The trip's arrival and/or departure time has been updated." - UPDATED -} - """ Transit modes include modes that are used within organized transportation networks run by public transportation authorities, taxi companies etc. diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json index 1f3285d9e7d..5d60b684b76 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json @@ -29,17 +29,11 @@ "scheduledTime": "2024-08-09T11:30:00+02:00" } }, - "stoptimes": [ + "stopTimes": [ { - "dropOffType": null, - "headsign": "Stop headsign at stop 10", - "pickupType": null, - "realtimeState": "CANCELED", "stop": { "gtfsId": "F:Stop_0" }, - "stopPosition": 10, - "timepoint": false, "arrival": { "scheduledTime": "2024-08-09T11:30:00+02:00", "estimated": { @@ -56,15 +50,9 @@ } }, { - "dropOffType": null, - "headsign": "Stop headsign at stop 20", - "pickupType": null, - "realtimeState": "CANCELED", "stop": { "gtfsId": "F:Stop_1" }, - "stopPosition": 20, - "timepoint": false, "arrival": { "scheduledTime": "2024-08-09T11:35:00+02:00", "estimated": { @@ -81,15 +69,9 @@ } }, { - "dropOffType": null, - "headsign": "Stop headsign at stop 30", - "pickupType": null, - "realtimeState": "CANCELED", "stop": { "gtfsId": "F:Stop_2" }, - "stopPosition": 30, - "timepoint": false, "arrival": { "scheduledTime": "2024-08-09T11:40:00+02:00", "estimated": { diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index 80b1dd089bd..cb738d4c56b 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -28,16 +28,10 @@ scheduledTime } } - stoptimes { - dropOffType - headsign - pickupType - realtimeState + stopTimes { stop { gtfsId } - stopPosition - timepoint arrival { scheduledTime estimated { From c15a29edcb7289c8188d49b60d61c82bd15465b4 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 25 Oct 2024 21:32:33 +0300 Subject: [PATCH 24/48] Mark stopTimes as non-null --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2b15423fbc0..d7aaaf67002 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -578,7 +578,7 @@ type FixedTripOnServiceDate { "The time when the trip starts from a stop and information related to the stop." start: FixedDatedStopTime "List of times when this trip arrives to or departs from a stop and information related to the stop" - stopTimes: [FixedDatedStopTime!] + stopTimes: [FixedDatedStopTime!]! "This trip on service date is an instance of this trip." trip: Trip } From 65927c6e4670911c847055abfc3e5bf3fceda901 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 25 Oct 2024 21:36:32 +0300 Subject: [PATCH 25/48] Do less inside timetable snapshot provider initialization --- .../apis/gtfs/GraphQLIntegrationTest.java | 11 ++++--- .../service/DefaultTransitServiceTest.java | 29 +++++++++---------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 83abb6fcfdf..ec079341ad6 100644 --- a/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/application/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -253,13 +253,12 @@ public Set getRoutesForStop(StopLocation stop) { calendarServiceData, DataImportIssueStore.NOOP ); - timetableRepository.initTimetableSnapshotProvider(() -> { - TimetableSnapshot timetableSnapshot = new TimetableSnapshot(); - tripTimes2.cancelTrip(); - timetableSnapshot.update(new RealTimeTripUpdate(pattern, tripTimes2, secondDate)); + TimetableSnapshot timetableSnapshot = new TimetableSnapshot(); + tripTimes2.cancelTrip(); + timetableSnapshot.update(new RealTimeTripUpdate(pattern, tripTimes2, secondDate)); - return timetableSnapshot.commit(); - }); + var snapshot = timetableSnapshot.commit(); + timetableRepository.initTimetableSnapshotProvider(() -> snapshot); var step1 = walkStep("street") .withRelativeDirection(RelativeDirection.DEPART) diff --git a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 2268b3628e6..26317a0ea80 100644 --- a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -93,21 +93,20 @@ static void setup() { timetableRepository.addTripPattern(RAIL_PATTERN.getId(), RAIL_PATTERN); timetableRepository.index(); - timetableRepository.initTimetableSnapshotProvider(() -> { - TimetableSnapshot timetableSnapshot = new TimetableSnapshot(); - RealTimeTripTimes tripTimes = RealTimeTripTimes.of( - ScheduledTripTimes - .of() - .withTrip(TimetableRepositoryForTest.trip("REAL_TIME_TRIP").build()) - .withDepartureTimes(new int[] { 0, 1 }) - .build() - ); - timetableSnapshot.update(new RealTimeTripUpdate(REAL_TIME_PATTERN, tripTimes, firstDate)); - timetableSnapshot.update(new RealTimeTripUpdate(RAIL_PATTERN, canceledTripTimes, firstDate)); - timetableSnapshot.update(new RealTimeTripUpdate(RAIL_PATTERN, canceledTripTimes, secondDate)); - - return timetableSnapshot.commit(); - }); + TimetableSnapshot timetableSnapshot = new TimetableSnapshot(); + RealTimeTripTimes tripTimes = RealTimeTripTimes.of( + ScheduledTripTimes + .of() + .withTrip(TimetableRepositoryForTest.trip("REAL_TIME_TRIP").build()) + .withDepartureTimes(new int[] { 0, 1 }) + .build() + ); + timetableSnapshot.update(new RealTimeTripUpdate(REAL_TIME_PATTERN, tripTimes, firstDate)); + timetableSnapshot.update(new RealTimeTripUpdate(RAIL_PATTERN, canceledTripTimes, firstDate)); + timetableSnapshot.update(new RealTimeTripUpdate(RAIL_PATTERN, canceledTripTimes, secondDate)); + + var snapshot = timetableSnapshot.commit(); + timetableRepository.initTimetableSnapshotProvider(() -> snapshot); service = new DefaultTransitService(timetableRepository) { From 9c124df484601c49a5de578c5ed020d058e339bc Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 25 Oct 2024 22:08:46 +0300 Subject: [PATCH 26/48] Minor fixes --- .../apis/gtfs/datafetchers/LegImpl.java | 14 +++++++------- .../apis/gtfs/datafetchers/StoptimeImpl.java | 4 ++-- .../apis/gtfs/generated/GraphQLDataFetchers.java | 9 +++++---- .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../apis/gtfs/mapping/PickDropMapper.java | 11 ++++++----- .../apis/gtfs/model/ArrivalDepartureTime.java | 5 +---- .../org/opentripplanner/model/TripTimeOnDate.java | 4 ++-- .../street/model/vertex/StationCentroidVertex.java | 1 - .../transit/service/DefaultTransitService.java | 2 +- .../transit/service/TransitService.java | 2 +- 10 files changed, 26 insertions(+), 28 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 86d6d5be1a9..4db347ee784 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -10,12 +10,12 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; import org.opentripplanner.apis.gtfs.mapping.NumberMapper; +import org.opentripplanner.apis.gtfs.mapping.PickDropMapper; import org.opentripplanner.apis.gtfs.mapping.RealtimeStateMapper; import org.opentripplanner.ext.restapi.mapping.LocalDateMapper; import org.opentripplanner.ext.ridehailing.model.RideEstimate; import org.opentripplanner.ext.ridehailing.model.RideHailingLeg; import org.opentripplanner.framework.graphql.GraphQLUtils; -import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; import org.opentripplanner.model.plan.LegTime; @@ -66,12 +66,12 @@ public DataFetcher dropOffBookingInfo() { } @Override - public DataFetcher dropoffType() { + public DataFetcher dropoffType() { return environment -> { if (getSource(environment).getAlightRule() == null) { - return PickDrop.SCHEDULED.name(); + return GraphQLTypes.GraphQLPickupDropoffType.SCHEDULED; } - return getSource(environment).getAlightRule().name(); + return PickDropMapper.map(getSource(environment).getAlightRule()); }; } @@ -177,12 +177,12 @@ public DataFetcher pickupBookingInfo() { } @Override - public DataFetcher pickupType() { + public DataFetcher pickupType() { return environment -> { if (getSource(environment).getBoardRule() == null) { - return PickDrop.SCHEDULED.name(); + return GraphQLTypes.GraphQLPickupDropoffType.SCHEDULED; } - return getSource(environment).getBoardRule().name(); + return PickDropMapper.map(getSource(environment).getBoardRule()); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java index 155c754cfa8..e6244124ba9 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -25,7 +25,7 @@ public DataFetcher departureDelay() { } @Override - public DataFetcher dropoffType() { + public DataFetcher dropoffType() { return environment -> PickDropMapper.map(getSource(environment).getDropoffType()); } @@ -36,7 +36,7 @@ public DataFetcher headsign() { } @Override - public DataFetcher pickupType() { + public DataFetcher pickupType() { return environment -> PickDropMapper.map(getSource(environment).getPickupType()); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index f57a732dadb..eeeac1ffd0f 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -18,6 +18,7 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLBikesAllowed; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus; +import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLPickupDropoffType; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRealtimeState; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRelativeDirection; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRoutingErrorCode; @@ -504,7 +505,7 @@ public interface GraphQLLeg { public DataFetcher dropOffBookingInfo(); - public DataFetcher dropoffType(); + public DataFetcher dropoffType(); public DataFetcher duration(); @@ -538,7 +539,7 @@ public interface GraphQLLeg { public DataFetcher pickupBookingInfo(); - public DataFetcher pickupType(); + public DataFetcher pickupType(); public DataFetcher realTime(); @@ -1110,11 +1111,11 @@ public interface GraphQLStoptime { public DataFetcher departureDelay(); - public DataFetcher dropoffType(); + public DataFetcher dropoffType(); public DataFetcher headsign(); - public DataFetcher pickupType(); + public DataFetcher pickupType(); public DataFetcher realtime(); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 2c7fb9735f4..5309310e80d 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -80,7 +80,7 @@ config: TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode PageInfo: Object Pattern: org.opentripplanner.transit.model.network.TripPattern#TripPattern - PickupDropoffType: String + PickupDropoffType: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLPickupDropoffType#GraphQLPickupDropoffType Place: org.opentripplanner.model.plan.StopArrival#StopArrival placeAtDistance: org.opentripplanner.routing.graphfinder.PlaceAtDistance#PlaceAtDistance placeAtDistanceConnection: graphql.relay.Connection#Connection diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java b/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java index c8e4d212999..acb7e61cc4b 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/mapping/PickDropMapper.java @@ -1,17 +1,18 @@ package org.opentripplanner.apis.gtfs.mapping; import javax.annotation.Nullable; +import org.opentripplanner.apis.gtfs.generated.GraphQLTypes; import org.opentripplanner.model.PickDrop; public final class PickDropMapper { @Nullable - public static String map(PickDrop pickDrop) { + public static GraphQLTypes.GraphQLPickupDropoffType map(PickDrop pickDrop) { return switch (pickDrop) { - case SCHEDULED -> "SCHEDULED"; - case NONE -> "NONE"; - case CALL_AGENCY -> "CALL_AGENCY"; - case COORDINATE_WITH_DRIVER -> "COORDINATE_WITH_DRIVER"; + case SCHEDULED -> GraphQLTypes.GraphQLPickupDropoffType.SCHEDULED; + case NONE -> GraphQLTypes.GraphQLPickupDropoffType.NONE; + case CALL_AGENCY -> GraphQLTypes.GraphQLPickupDropoffType.CALL_AGENCY; + case COORDINATE_WITH_DRIVER -> GraphQLTypes.GraphQLPickupDropoffType.COORDINATE_WITH_DRIVER; case CANCELLED -> null; }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java b/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java index 529d83c7459..3a801537dd1 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java @@ -2,7 +2,6 @@ import java.time.Duration; import java.time.ZonedDateTime; -import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -10,16 +9,14 @@ * if available. */ public record ArrivalDepartureTime( - @Nonnull ZonedDateTime scheduledTime, + ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated ) { - @Nonnull public static ArrivalDepartureTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); return new ArrivalDepartureTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); } - @Nonnull public static ArrivalDepartureTime ofStatic(ZonedDateTime staticTime) { return new ArrivalDepartureTime(staticTime, null); } diff --git a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 4c0a4eda26c..857bb42ee51 100644 --- a/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/application/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -172,14 +172,14 @@ public int getRealtimeDeparture() { * Returns the actual arrival time if available. Otherwise -1 is returned. */ public int getActualArrival() { - return tripTimes.isRecordedStop(stopIndex) ? tripTimes.getArrivalTime(stopIndex) : UNDEFINED; + return isRecordedStop() ? tripTimes.getArrivalTime(stopIndex) : UNDEFINED; } /** * Returns the actual departure time if available. Otherwise -1 is returned. */ public int getActualDeparture() { - return tripTimes.isRecordedStop(stopIndex) ? tripTimes.getDepartureTime(stopIndex) : UNDEFINED; + return isRecordedStop() ? tripTimes.getDepartureTime(stopIndex) : UNDEFINED; } public int getArrivalDelay() { diff --git a/application/src/main/java/org/opentripplanner/street/model/vertex/StationCentroidVertex.java b/application/src/main/java/org/opentripplanner/street/model/vertex/StationCentroidVertex.java index f6f3b00191d..30de8e0f597 100644 --- a/application/src/main/java/org/opentripplanner/street/model/vertex/StationCentroidVertex.java +++ b/application/src/main/java/org/opentripplanner/street/model/vertex/StationCentroidVertex.java @@ -20,7 +20,6 @@ public Station getStation() { return this.station; } - @Nonnull @Override public I18NString getName() { return station.getName(); diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index c8cfbcaae4f..8270a0e06d1 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -298,7 +298,7 @@ public Trip getScheduledTripForId(FeedScopedId id) { * TODO This only supports realtime cancelled trips for now. */ @Override - public Collection getCanceledTrips(List feeds) { + public Collection getCanceledTrips(@Nullable List feeds) { OTPRequestTimeoutException.checkForTimeout(); var timetableSnapshot = lazyGetTimeTableSnapShot(); if (timetableSnapshot == null) { diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java index d74401c0def..c8b1cc21e63 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -174,7 +174,7 @@ public interface TransitService { * * @param feeds If not null, used for filtering. */ - Collection getCanceledTrips(List feeds); + Collection getCanceledTrips(@Nullable List feeds); /** * Return all routes, including those created by real-time updates. From 9e5eb1489819ca82f58fd91544492597367e2ef7 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 25 Oct 2024 22:17:43 +0300 Subject: [PATCH 27/48] Rename FixedDatedStopTime -> FixedStopTimeOnServiceDate --- .../org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 4 ++-- ...pTimeImpl.java => FixedStopTimeOnServiceDateImpl.java} | 3 ++- .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../org/opentripplanner/apis/gtfs/schema.graphqls | 8 ++++---- 4 files changed, 9 insertions(+), 8 deletions(-) rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{FixedDatedStopTimeImpl.java => FixedStopTimeOnServiceDateImpl.java} (95%) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index c8587e5851a..9aeed1e9472 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -40,7 +40,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.FareProductTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.FareProductUseImpl; import org.opentripplanner.apis.gtfs.datafetchers.FeedImpl; -import org.opentripplanner.apis.gtfs.datafetchers.FixedDatedStopTimeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.FixedStopTimeOnServiceDateImpl; import org.opentripplanner.apis.gtfs.datafetchers.FixedTripOnServiceDateImpl; import org.opentripplanner.apis.gtfs.datafetchers.GeometryImpl; import org.opentripplanner.apis.gtfs.datafetchers.ItineraryImpl; @@ -183,7 +183,7 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) .type(typeWiring.build(FixedTripOnServiceDateImpl.class)) - .type(typeWiring.build(FixedDatedStopTimeImpl.class)) + .type(typeWiring.build(FixedStopTimeOnServiceDateImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java similarity index 95% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java index ea53804298a..50cdb002a3e 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedDatedStopTimeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java @@ -12,7 +12,8 @@ import org.opentripplanner.model.TripTimeOnDate; import org.opentripplanner.transit.service.TransitService; -public class FixedDatedStopTimeImpl implements GraphQLDataFetchers.GraphQLFixedDatedStopTime { +public class FixedStopTimeOnServiceDateImpl + implements GraphQLDataFetchers.GraphQLFixedDatedStopTime { @Override public DataFetcher arrival() { diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 5309310e80d..66b701c5e01 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -59,7 +59,7 @@ config: ContactInfo: org.opentripplanner.transit.model.organization.ContactInfo Cluster: Object Coordinates: org.locationtech.jts.geom.Coordinate#Coordinate - FixedDatedStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate + FixedStopTimeOnServiceDate: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate FixedTripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate TripOnServiceDateConnection: graphql.relay.Connection#Connection TripOnServiceDateEdge: graphql.relay.Edge#Edge diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index d7aaaf67002..00aa6ab71b4 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -554,7 +554,7 @@ type FeedPublisher { Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. This can include realtime estimates. """ -type FixedDatedStopTime { +type FixedStopTimeOnServiceDate { "Scheduled arrival time to the stop and a realtime estimate, if one exists." arrival: ArrivalDepartureTime "Scheduled departure time from the stop and a realtime estimate, if one exists." @@ -574,11 +574,11 @@ type FixedTripOnServiceDate { """ date: LocalDate! "The time when the trip ends at a stop and information related to the stop." - end: FixedDatedStopTime + end: FixedStopTimeOnServiceDate "The time when the trip starts from a stop and information related to the stop." - start: FixedDatedStopTime + start: FixedStopTimeOnServiceDate "List of times when this trip arrives to or departs from a stop and information related to the stop" - stopTimes: [FixedDatedStopTime!]! + stopTimes: [FixedStopTimeOnServiceDate!]! "This trip on service date is an instance of this trip." trip: Trip } From 7f1948e4c8d4011732f19a5cb9c0cea40cf97641 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 25 Oct 2024 22:33:21 +0300 Subject: [PATCH 28/48] Run codegen --- .../apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java | 2 +- .../apis/gtfs/generated/GraphQLDataFetchers.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java index 50cdb002a3e..f6e8c62b223 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java @@ -13,7 +13,7 @@ import org.opentripplanner.transit.service.TransitService; public class FixedStopTimeOnServiceDateImpl - implements GraphQLDataFetchers.GraphQLFixedDatedStopTime { + implements GraphQLDataFetchers.GraphQLFixedStopTimeOnServiceDate { @Override public DataFetcher arrival() { diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index eeeac1ffd0f..9dc3fa6662f 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -425,7 +425,7 @@ public interface GraphQLFeedPublisher { * Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. * This can include realtime estimates. */ - public interface GraphQLFixedDatedStopTime { + public interface GraphQLFixedStopTimeOnServiceDate { public DataFetcher arrival(); public DataFetcher departure(); From 7ed48c3d556ab37bb375f8c23eb34018c30d5b39 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Thu, 31 Oct 2024 15:11:20 +0200 Subject: [PATCH 29/48] Improve schema doc and mark some fields as non-null --- .../opentripplanner/apis/gtfs/schema.graphqls | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 4f51c0e3085..2853164008c 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -165,7 +165,7 @@ type ArrivalDepartureTime { "The estimated time of the event. If no real-time information is available, this is null." estimated: RealTimeEstimate "The scheduled time of the event." - scheduledTime: OffsetDateTime + scheduledTime: OffsetDateTime! } "Bike park represents a location where bicycles can be parked." @@ -573,10 +573,10 @@ type FixedTripOnServiceDate { on Sunday morning at 1am to 3am, might have the previous Saturday's service date. """ date: LocalDate! - "The time when the trip ends at a stop and information related to the stop." - end: FixedStopTimeOnServiceDate - "The time when the trip starts from a stop and information related to the stop." - start: FixedStopTimeOnServiceDate + "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." + end: FixedStopTimeOnServiceDate! + "Information related to trip's scheduled departure from the first stop. Can contain realtime information." + start: FixedStopTimeOnServiceDate! "List of times when this trip arrives to or departs from a stop and information related to the stop" stopTimes: [FixedStopTimeOnServiceDate!]! "This trip on service date is an instance of this trip." @@ -1146,15 +1146,32 @@ type QueryType { ids: [String] ): [BikeRentalStation] @deprecated(reason : "Use rentalVehicles or vehicleRentalStations instead") """ - Get pages of canceled Trips. Follows the + Get pages of canceled Trips. Planned cancellations are not currently supported. Follows the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). """ canceledTrips( + """ + This parameter is part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm) + and should be used together with the `first` parameter. + """ after: String, + """ + This parameter is part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm) + and should be used together with the `last` parameter. + """ before: String, "Feed feedIds (e.g. [\"HSL\"])." feeds: [String], + """ + Limits how many trips are returned. This parameter is part of the + [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm) and can be used together with + the `after` parameter. + """ first: Int, + """ + This parameter is part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm) + and should be used together with the `before` parameter. + """ last: Int ): TripOnServiceDateConnection "Get canceled TripTimes." @@ -1191,7 +1208,7 @@ type QueryType { routes: [String], "Trip gtfsIds (e.g. [\"HSL:1098_20190405_Ma_2_1455\"])." trips: [String] - ): [Stoptime] @deprecated(reason : "`cancelledTripTimes` is deprecated. Use `canceledTrips` instead.") + ): [Stoptime] @deprecated(reason : "`cancelledTripTimes` is not implemented. Use `canceledTrips` instead.") "Get a single car park based on its ID, i.e. value of field `carParkId`" carPark(id: String!): CarPark @deprecated(reason : "carPark is deprecated. Use vehicleParking instead.") "Get all car parks" From 2797fa53f4d1f2faeff9ae2b0704c0069046b7c6 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 1 Nov 2024 13:44:40 +0200 Subject: [PATCH 30/48] Slightly refactor methods to fetch cancelled trips --- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 12 ++- .../model/TimetableSnapshot.java | 75 ++++++++++++------- .../service/DefaultTransitService.java | 65 +++++++++++----- .../transit/service/TransitService.java | 11 ++- .../service/DefaultTransitServiceTest.java | 22 +++++- 5 files changed, 131 insertions(+), 54 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 5b9c151557b..784dd5f51bf 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -833,9 +833,15 @@ public DataFetcher> trips() { public DataFetcher> canceledTrips() { return environment -> { var args = new GraphQLTypes.GraphQLQueryTypeCanceledTripsArgs(environment.getArguments()); - var trips = new ArrayList<>( - getTransitService(environment).getCanceledTrips(args.getGraphQLFeeds()) - ); + if (args.getGraphQLFeeds() != null && args.getGraphQLFeeds().isEmpty()) { + throw new IllegalArgumentException( + "Feeds need to be either not specified or contain elements." + ); + } + + var trips = args.getGraphQLFeeds() != null + ? getTransitService(environment).findCanceledTrips(args.getGraphQLFeeds()) + : getTransitService(environment).listCanceledTrips(); return new SimpleListConnection<>(trips).get(environment); }; } diff --git a/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java b/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java index f8365ef025a..b8aace7feb0 100644 --- a/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java +++ b/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java @@ -20,6 +20,7 @@ import java.util.Map.Entry; import java.util.SortedSet; import java.util.TreeSet; +import java.util.function.Predicate; import java.util.stream.Collectors; import javax.annotation.Nullable; import org.opentripplanner.routing.algorithm.raptoradapter.transit.mappers.TransitLayerUpdater; @@ -226,35 +227,24 @@ public TripPattern getNewTripPatternForModifiedTrip(FeedScopedId tripId, LocalDa } /** - * Get trips which have been canceled. + * Find trips which have been canceled. * - * @param feeds if not null, only return trips from these feeds + * @param feeds only return trips from these feeds. Empty list is not allowed. */ - public ArrayList getCanceledTrips(List feeds) { - return timetables - .values() - .stream() - .flatMap(timetables -> - timetables - .stream() - .flatMap(timetable -> - timetable - .getTripTimes() - .stream() - .filter(tripTimes -> - tripTimes.isCanceled() && - (feeds == null || feeds.contains(tripTimes.getTrip().getId().getFeedId())) - ) - .map(tripTimes -> - TripOnServiceDate - .of(tripTimes.getTrip().getId()) - .withServiceDate(timetable.getServiceDate()) - .withTrip(tripTimes.getTrip()) - .build() - ) - ) - ) - .collect(Collectors.toCollection(ArrayList::new)); + public List findCanceledTrips(List feeds) { + if (feeds == null || feeds.isEmpty()) { + throw new IllegalArgumentException("Feeds list cannot be null or empty"); + } + return findTripsOnServiceDates(tripTimes -> + tripTimes.isCanceled() && feeds.contains(tripTimes.getTrip().getId().getFeedId()) + ); + } + + /** + * List trips which have been canceled. + */ + public List listCanceledTrips() { + return findTripsOnServiceDates(TripTimes::isCanceled); } /** @@ -679,6 +669,37 @@ private void validateNotReadOnly() { } } + private TripOnServiceDate mapToTripOnServiceDate(TripTimes tripTimes, Timetable timetable) { + return TripOnServiceDate + .of(tripTimes.getTrip().getId()) + .withServiceDate(timetable.getServiceDate()) + .withTrip(tripTimes.getTrip()) + .build(); + } + + /** + * Find trips from timetables based on filter criteria. + * + * @param filter used to filter {@link TripTimes}. + */ + private List findTripsOnServiceDates(Predicate filter) { + return timetables + .values() + .stream() + .flatMap(timetables -> + timetables + .stream() + .flatMap(timetable -> + timetable + .getTripTimes() + .stream() + .filter(filter) + .map(tripTimes -> mapToTripOnServiceDate(tripTimes, timetable)) + ) + ) + .collect(Collectors.toCollection(ArrayList::new)); + } + protected static class SortedTimetableComparator implements Comparator { @Override diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 98f73d5afcb..114414210ce 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -10,6 +10,7 @@ import java.time.ZonedDateTime; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -298,30 +299,34 @@ public Trip getScheduledTripForId(FeedScopedId id) { * TODO This only supports realtime cancelled trips for now. */ @Override - public Collection getCanceledTrips(@Nullable List feeds) { + public List findCanceledTrips(List feeds) { + if (feeds == null || feeds.isEmpty()) { + throw new IllegalArgumentException( + "Feeds list cannot be empty or null. It needs to have elements." + ); + } OTPRequestTimeoutException.checkForTimeout(); var timetableSnapshot = lazyGetTimeTableSnapShot(); if (timetableSnapshot == null) { return List.of(); } - List canceledTrips = timetableSnapshot.getCanceledTrips(feeds); - canceledTrips.sort((t1, t2) -> { - if (t1.getServiceDate().isBefore(t2.getServiceDate())) { - return -1; - } else if (t2.getServiceDate().isBefore(t1.getServiceDate())) { - return 1; - } - var departure1 = getDepartureTime(t1); - var departure2 = getDepartureTime(t2); - if (departure1 < departure2) { - return -1; - } else if (departure1 > departure2) { - return 1; - } else { - // identical departure day and time, so sort by unique feedscope id - return t1.getTrip().getId().compareTo(t2.getTrip().getId()); - } - }); + List canceledTrips = timetableSnapshot.findCanceledTrips(feeds); + canceledTrips.sort(new TripOnServiceDateComparator()); + return canceledTrips; + } + + /** + * TODO This only supports realtime cancelled trips for now. + */ + @Override + public List listCanceledTrips() { + OTPRequestTimeoutException.checkForTimeout(); + var timetableSnapshot = lazyGetTimeTableSnapShot(); + if (timetableSnapshot == null) { + return List.of(); + } + List canceledTrips = timetableSnapshot.listCanceledTrips(); + canceledTrips.sort(new TripOnServiceDateComparator()); return canceledTrips; } @@ -799,4 +804,26 @@ private int getDepartureTime(TripOnServiceDate trip) { var timetable = timetableSnapshot.resolve(pattern, trip.getServiceDate()); return timetable.getTripTimes(trip.getTrip()).getDepartureTime(0); } + + private class TripOnServiceDateComparator implements Comparator { + + @Override + public int compare(TripOnServiceDate t1, TripOnServiceDate t2) { + if (t1.getServiceDate().isBefore(t2.getServiceDate())) { + return -1; + } else if (t2.getServiceDate().isBefore(t1.getServiceDate())) { + return 1; + } + var departure1 = getDepartureTime(t1); + var departure2 = getDepartureTime(t2); + if (departure1 < departure2) { + return -1; + } else if (departure1 > departure2) { + return 1; + } else { + // identical departure day and time, so sort by unique feedscope id + return t1.getTrip().getId().compareTo(t2.getTrip().getId()); + } + } + } } diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java index c8b1cc21e63..4e0b49d559f 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -170,11 +170,16 @@ public interface TransitService { Collection getAllTrips(); /** - * Get canceled trips. + * Find canceled trips. * - * @param feeds If not null, used for filtering. + * @param feeds used for filtering. Empty list is not allowed. */ - Collection getCanceledTrips(@Nullable List feeds); + List findCanceledTrips(List feeds); + + /** + * List all canceled trips. + */ + List listCanceledTrips(); /** * Return all routes, including those created by real-time updates. diff --git a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 1d463955bad..534b0103854 100644 --- a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -1,5 +1,6 @@ package org.opentripplanner.transit.service; +import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.model.plan.PlanTestConstants.T11_30; import static org.opentripplanner.transit.model.basic.TransitMode.BUS; @@ -152,8 +153,25 @@ void getPatternForStopsWithRealTime() { } @Test - void getCanceledTrips() { - var canceledTrips = service.getCanceledTrips(null); + void listCanceledTrips() { + var canceledTrips = service.listCanceledTrips(); assertEquals("[TripOnServiceDate{F:123}, TripOnServiceDate{F:123}]", canceledTrips.toString()); } + + @Test + void findCanceledTrips() { + var canceledTripsForFeedWithCancellations = service.findCanceledTrips(List.of("F", "G")); + assertEquals( + "[TripOnServiceDate{F:123}, TripOnServiceDate{F:123}]", + canceledTripsForFeedWithCancellations.toString() + ); + + var canceledTripsForFeedWithoutCancellations = service.findCanceledTrips(List.of("G")); + assertEquals("[]", canceledTripsForFeedWithoutCancellations.toString()); + } + + @Test + void findCanceledTripsWithEmptyFeeds() { + assertThrows(IllegalArgumentException.class, () -> service.findCanceledTrips(List.of())); + } } From a2b30f865258b48e5fb66cde8fb5ff95a0211d06 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 1 Nov 2024 13:57:00 +0200 Subject: [PATCH 31/48] Improve schema doc --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2853164008c..1d970162390 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1146,7 +1146,9 @@ type QueryType { ids: [String] ): [BikeRentalStation] @deprecated(reason : "Use rentalVehicles or vehicleRentalStations instead") """ - Get pages of canceled Trips. Planned cancellations are not currently supported. Follows the + Get pages of canceled trips. Planned cancellations are not currently supported. Limiting the number of + returned trips with either `first` or `last` is highly recommended since the number of returned trips + can be really high when there is a strike affecting the transit services, for example. Follows the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). """ canceledTrips( From 6eaef7a9c345c80c6d5f422db6e1d01a96ed18b3 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 1 Nov 2024 14:02:26 +0200 Subject: [PATCH 32/48] Rename date -> serviceDate --- .../apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java | 2 +- .../apis/gtfs/generated/GraphQLDataFetchers.java | 4 ++-- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 2 +- .../apis/gtfs/expectations/canceled-trips.json | 2 +- .../opentripplanner/apis/gtfs/queries/canceled-trips.graphql | 3 +-- 5 files changed, 6 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java index f6923cdc394..c34c25e3f1d 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java @@ -20,7 +20,7 @@ public class FixedTripOnServiceDateImpl implements GraphQLDataFetchers.GraphQLFixedTripOnServiceDate { @Override - public DataFetcher date() { + public DataFetcher serviceDate() { return env -> getSource(env).getServiceDate(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 9dc3fa6662f..60e0b1e3fbc 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -435,10 +435,10 @@ public interface GraphQLFixedStopTimeOnServiceDate { /** A fixed (i.e. not flexible or frequency based) trip on a specific service date */ public interface GraphQLFixedTripOnServiceDate { - public DataFetcher date(); - public DataFetcher end(); + public DataFetcher serviceDate(); + public DataFetcher start(); public DataFetcher> stopTimes(); diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 1d970162390..4cfe9fa6fd0 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -572,7 +572,7 @@ type FixedTripOnServiceDate { correspond to a how a passenger thinks of a calendar date. For example, a night bus running on Sunday morning at 1am to 3am, might have the previous Saturday's service date. """ - date: LocalDate! + serviceDate: LocalDate! "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." end: FixedStopTimeOnServiceDate! "Information related to trip's scheduled departure from the first stop. Can contain realtime information." diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json index 5d60b684b76..b3facd3da1f 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json @@ -10,7 +10,7 @@ "edges": [ { "node": { - "date": "2024-08-09", + "serviceDate": "2024-08-09", "end": { "arrival": { "estimated": { diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index cb738d4c56b..a29950f7b0e 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -9,7 +9,7 @@ edges { node { ... on FixedTripOnServiceDate { - date + serviceDate end { arrival { estimated { @@ -47,7 +47,6 @@ } } } - date trip { gtfsId } From 396c43c83e7faaf6f709fcb518f73a913bdf18a5 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 1 Nov 2024 14:36:09 +0200 Subject: [PATCH 33/48] Rename ArrivalDepartureTime -> FixedArrivalDepartureTime and LegTime -> FixedArrivalDepartureTime --- .../impl/CombinedInterlinedTransitLeg.java | 6 ++-- .../ext/flex/FlexibleTransitLeg.java | 10 +++--- .../FixedStopTimeOnServiceDateImpl.java | 14 ++++---- .../apis/gtfs/datafetchers/LegImpl.java | 6 ++-- .../apis/gtfs/datafetchers/PlaceImpl.java | 6 ++-- .../gtfs/generated/GraphQLDataFetchers.java | 35 +++++++++---------- .../apis/gtfs/generated/graphql-codegen.yml | 4 +-- .../apis/gtfs/model/ArrivalDepartureTime.java | 29 --------------- ...me.java => FixedArrivalDepartureTime.java} | 21 +++++++---- .../model/plan/FrequencyTransitLeg.java | 8 +++-- .../org/opentripplanner/model/plan/Leg.java | 4 +-- .../model/plan/ScheduledTransitLeg.java | 12 +++---- .../model/plan/StopArrival.java | 8 ++--- .../model/plan/StopArrivalMapper.java | 8 ++--- .../opentripplanner/model/plan/StreetLeg.java | 8 ++--- .../model/plan/UnknownTransitPathLeg.java | 8 ++--- .../opentripplanner/apis/gtfs/schema.graphqls | 30 ++++++++-------- 17 files changed, 99 insertions(+), 118 deletions(-) delete mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java rename application/src/main/java/org/opentripplanner/model/plan/{LegTime.java => FixedArrivalDepartureTime.java} (61%) diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index d3608ccf8d9..5d27ea650ed 100644 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -10,7 +10,7 @@ import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -55,12 +55,12 @@ public Trip getTrip() { } @Override - public LegTime start() { + public FixedArrivalDepartureTime start() { return first.start(); } @Override - public LegTime end() { + public FixedArrivalDepartureTime end() { return second.end(); } diff --git a/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index cf6c229c46f..14988f4cdc2 100644 --- a/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -15,7 +15,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -87,13 +87,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTime start() { - return LegTime.ofStatic(startTime); + public FixedArrivalDepartureTime start() { + return FixedArrivalDepartureTime.ofStatic(startTime); } @Override - public LegTime end() { - return LegTime.ofStatic(endTime); + public FixedArrivalDepartureTime end() { + return FixedArrivalDepartureTime.ofStatic(endTime); } @Override diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java index f6e8c62b223..a7551e487f5 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java @@ -7,16 +7,16 @@ import java.time.ZonedDateTime; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.transit.service.TransitService; public class FixedStopTimeOnServiceDateImpl implements GraphQLDataFetchers.GraphQLFixedStopTimeOnServiceDate { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledArrival()); @@ -24,13 +24,13 @@ public DataFetcher arrival() { return null; } return tripTime.isRealtime() - ? ArrivalDepartureTime.of(scheduledTime, tripTime.getArrivalDelay()) - : ArrivalDepartureTime.ofStatic(scheduledTime); + ? FixedArrivalDepartureTime.of(scheduledTime, tripTime.getArrivalDelay()) + : FixedArrivalDepartureTime.ofStatic(scheduledTime); }; } @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledDeparture()); @@ -38,8 +38,8 @@ public DataFetcher departure() { return null; } return tripTime.isRealtime() - ? ArrivalDepartureTime.of(scheduledTime, tripTime.getDepartureDelay()) - : ArrivalDepartureTime.ofStatic(scheduledTime); + ? FixedArrivalDepartureTime.of(scheduledTime, tripTime.getDepartureDelay()) + : FixedArrivalDepartureTime.ofStatic(scheduledTime); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 4db347ee784..59fc154a7c4 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -17,8 +17,8 @@ import org.opentripplanner.ext.ridehailing.model.RideHailingLeg; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.fare.FareProductUse; +import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -81,7 +81,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -227,7 +227,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 145321f809c..5c8cc44147a 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -7,7 +7,7 @@ import org.opentripplanner.apis.gtfs.model.StopPosition; import org.opentripplanner.apis.gtfs.model.StopPosition.PositionAtStop; import org.opentripplanner.framework.graphql.GraphQLUtils; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.VertexType; @@ -19,7 +19,7 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> getSource(environment).arrival; } @@ -58,7 +58,7 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> getSource(environment).departure; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 60e0b1e3fbc..7053e185d70 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -23,7 +23,6 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRelativeDirection; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRoutingErrorCode; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; -import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; import org.opentripplanner.apis.gtfs.model.FeedPublisher; import org.opentripplanner.apis.gtfs.model.PlanPageInfo; import org.opentripplanner.apis.gtfs.model.RideHailingProvider; @@ -40,9 +39,9 @@ import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.fare.RiderCategory; import org.opentripplanner.model.plan.Emissions; +import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -143,16 +142,6 @@ public interface GraphQLAlert { /** Entity related to an alert */ public interface GraphQLAlertEntity extends TypeResolver {} - /** - * Timing of an arrival or a departure to or from a stop. May contain real-time information if - * available. - */ - public interface GraphQLArrivalDepartureTime { - public DataFetcher estimated(); - - public DataFetcher scheduledTime(); - } - /** Bike park represents a location where bicycles can be parked. */ public interface GraphQLBikePark { public DataFetcher bikeParkId(); @@ -421,14 +410,24 @@ public interface GraphQLFeedPublisher { public DataFetcher url(); } + /** + * Timing of an arrival or a departure to or from a stop. May contain real-time information if + * available. This is used when there is a known scheduled time. + */ + public interface GraphQLFixedArrivalDepartureTime { + public DataFetcher estimated(); + + public DataFetcher scheduledTime(); + } + /** * Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. * This can include realtime estimates. */ public interface GraphQLFixedStopTimeOnServiceDate { - public DataFetcher arrival(); + public DataFetcher arrival(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher stop(); } @@ -509,7 +508,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -553,7 +552,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -661,7 +660,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -671,7 +670,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 66b701c5e01..5b02cd86f89 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -63,7 +63,7 @@ config: FixedTripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate TripOnServiceDateConnection: graphql.relay.Connection#Connection TripOnServiceDateEdge: graphql.relay.Edge#Edge - ArrivalDepartureTime: org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime#ArrivalDepartureTime + FixedArrivalDepartureTime: org.opentripplanner.model.plan.FixedArrivalDepartureTime#FixedArrivalDepartureTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step @@ -74,7 +74,7 @@ config: InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField Itinerary: org.opentripplanner.model.plan.Itinerary#Itinerary Leg: org.opentripplanner.model.plan.Leg#Leg - LegTime: org.opentripplanner.model.plan.LegTime#LegTime + LegTime: org.opentripplanner.model.plan.FixedArrivalDepartureTime#FixedArrivalDepartureTime Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java b/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java deleted file mode 100644 index 3a801537dd1..00000000000 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.opentripplanner.apis.gtfs.model; - -import java.time.Duration; -import java.time.ZonedDateTime; -import javax.annotation.Nullable; - -/** - * Timing of an arrival or a departure to or from a stop. May contain real-time information - * if available. - */ -public record ArrivalDepartureTime( - ZonedDateTime scheduledTime, - @Nullable RealTimeEstimate estimated -) { - public static ArrivalDepartureTime of(ZonedDateTime realtime, int delaySecs) { - var delay = Duration.ofSeconds(delaySecs); - return new ArrivalDepartureTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); - } - - public static ArrivalDepartureTime ofStatic(ZonedDateTime staticTime) { - return new ArrivalDepartureTime(staticTime, null); - } - - /** - * Realtime information about a vehicle at a certain place. - * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. - */ - record RealTimeEstimate(ZonedDateTime time, Duration delay) {} -} diff --git a/application/src/main/java/org/opentripplanner/model/plan/LegTime.java b/application/src/main/java/org/opentripplanner/model/plan/FixedArrivalDepartureTime.java similarity index 61% rename from application/src/main/java/org/opentripplanner/model/plan/LegTime.java rename to application/src/main/java/org/opentripplanner/model/plan/FixedArrivalDepartureTime.java index 71ced95942a..f27644b59a6 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/application/src/main/java/org/opentripplanner/model/plan/FixedArrivalDepartureTime.java @@ -6,20 +6,27 @@ import javax.annotation.Nullable; /** - * A scheduled time of a transit vehicle at a certain location with a optional realtime information. + * A scheduled time of a transit vehicle at a certain location with an optional realtime + * information. */ -public record LegTime(ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated) { - public LegTime { +public record FixedArrivalDepartureTime( + ZonedDateTime scheduledTime, + @Nullable RealTimeEstimate estimated +) { + public FixedArrivalDepartureTime { Objects.requireNonNull(scheduledTime); } - public static LegTime of(ZonedDateTime realtime, int delaySecs) { + public static FixedArrivalDepartureTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); + return new FixedArrivalDepartureTime( + realtime.minus(delay), + new RealTimeEstimate(realtime, delay) + ); } - public static LegTime ofStatic(ZonedDateTime staticTime) { - return new LegTime(staticTime, null); + public static FixedArrivalDepartureTime ofStatic(ZonedDateTime staticTime) { + return new FixedArrivalDepartureTime(staticTime, null); } /** diff --git a/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index 48c4b1b7b87..19a2ce2c491 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -55,8 +55,12 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - LegTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), - LegTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), + FixedArrivalDepartureTime.ofStatic( + ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime) + ), + FixedArrivalDepartureTime.ofStatic( + ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime) + ), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/application/src/main/java/org/opentripplanner/model/plan/Leg.java b/application/src/main/java/org/opentripplanner/model/plan/Leg.java index 2a4483d7cd2..718b3ba5360 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -209,12 +209,12 @@ default Accessibility getTripWheelchairAccessibility() { /** * The time (including realtime information) when the leg starts. */ - LegTime start(); + FixedArrivalDepartureTime start(); /** * The time (including realtime information) when the leg ends. */ - LegTime end(); + FixedArrivalDepartureTime end(); /** * The date and time this leg begins. diff --git a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 068d6675eec..784232a5060 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -161,20 +161,20 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTime start() { + public FixedArrivalDepartureTime start() { if (isRealTimeUpdated()) { - return LegTime.of(startTime, getDepartureDelay()); + return FixedArrivalDepartureTime.of(startTime, getDepartureDelay()); } else { - return LegTime.ofStatic(startTime); + return FixedArrivalDepartureTime.ofStatic(startTime); } } @Override - public LegTime end() { + public FixedArrivalDepartureTime end() { if (isRealTimeUpdated()) { - return LegTime.of(endTime, getArrivalDelay()); + return FixedArrivalDepartureTime.of(endTime, getArrivalDelay()); } else { - return LegTime.ofStatic(endTime); + return FixedArrivalDepartureTime.ofStatic(endTime); } } diff --git a/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 489b122da09..bd0bc52cd6e 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -9,8 +9,8 @@ public final class StopArrival { public final Place place; - public final LegTime arrival; - public final LegTime departure; + public final FixedArrivalDepartureTime arrival; + public final FixedArrivalDepartureTime departure; public final Integer stopPosInPattern; public final Integer gtfsStopSequence; @@ -24,8 +24,8 @@ public final class StopArrival { */ public StopArrival( Place place, - LegTime arrival, - LegTime departure, + FixedArrivalDepartureTime arrival, + FixedArrivalDepartureTime departure, Integer stopPosInPattern, Integer gtfsStopSequence ) { diff --git a/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java index 25bab2a7c3f..23d75df357c 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -34,12 +34,12 @@ StopArrival map(int i, StopLocation stop, boolean realTime) { tripTimes.getDepartureTime(i) ); - var arrival = LegTime.ofStatic(arrivalTime); - var departure = LegTime.ofStatic(departureTime); + var arrival = FixedArrivalDepartureTime.ofStatic(arrivalTime); + var departure = FixedArrivalDepartureTime.ofStatic(departureTime); if (realTime) { - arrival = LegTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = LegTime.of(departureTime, tripTimes.getDepartureDelay(i)); + arrival = FixedArrivalDepartureTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = FixedArrivalDepartureTime.of(departureTime, tripTimes.getDepartureDelay(i)); } return new StopArrival( diff --git a/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 6384159a4ec..15dfda93079 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTime start() { - return LegTime.ofStatic(startTime); + public FixedArrivalDepartureTime start() { + return FixedArrivalDepartureTime.ofStatic(startTime); } @Override - public LegTime end() { - return LegTime.ofStatic(endTime); + public FixedArrivalDepartureTime end() { + return FixedArrivalDepartureTime.ofStatic(endTime); } @Override diff --git a/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index 76179a8ee7c..c6ec7f8c45b 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -70,13 +70,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTime start() { - return LegTime.ofStatic(startTime); + public FixedArrivalDepartureTime start() { + return FixedArrivalDepartureTime.ofStatic(startTime); } @Override - public LegTime end() { - return LegTime.ofStatic(endTime); + public FixedArrivalDepartureTime end() { + return FixedArrivalDepartureTime.ofStatic(endTime); } @Override diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 4cfe9fa6fd0..da7bec99199 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -157,17 +157,6 @@ type Alert implements Node { trip: Trip @deprecated(reason : "Alert can have multiple affected entities now instead of there being duplicate alerts\nfor different entities. This will return only one of the affected trips.\nUse entities instead.") } -""" -Timing of an arrival or a departure to or from a stop. May contain real-time information if -available. -""" -type ArrivalDepartureTime { - "The estimated time of the event. If no real-time information is available, this is null." - estimated: RealTimeEstimate - "The scheduled time of the event." - scheduledTime: OffsetDateTime! -} - "Bike park represents a location where bicycles can be parked." type BikePark implements Node & PlaceInterface { "ID of the bike park" @@ -550,21 +539,34 @@ type FeedPublisher { url: String! } +""" +Timing of an arrival or a departure to or from a stop. May contain real-time information if +available. This is used when there is a known scheduled time. +""" +type FixedArrivalDepartureTime { + "The estimated time of the event. If no real-time information is available, this is null." + estimated: RealTimeEstimate + "The scheduled time of the event." + scheduledTime: OffsetDateTime! +} + """ Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. This can include realtime estimates. """ type FixedStopTimeOnServiceDate { "Scheduled arrival time to the stop and a realtime estimate, if one exists." - arrival: ArrivalDepartureTime + arrival: FixedArrivalDepartureTime "Scheduled departure time from the stop and a realtime estimate, if one exists." - departure: ArrivalDepartureTime + departure: FixedArrivalDepartureTime "The stop where this arrival/departure happens" stop: Stop } "A fixed (i.e. not flexible or frequency based) trip on a specific service date" type FixedTripOnServiceDate { + "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." + end: FixedStopTimeOnServiceDate! """ The service date when the trip occurs. @@ -573,8 +575,6 @@ type FixedTripOnServiceDate { on Sunday morning at 1am to 3am, might have the previous Saturday's service date. """ serviceDate: LocalDate! - "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." - end: FixedStopTimeOnServiceDate! "Information related to trip's scheduled departure from the first stop. Can contain realtime information." start: FixedStopTimeOnServiceDate! "List of times when this trip arrives to or departs from a stop and information related to the stop" From 672a96830d0614f198334460bc52f58e29ee902c Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Wed, 13 Nov 2024 15:17:02 +0200 Subject: [PATCH 34/48] Make TripOnServiceDate an interface and rename some types --- .../impl/CombinedInterlinedTransitLeg.java | 6 +- .../ext/flex/FlexibleTransitLeg.java | 10 +- .../apis/gtfs/GtfsGraphQLIndex.java | 8 +- .../apis/gtfs/datafetchers/LegImpl.java | 6 +- .../apis/gtfs/datafetchers/PlaceImpl.java | 6 +- ....java => RegularRealTimeStopTimeImpl.java} | 18 +-- ...java => RegularTripOnServiceDateImpl.java} | 4 +- .../TripOnServiceDateTypeResolver.java | 2 +- .../gtfs/generated/GraphQLDataFetchers.java | 86 ++++++++------- .../apis/gtfs/generated/graphql-codegen.yml | 8 +- .../model/plan/FrequencyTransitLeg.java | 4 +- .../org/opentripplanner/model/plan/Leg.java | 4 +- ....java => RegularArrivalDepartureTime.java} | 12 +- .../model/plan/ScheduledTransitLeg.java | 12 +- .../model/plan/StopArrival.java | 8 +- .../model/plan/StopArrivalMapper.java | 8 +- .../opentripplanner/model/plan/StreetLeg.java | 8 +- .../model/plan/UnknownTransitPathLeg.java | 8 +- .../opentripplanner/apis/gtfs/schema.graphqls | 103 ++++++++++-------- .../apis/gtfs/queries/canceled-trips.graphql | 2 +- 20 files changed, 168 insertions(+), 155 deletions(-) rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{FixedStopTimeOnServiceDateImpl.java => RegularRealTimeStopTimeImpl.java} (76%) rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{FixedTripOnServiceDateImpl.java => RegularTripOnServiceDateImpl.java} (97%) rename application/src/main/java/org/opentripplanner/model/plan/{FixedArrivalDepartureTime.java => RegularArrivalDepartureTime.java} (74%) diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 5d27ea650ed..a53c3a689c2 100644 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -10,7 +10,7 @@ import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.FixedArrivalDepartureTime; +import org.opentripplanner.model.plan.RegularArrivalDepartureTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -55,12 +55,12 @@ public Trip getTrip() { } @Override - public FixedArrivalDepartureTime start() { + public RegularArrivalDepartureTime start() { return first.start(); } @Override - public FixedArrivalDepartureTime end() { + public RegularArrivalDepartureTime end() { return second.end(); } diff --git a/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index 14988f4cdc2..9c59da7d39f 100644 --- a/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -15,7 +15,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.FixedArrivalDepartureTime; +import org.opentripplanner.model.plan.RegularArrivalDepartureTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -87,13 +87,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public FixedArrivalDepartureTime start() { - return FixedArrivalDepartureTime.ofStatic(startTime); + public RegularArrivalDepartureTime start() { + return RegularArrivalDepartureTime.ofStatic(startTime); } @Override - public FixedArrivalDepartureTime end() { - return FixedArrivalDepartureTime.ofStatic(endTime); + public RegularArrivalDepartureTime end() { + return RegularArrivalDepartureTime.ofStatic(endTime); } @Override diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 9aeed1e9472..014acb97398 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -40,8 +40,6 @@ import org.opentripplanner.apis.gtfs.datafetchers.FareProductTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.FareProductUseImpl; import org.opentripplanner.apis.gtfs.datafetchers.FeedImpl; -import org.opentripplanner.apis.gtfs.datafetchers.FixedStopTimeOnServiceDateImpl; -import org.opentripplanner.apis.gtfs.datafetchers.FixedTripOnServiceDateImpl; import org.opentripplanner.apis.gtfs.datafetchers.GeometryImpl; import org.opentripplanner.apis.gtfs.datafetchers.ItineraryImpl; import org.opentripplanner.apis.gtfs.datafetchers.LegImpl; @@ -54,6 +52,8 @@ import org.opentripplanner.apis.gtfs.datafetchers.PlanConnectionImpl; import org.opentripplanner.apis.gtfs.datafetchers.PlanImpl; import org.opentripplanner.apis.gtfs.datafetchers.QueryTypeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.RegularRealTimeStopTimeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.RegularTripOnServiceDateImpl; import org.opentripplanner.apis.gtfs.datafetchers.RentalVehicleImpl; import org.opentripplanner.apis.gtfs.datafetchers.RentalVehicleTypeImpl; import org.opentripplanner.apis.gtfs.datafetchers.RideHailingEstimateImpl; @@ -182,8 +182,8 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(CurrencyImpl.class)) .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) - .type(typeWiring.build(FixedTripOnServiceDateImpl.class)) - .type(typeWiring.build(FixedStopTimeOnServiceDateImpl.class)) + .type(typeWiring.build(RegularTripOnServiceDateImpl.class)) + .type(typeWiring.build(RegularRealTimeStopTimeImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index 59fc154a7c4..c90339f1016 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -17,8 +17,8 @@ import org.opentripplanner.ext.ridehailing.model.RideHailingLeg; import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.fare.FareProductUse; -import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Leg; +import org.opentripplanner.model.plan.RegularArrivalDepartureTime; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -81,7 +81,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -227,7 +227,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 5c8cc44147a..b732bb14887 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -7,8 +7,8 @@ import org.opentripplanner.apis.gtfs.model.StopPosition; import org.opentripplanner.apis.gtfs.model.StopPosition.PositionAtStop; import org.opentripplanner.framework.graphql.GraphQLUtils; -import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Place; +import org.opentripplanner.model.plan.RegularArrivalDepartureTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.VertexType; import org.opentripplanner.routing.vehicle_parking.VehicleParking; @@ -19,7 +19,7 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> getSource(environment).arrival; } @@ -58,7 +58,7 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> getSource(environment).departure; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java similarity index 76% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java index a7551e487f5..2f524bdea34 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedStopTimeOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java @@ -9,14 +9,14 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.model.plan.FixedArrivalDepartureTime; +import org.opentripplanner.model.plan.RegularArrivalDepartureTime; import org.opentripplanner.transit.service.TransitService; -public class FixedStopTimeOnServiceDateImpl - implements GraphQLDataFetchers.GraphQLFixedStopTimeOnServiceDate { +public class RegularRealTimeStopTimeImpl + implements GraphQLDataFetchers.GraphQLRegularRealTimeStopTime { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledArrival()); @@ -24,13 +24,13 @@ public DataFetcher arrival() { return null; } return tripTime.isRealtime() - ? FixedArrivalDepartureTime.of(scheduledTime, tripTime.getArrivalDelay()) - : FixedArrivalDepartureTime.ofStatic(scheduledTime); + ? RegularArrivalDepartureTime.of(scheduledTime, tripTime.getArrivalDelay()) + : RegularArrivalDepartureTime.ofStatic(scheduledTime); }; } @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledDeparture()); @@ -38,8 +38,8 @@ public DataFetcher departure() { return null; } return tripTime.isRealtime() - ? FixedArrivalDepartureTime.of(scheduledTime, tripTime.getDepartureDelay()) - : FixedArrivalDepartureTime.ofStatic(scheduledTime); + ? RegularArrivalDepartureTime.of(scheduledTime, tripTime.getDepartureDelay()) + : RegularArrivalDepartureTime.ofStatic(scheduledTime); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularTripOnServiceDateImpl.java similarity index 97% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularTripOnServiceDateImpl.java index c34c25e3f1d..54cda759fd4 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/FixedTripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularTripOnServiceDateImpl.java @@ -16,8 +16,8 @@ import org.opentripplanner.transit.model.timetable.TripOnServiceDate; import org.opentripplanner.transit.service.TransitService; -public class FixedTripOnServiceDateImpl - implements GraphQLDataFetchers.GraphQLFixedTripOnServiceDate { +public class RegularTripOnServiceDateImpl + implements GraphQLDataFetchers.GraphQLRegularTripOnServiceDate { @Override public DataFetcher serviceDate() { diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java index aaf8d6dae14..570177768f0 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java @@ -14,7 +14,7 @@ public GraphQLObjectType getType(TypeResolutionEnvironment environment) { GraphQLSchema schema = environment.getSchema(); if (o instanceof TripOnServiceDate) { - return schema.getObjectType("FixedTripOnServiceDate"); + return schema.getObjectType("RegularTripOnServiceDate"); } return null; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 7053e185d70..f89a94f7a31 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -39,9 +39,9 @@ import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.fare.RiderCategory; import org.opentripplanner.model.plan.Emissions; -import org.opentripplanner.model.plan.FixedArrivalDepartureTime; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; +import org.opentripplanner.model.plan.RegularArrivalDepartureTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -410,41 +410,6 @@ public interface GraphQLFeedPublisher { public DataFetcher url(); } - /** - * Timing of an arrival or a departure to or from a stop. May contain real-time information if - * available. This is used when there is a known scheduled time. - */ - public interface GraphQLFixedArrivalDepartureTime { - public DataFetcher estimated(); - - public DataFetcher scheduledTime(); - } - - /** - * Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. - * This can include realtime estimates. - */ - public interface GraphQLFixedStopTimeOnServiceDate { - public DataFetcher arrival(); - - public DataFetcher departure(); - - public DataFetcher stop(); - } - - /** A fixed (i.e. not flexible or frequency based) trip on a specific service date */ - public interface GraphQLFixedTripOnServiceDate { - public DataFetcher end(); - - public DataFetcher serviceDate(); - - public DataFetcher start(); - - public DataFetcher> stopTimes(); - - public DataFetcher trip(); - } - public interface GraphQLGeometry { public DataFetcher length(); @@ -508,7 +473,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -552,7 +517,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -660,7 +625,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -670,7 +635,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); @@ -881,6 +846,41 @@ public interface GraphQLRealTimeEstimate { public DataFetcher time(); } + /** + * Timing of an arrival or a departure to or from a stop. May contain real-time information if + * available. This is used when there is a known scheduled time. + */ + public interface GraphQLRegularRealTimeArrivalDepartureTime { + public DataFetcher estimated(); + + public DataFetcher scheduledTime(); + } + + /** + * Regular real-time stop time represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. + * This can include real-time estimates. + */ + public interface GraphQLRegularRealTimeStopTime { + public DataFetcher arrival(); + + public DataFetcher departure(); + + public DataFetcher stop(); + } + + /** A regular (i.e. not flexible) trip on a specific service date */ + public interface GraphQLRegularTripOnServiceDate { + public DataFetcher end(); + + public DataFetcher serviceDate(); + + public DataFetcher start(); + + public DataFetcher> stopTimes(); + + public DataFetcher trip(); + } + /** Rental vehicle represents a vehicle that belongs to a rental network. */ public interface GraphQLRentalVehicle { public DataFetcher allowPickupNow(); @@ -1240,7 +1240,11 @@ public interface GraphQLTripOccupancy { } /** An instance of a trip on a service date. */ - public interface GraphQLTripOnServiceDate extends TypeResolver {} + public interface GraphQLTripOnServiceDate extends TypeResolver { + public default DataFetcher serviceDate() { + return null; + } + } /** * A connection to a list of trips on service dates that follows diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 5b02cd86f89..1df05e0fb5a 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -59,11 +59,11 @@ config: ContactInfo: org.opentripplanner.transit.model.organization.ContactInfo Cluster: Object Coordinates: org.locationtech.jts.geom.Coordinate#Coordinate - FixedStopTimeOnServiceDate: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate - FixedTripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate + RegularRealTimeStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate + RegularTripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate TripOnServiceDateConnection: graphql.relay.Connection#Connection TripOnServiceDateEdge: graphql.relay.Edge#Edge - FixedArrivalDepartureTime: org.opentripplanner.model.plan.FixedArrivalDepartureTime#FixedArrivalDepartureTime + RegularRealTimeArrivalDepartureTime: org.opentripplanner.model.plan.RegularArrivalDepartureTime#RegularArrivalDepartureTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step @@ -74,7 +74,7 @@ config: InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField Itinerary: org.opentripplanner.model.plan.Itinerary#Itinerary Leg: org.opentripplanner.model.plan.Leg#Leg - LegTime: org.opentripplanner.model.plan.FixedArrivalDepartureTime#FixedArrivalDepartureTime + LegTime: org.opentripplanner.model.plan.RegularArrivalDepartureTime#RegularArrivalDepartureTime Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index 19a2ce2c491..042cb3ccb87 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -55,10 +55,10 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - FixedArrivalDepartureTime.ofStatic( + RegularArrivalDepartureTime.ofStatic( ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime) ), - FixedArrivalDepartureTime.ofStatic( + RegularArrivalDepartureTime.ofStatic( ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime) ), i, diff --git a/application/src/main/java/org/opentripplanner/model/plan/Leg.java b/application/src/main/java/org/opentripplanner/model/plan/Leg.java index 718b3ba5360..18b4c04fc1f 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -209,12 +209,12 @@ default Accessibility getTripWheelchairAccessibility() { /** * The time (including realtime information) when the leg starts. */ - FixedArrivalDepartureTime start(); + RegularArrivalDepartureTime start(); /** * The time (including realtime information) when the leg ends. */ - FixedArrivalDepartureTime end(); + RegularArrivalDepartureTime end(); /** * The date and time this leg begins. diff --git a/application/src/main/java/org/opentripplanner/model/plan/FixedArrivalDepartureTime.java b/application/src/main/java/org/opentripplanner/model/plan/RegularArrivalDepartureTime.java similarity index 74% rename from application/src/main/java/org/opentripplanner/model/plan/FixedArrivalDepartureTime.java rename to application/src/main/java/org/opentripplanner/model/plan/RegularArrivalDepartureTime.java index f27644b59a6..370e91934e1 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/FixedArrivalDepartureTime.java +++ b/application/src/main/java/org/opentripplanner/model/plan/RegularArrivalDepartureTime.java @@ -9,24 +9,24 @@ * A scheduled time of a transit vehicle at a certain location with an optional realtime * information. */ -public record FixedArrivalDepartureTime( +public record RegularArrivalDepartureTime( ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated ) { - public FixedArrivalDepartureTime { + public RegularArrivalDepartureTime { Objects.requireNonNull(scheduledTime); } - public static FixedArrivalDepartureTime of(ZonedDateTime realtime, int delaySecs) { + public static RegularArrivalDepartureTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new FixedArrivalDepartureTime( + return new RegularArrivalDepartureTime( realtime.minus(delay), new RealTimeEstimate(realtime, delay) ); } - public static FixedArrivalDepartureTime ofStatic(ZonedDateTime staticTime) { - return new FixedArrivalDepartureTime(staticTime, null); + public static RegularArrivalDepartureTime ofStatic(ZonedDateTime staticTime) { + return new RegularArrivalDepartureTime(staticTime, null); } /** diff --git a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 784232a5060..07c69765af7 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -161,20 +161,20 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public FixedArrivalDepartureTime start() { + public RegularArrivalDepartureTime start() { if (isRealTimeUpdated()) { - return FixedArrivalDepartureTime.of(startTime, getDepartureDelay()); + return RegularArrivalDepartureTime.of(startTime, getDepartureDelay()); } else { - return FixedArrivalDepartureTime.ofStatic(startTime); + return RegularArrivalDepartureTime.ofStatic(startTime); } } @Override - public FixedArrivalDepartureTime end() { + public RegularArrivalDepartureTime end() { if (isRealTimeUpdated()) { - return FixedArrivalDepartureTime.of(endTime, getArrivalDelay()); + return RegularArrivalDepartureTime.of(endTime, getArrivalDelay()); } else { - return FixedArrivalDepartureTime.ofStatic(endTime); + return RegularArrivalDepartureTime.ofStatic(endTime); } } diff --git a/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java index bd0bc52cd6e..d4914b0691b 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -9,8 +9,8 @@ public final class StopArrival { public final Place place; - public final FixedArrivalDepartureTime arrival; - public final FixedArrivalDepartureTime departure; + public final RegularArrivalDepartureTime arrival; + public final RegularArrivalDepartureTime departure; public final Integer stopPosInPattern; public final Integer gtfsStopSequence; @@ -24,8 +24,8 @@ public final class StopArrival { */ public StopArrival( Place place, - FixedArrivalDepartureTime arrival, - FixedArrivalDepartureTime departure, + RegularArrivalDepartureTime arrival, + RegularArrivalDepartureTime departure, Integer stopPosInPattern, Integer gtfsStopSequence ) { diff --git a/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java index 23d75df357c..5377ee809b3 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -34,12 +34,12 @@ StopArrival map(int i, StopLocation stop, boolean realTime) { tripTimes.getDepartureTime(i) ); - var arrival = FixedArrivalDepartureTime.ofStatic(arrivalTime); - var departure = FixedArrivalDepartureTime.ofStatic(departureTime); + var arrival = RegularArrivalDepartureTime.ofStatic(arrivalTime); + var departure = RegularArrivalDepartureTime.ofStatic(departureTime); if (realTime) { - arrival = FixedArrivalDepartureTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = FixedArrivalDepartureTime.of(departureTime, tripTimes.getDepartureDelay(i)); + arrival = RegularArrivalDepartureTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = RegularArrivalDepartureTime.of(departureTime, tripTimes.getDepartureDelay(i)); } return new StopArrival( diff --git a/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 15dfda93079..62e03ee0acb 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public FixedArrivalDepartureTime start() { - return FixedArrivalDepartureTime.ofStatic(startTime); + public RegularArrivalDepartureTime start() { + return RegularArrivalDepartureTime.ofStatic(startTime); } @Override - public FixedArrivalDepartureTime end() { - return FixedArrivalDepartureTime.ofStatic(endTime); + public RegularArrivalDepartureTime end() { + return RegularArrivalDepartureTime.ofStatic(endTime); } @Override diff --git a/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index c6ec7f8c45b..358cfd9fe05 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -70,13 +70,13 @@ public boolean hasSameMode(Leg other) { } @Override - public FixedArrivalDepartureTime start() { - return FixedArrivalDepartureTime.ofStatic(startTime); + public RegularArrivalDepartureTime start() { + return RegularArrivalDepartureTime.ofStatic(startTime); } @Override - public FixedArrivalDepartureTime end() { - return FixedArrivalDepartureTime.ofStatic(endTime); + public RegularArrivalDepartureTime end() { + return RegularArrivalDepartureTime.ofStatic(endTime); } @Override diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 0496bd4448c..8cbf5fb91fa 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -70,14 +70,23 @@ interface PlaceInterface { lon: Float } +"An instance of a trip on a service date." +interface TripOnServiceDate { + """ + The service date when the trip occurs. + + **Note**: A service date is a technical term useful for transit planning purposes and might not + correspond to a how a passenger thinks of a calendar date. For example, a night bus running + on Sunday morning at 1am to 3am, might have the previous Saturday's service date. + """ + serviceDate: LocalDate! +} + "Entity related to an alert" union AlertEntity = Agency | Pattern | Route | RouteType | Stop | StopOnRoute | StopOnTrip | Trip | Unknown union StopPosition = PositionAtStop | PositionBetweenStops -"An instance of a trip on a service date." -union TripOnServiceDate = FixedTripOnServiceDate - "A public transport agency" type Agency implements Node { """ @@ -539,50 +548,6 @@ type FeedPublisher { url: String! } -""" -Timing of an arrival or a departure to or from a stop. May contain real-time information if -available. This is used when there is a known scheduled time. -""" -type FixedArrivalDepartureTime { - "The estimated time of the event. If no real-time information is available, this is null." - estimated: RealTimeEstimate - "The scheduled time of the event." - scheduledTime: OffsetDateTime! -} - -""" -Exact dated stoptime represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. -This can include realtime estimates. -""" -type FixedStopTimeOnServiceDate { - "Scheduled arrival time to the stop and a realtime estimate, if one exists." - arrival: FixedArrivalDepartureTime - "Scheduled departure time from the stop and a realtime estimate, if one exists." - departure: FixedArrivalDepartureTime - "The stop where this arrival/departure happens" - stop: Stop -} - -"A fixed (i.e. not flexible or frequency based) trip on a specific service date" -type FixedTripOnServiceDate { - "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." - end: FixedStopTimeOnServiceDate! - """ - The service date when the trip occurs. - - **Note**: A service date is a technical term useful for transit planning purposes and might not - correspond to a how a passenger thinks of a calendar date. For example, a night bus running - on Sunday morning at 1am to 3am, might have the previous Saturday's service date. - """ - serviceDate: LocalDate! - "Information related to trip's scheduled departure from the first stop. Can contain realtime information." - start: FixedStopTimeOnServiceDate! - "List of times when this trip arrives to or departs from a stop and information related to the stop" - stopTimes: [FixedStopTimeOnServiceDate!]! - "This trip on service date is an instance of this trip." - trip: Trip -} - type Geometry { "The number of points in the string" length: Int @@ -1824,6 +1789,50 @@ type RealTimeEstimate { time: OffsetDateTime! } +""" +Timing of an arrival or a departure to or from a stop. May contain real-time information if +available. This is used when there is a known scheduled time. +""" +type RegularRealTimeArrivalDepartureTime { + "The estimated time of the event. If no real-time information is available, this is null." + estimated: RealTimeEstimate + "The scheduled time of the event." + scheduledTime: OffsetDateTime! +} + +""" +Regular real-time stop time represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. +This can include real-time estimates. +""" +type RegularRealTimeStopTime { + "Scheduled arrival time to the stop and a real-time estimate, if one exists." + arrival: RegularRealTimeArrivalDepartureTime + "Scheduled departure time from the stop and a real-time estimate, if one exists." + departure: RegularRealTimeArrivalDepartureTime + "The stop where this arrival/departure happens" + stop: Stop +} + +"A regular (i.e. not flexible) trip on a specific service date" +type RegularTripOnServiceDate implements TripOnServiceDate { + "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." + end: RegularRealTimeStopTime! + """ + The service date when the trip occurs. + + **Note**: A service date is a technical term useful for transit planning purposes and might not + correspond to a how a passenger thinks of a calendar date. For example, a night bus running + on Sunday morning at 1am to 3am, might have the previous Saturday's service date. + """ + serviceDate: LocalDate! + "Information related to trip's scheduled departure from the first stop. Can contain realtime information." + start: RegularRealTimeStopTime! + "List of times when this trip arrives to or departs from a stop and information related to the stop" + stopTimes: [RegularRealTimeStopTime!]! + "This trip on service date is an instance of this trip." + trip: Trip +} + "Rental vehicle represents a vehicle that belongs to a rental network." type RentalVehicle implements Node & PlaceInterface { "If true, vehicle is currently available for renting." diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index a29950f7b0e..9629c4ae418 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -8,7 +8,7 @@ } edges { node { - ... on FixedTripOnServiceDate { + ... on RegularTripOnServiceDate { serviceDate end { arrival { From 8885c193c6778ead7ad75728e2bae5c5859e27db Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Sun, 17 Nov 2024 23:46:45 +0200 Subject: [PATCH 35/48] Rename RegularArrivalDepartureTime -> LegCallTime --- .../impl/CombinedInterlinedTransitLeg.java | 6 +++--- .../ext/flex/FlexibleTransitLeg.java | 10 +++++----- .../apis/gtfs/datafetchers/LegImpl.java | 6 +++--- .../apis/gtfs/datafetchers/PlaceImpl.java | 6 +++--- .../RegularRealTimeStopTimeImpl.java | 14 ++++++------- .../gtfs/generated/GraphQLDataFetchers.java | 14 ++++++------- .../apis/gtfs/generated/graphql-codegen.yml | 4 ++-- .../model/plan/FrequencyTransitLeg.java | 8 ++------ .../org/opentripplanner/model/plan/Leg.java | 4 ++-- ...valDepartureTime.java => LegCallTime.java} | 20 +++++++------------ .../model/plan/ScheduledTransitLeg.java | 12 +++++------ .../model/plan/StopArrival.java | 8 ++++---- .../model/plan/StopArrivalMapper.java | 8 ++++---- .../opentripplanner/model/plan/StreetLeg.java | 8 ++++---- .../model/plan/UnknownTransitPathLeg.java | 8 ++++---- 15 files changed, 63 insertions(+), 73 deletions(-) rename application/src/main/java/org/opentripplanner/model/plan/{RegularArrivalDepartureTime.java => LegCallTime.java} (62%) diff --git a/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index f41126a6a60..60d03e484df 100644 --- a/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/application/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -9,7 +9,7 @@ import org.locationtech.jts.geom.LineString; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.RegularArrivalDepartureTime; +import org.opentripplanner.model.plan.LegCallTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -55,12 +55,12 @@ public Trip getTrip() { } @Override - public RegularArrivalDepartureTime start() { + public LegCallTime start() { return first.start(); } @Override - public RegularArrivalDepartureTime end() { + public LegCallTime end() { return second.end(); } diff --git a/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index 39a9d0375d6..769407aa05a 100644 --- a/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/application/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -13,7 +13,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.RegularArrivalDepartureTime; +import org.opentripplanner.model.plan.LegCallTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -87,13 +87,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public RegularArrivalDepartureTime start() { - return RegularArrivalDepartureTime.ofStatic(startTime); + public LegCallTime start() { + return LegCallTime.ofStatic(startTime); } @Override - public RegularArrivalDepartureTime end() { - return RegularArrivalDepartureTime.ofStatic(endTime); + public LegCallTime end() { + return LegCallTime.ofStatic(endTime); } @Override diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java index c90339f1016..fdd2609e17a 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -18,7 +18,7 @@ import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.RegularArrivalDepartureTime; +import org.opentripplanner.model.plan.LegCallTime; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -81,7 +81,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -227,7 +227,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index b732bb14887..e1924101b1b 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -7,8 +7,8 @@ import org.opentripplanner.apis.gtfs.model.StopPosition; import org.opentripplanner.apis.gtfs.model.StopPosition.PositionAtStop; import org.opentripplanner.framework.graphql.GraphQLUtils; +import org.opentripplanner.model.plan.LegCallTime; import org.opentripplanner.model.plan.Place; -import org.opentripplanner.model.plan.RegularArrivalDepartureTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.VertexType; import org.opentripplanner.routing.vehicle_parking.VehicleParking; @@ -19,7 +19,7 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> getSource(environment).arrival; } @@ -58,7 +58,7 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> getSource(environment).departure; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java index 54f99b828a1..de4476f6651 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java @@ -8,7 +8,7 @@ import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.model.plan.RegularArrivalDepartureTime; +import org.opentripplanner.model.plan.LegCallTime; import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.utils.time.ServiceDateUtils; @@ -16,7 +16,7 @@ public class RegularRealTimeStopTimeImpl implements GraphQLDataFetchers.GraphQLRegularRealTimeStopTime { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledArrival()); @@ -24,13 +24,13 @@ public DataFetcher arrival() { return null; } return tripTime.isRealtime() - ? RegularArrivalDepartureTime.of(scheduledTime, tripTime.getArrivalDelay()) - : RegularArrivalDepartureTime.ofStatic(scheduledTime); + ? LegCallTime.of(scheduledTime, tripTime.getArrivalDelay()) + : LegCallTime.ofStatic(scheduledTime); }; } @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledDeparture()); @@ -38,8 +38,8 @@ public DataFetcher departure() { return null; } return tripTime.isRealtime() - ? RegularArrivalDepartureTime.of(scheduledTime, tripTime.getDepartureDelay()) - : RegularArrivalDepartureTime.ofStatic(scheduledTime); + ? LegCallTime.of(scheduledTime, tripTime.getDepartureDelay()) + : LegCallTime.ofStatic(scheduledTime); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 0d06737b4e3..c2f2d236b41 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -41,7 +41,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.RegularArrivalDepartureTime; +import org.opentripplanner.model.plan.LegCallTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -473,7 +473,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -517,7 +517,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -625,7 +625,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -635,7 +635,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); @@ -861,9 +861,9 @@ public interface GraphQLRegularRealTimeArrivalDepartureTime { * This can include real-time estimates. */ public interface GraphQLRegularRealTimeStopTime { - public DataFetcher arrival(); + public DataFetcher arrival(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher stop(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 1df05e0fb5a..156053ad5dc 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -63,7 +63,7 @@ config: RegularTripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate TripOnServiceDateConnection: graphql.relay.Connection#Connection TripOnServiceDateEdge: graphql.relay.Edge#Edge - RegularRealTimeArrivalDepartureTime: org.opentripplanner.model.plan.RegularArrivalDepartureTime#RegularArrivalDepartureTime + RegularRealTimeArrivalDepartureTime: org.opentripplanner.model.plan.LegCallTime#LegCallTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step @@ -74,7 +74,7 @@ config: InputField: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLInputField#GraphQLInputField Itinerary: org.opentripplanner.model.plan.Itinerary#Itinerary Leg: org.opentripplanner.model.plan.Leg#Leg - LegTime: org.opentripplanner.model.plan.RegularArrivalDepartureTime#RegularArrivalDepartureTime + LegTime: org.opentripplanner.model.plan.LegCallTime#LegCallTime Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index a26b6c88951..6226b0d2b01 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -55,12 +55,8 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - RegularArrivalDepartureTime.ofStatic( - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime) - ), - RegularArrivalDepartureTime.ofStatic( - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime) - ), + LegCallTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), + LegCallTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/application/src/main/java/org/opentripplanner/model/plan/Leg.java b/application/src/main/java/org/opentripplanner/model/plan/Leg.java index 00f1516a875..27e67400daf 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -209,12 +209,12 @@ default Accessibility getTripWheelchairAccessibility() { /** * The time (including realtime information) when the leg starts. */ - RegularArrivalDepartureTime start(); + LegCallTime start(); /** * The time (including realtime information) when the leg ends. */ - RegularArrivalDepartureTime end(); + LegCallTime end(); /** * The date and time this leg begins. diff --git a/application/src/main/java/org/opentripplanner/model/plan/RegularArrivalDepartureTime.java b/application/src/main/java/org/opentripplanner/model/plan/LegCallTime.java similarity index 62% rename from application/src/main/java/org/opentripplanner/model/plan/RegularArrivalDepartureTime.java rename to application/src/main/java/org/opentripplanner/model/plan/LegCallTime.java index 370e91934e1..78a6eb37694 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/RegularArrivalDepartureTime.java +++ b/application/src/main/java/org/opentripplanner/model/plan/LegCallTime.java @@ -7,26 +7,20 @@ /** * A scheduled time of a transit vehicle at a certain location with an optional realtime - * information. + * information. This is meant to be used in transit legs. */ -public record RegularArrivalDepartureTime( - ZonedDateTime scheduledTime, - @Nullable RealTimeEstimate estimated -) { - public RegularArrivalDepartureTime { +public record LegCallTime(ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated) { + public LegCallTime { Objects.requireNonNull(scheduledTime); } - public static RegularArrivalDepartureTime of(ZonedDateTime realtime, int delaySecs) { + public static LegCallTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new RegularArrivalDepartureTime( - realtime.minus(delay), - new RealTimeEstimate(realtime, delay) - ); + return new LegCallTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); } - public static RegularArrivalDepartureTime ofStatic(ZonedDateTime staticTime) { - return new RegularArrivalDepartureTime(staticTime, null); + public static LegCallTime ofStatic(ZonedDateTime staticTime) { + return new LegCallTime(staticTime, null); } /** diff --git a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 635f9ca07d7..55e4bccfdec 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -161,20 +161,20 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public RegularArrivalDepartureTime start() { + public LegCallTime start() { if (isRealTimeUpdated()) { - return RegularArrivalDepartureTime.of(startTime, getDepartureDelay()); + return LegCallTime.of(startTime, getDepartureDelay()); } else { - return RegularArrivalDepartureTime.ofStatic(startTime); + return LegCallTime.ofStatic(startTime); } } @Override - public RegularArrivalDepartureTime end() { + public LegCallTime end() { if (isRealTimeUpdated()) { - return RegularArrivalDepartureTime.of(endTime, getArrivalDelay()); + return LegCallTime.of(endTime, getArrivalDelay()); } else { - return RegularArrivalDepartureTime.ofStatic(endTime); + return LegCallTime.ofStatic(endTime); } } diff --git a/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 6d1314ad8b4..478c8eea379 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -9,8 +9,8 @@ public final class StopArrival { public final Place place; - public final RegularArrivalDepartureTime arrival; - public final RegularArrivalDepartureTime departure; + public final LegCallTime arrival; + public final LegCallTime departure; public final Integer stopPosInPattern; public final Integer gtfsStopSequence; @@ -24,8 +24,8 @@ public final class StopArrival { */ public StopArrival( Place place, - RegularArrivalDepartureTime arrival, - RegularArrivalDepartureTime departure, + LegCallTime arrival, + LegCallTime departure, Integer stopPosInPattern, Integer gtfsStopSequence ) { diff --git a/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java index 80f2de3de80..a4c83e10901 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -34,12 +34,12 @@ StopArrival map(int i, StopLocation stop, boolean realTime) { tripTimes.getDepartureTime(i) ); - var arrival = RegularArrivalDepartureTime.ofStatic(arrivalTime); - var departure = RegularArrivalDepartureTime.ofStatic(departureTime); + var arrival = LegCallTime.ofStatic(arrivalTime); + var departure = LegCallTime.ofStatic(departureTime); if (realTime) { - arrival = RegularArrivalDepartureTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = RegularArrivalDepartureTime.of(departureTime, tripTimes.getDepartureDelay(i)); + arrival = LegCallTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegCallTime.of(departureTime, tripTimes.getDepartureDelay(i)); } return new StopArrival( diff --git a/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index fbf2114da38..cb577b9ec49 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public RegularArrivalDepartureTime start() { - return RegularArrivalDepartureTime.ofStatic(startTime); + public LegCallTime start() { + return LegCallTime.ofStatic(startTime); } @Override - public RegularArrivalDepartureTime end() { - return RegularArrivalDepartureTime.ofStatic(endTime); + public LegCallTime end() { + return LegCallTime.ofStatic(endTime); } @Override diff --git a/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index ea07d97cb16..443621b750a 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/application/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -70,13 +70,13 @@ public boolean hasSameMode(Leg other) { } @Override - public RegularArrivalDepartureTime start() { - return RegularArrivalDepartureTime.ofStatic(startTime); + public LegCallTime start() { + return LegCallTime.ofStatic(startTime); } @Override - public RegularArrivalDepartureTime end() { - return RegularArrivalDepartureTime.ofStatic(endTime); + public LegCallTime end() { + return LegCallTime.ofStatic(endTime); } @Override From c7d6d4359c32438efbebde82383bc8363a936951 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 18 Nov 2024 00:32:16 +0200 Subject: [PATCH 36/48] Refactor LegCallTime --- .../model/plan/LegCallTime.java | 31 ++++++++++++------- .../model/plan/LegRealTimeEstimate.java | 30 ++++++++++++++++++ 2 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 application/src/main/java/org/opentripplanner/model/plan/LegRealTimeEstimate.java diff --git a/application/src/main/java/org/opentripplanner/model/plan/LegCallTime.java b/application/src/main/java/org/opentripplanner/model/plan/LegCallTime.java index 78a6eb37694..676b45c8f92 100644 --- a/application/src/main/java/org/opentripplanner/model/plan/LegCallTime.java +++ b/application/src/main/java/org/opentripplanner/model/plan/LegCallTime.java @@ -9,20 +9,35 @@ * A scheduled time of a transit vehicle at a certain location with an optional realtime * information. This is meant to be used in transit legs. */ -public record LegCallTime(ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated) { - public LegCallTime { - Objects.requireNonNull(scheduledTime); +public class LegCallTime { + + private final ZonedDateTime scheduledTime; + + @Nullable + private final LegRealTimeEstimate estimated; + + private LegCallTime(ZonedDateTime scheduledTime, @Nullable LegRealTimeEstimate estimated) { + this.scheduledTime = Objects.requireNonNull(scheduledTime); + this.estimated = estimated; } public static LegCallTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegCallTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); + return new LegCallTime(realtime.minus(delay), new LegRealTimeEstimate(realtime, delay)); } public static LegCallTime ofStatic(ZonedDateTime staticTime) { return new LegCallTime(staticTime, null); } + public ZonedDateTime scheduledTime() { + return scheduledTime; + } + + public LegRealTimeEstimate estimated() { + return estimated; + } + /** * The most up-to-date time available: if realtime data is available it is returned, if not then * the scheduled one is. @@ -31,13 +46,7 @@ public ZonedDateTime time() { if (estimated == null) { return scheduledTime; } else { - return estimated.time; + return estimated.time(); } } - - /** - * Realtime information about a vehicle at a certain place. - * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. - */ - record RealTimeEstimate(ZonedDateTime time, Duration delay) {} } diff --git a/application/src/main/java/org/opentripplanner/model/plan/LegRealTimeEstimate.java b/application/src/main/java/org/opentripplanner/model/plan/LegRealTimeEstimate.java new file mode 100644 index 00000000000..a924b0c22ae --- /dev/null +++ b/application/src/main/java/org/opentripplanner/model/plan/LegRealTimeEstimate.java @@ -0,0 +1,30 @@ +package org.opentripplanner.model.plan; + +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.Objects; + +/** + * Realtime information about a vehicle at a certain place. Meant to be used in transit legs. + */ +public class LegRealTimeEstimate { + + private final ZonedDateTime time; + private final Duration delay; + + /** + * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. + */ + public LegRealTimeEstimate(ZonedDateTime time, Duration delay) { + this.time = Objects.requireNonNull(time); + this.delay = Objects.requireNonNull(delay); + } + + public ZonedDateTime time() { + return time; + } + + public Duration delay() { + return delay; + } +} From 178c150725b78c2ebb4e3b3c089cc6b1d33bf16d Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 18 Nov 2024 12:20:10 +0200 Subject: [PATCH 37/48] Rename StopTime -> StopCall etc. and create own model for its times --- .../apis/gtfs/GtfsGraphQLIndex.java | 15 ++- ...ellableTripOnServiceDateTypeResolver.java} | 4 +- ...imeStopTimeImpl.java => StopCallImpl.java} | 17 ++- ...teImpl.java => TripOnServiceDateImpl.java} | 5 +- .../gtfs/generated/GraphQLDataFetchers.java | 84 +++++++------ .../apis/gtfs/generated/graphql-codegen.yml | 6 +- .../model/timetable/CallRealTimeEstimate.java | 31 +++++ .../transit/model/timetable/CallTime.java | 40 ++++++ .../opentripplanner/apis/gtfs/schema.graphqls | 116 +++++++++--------- .../gtfs/expectations/canceled-trips.json | 2 +- .../apis/gtfs/queries/canceled-trips.graphql | 4 +- 11 files changed, 201 insertions(+), 123 deletions(-) rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{TripOnServiceDateTypeResolver.java => CancellableTripOnServiceDateTypeResolver.java} (79%) rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{RegularRealTimeStopTimeImpl.java => StopCallImpl.java} (79%) rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{RegularTripOnServiceDateImpl.java => TripOnServiceDateImpl.java} (95%) create mode 100644 application/src/main/java/org/opentripplanner/transit/model/timetable/CallRealTimeEstimate.java create mode 100644 application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 014acb97398..2a7599ecfd7 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -31,6 +31,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.BikeRentalStationImpl; import org.opentripplanner.apis.gtfs.datafetchers.BookingInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.BookingTimeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.CancellableTripOnServiceDateTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.CarParkImpl; import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.CoordinatesImpl; @@ -52,14 +53,13 @@ import org.opentripplanner.apis.gtfs.datafetchers.PlanConnectionImpl; import org.opentripplanner.apis.gtfs.datafetchers.PlanImpl; import org.opentripplanner.apis.gtfs.datafetchers.QueryTypeImpl; -import org.opentripplanner.apis.gtfs.datafetchers.RegularRealTimeStopTimeImpl; -import org.opentripplanner.apis.gtfs.datafetchers.RegularTripOnServiceDateImpl; import org.opentripplanner.apis.gtfs.datafetchers.RentalVehicleImpl; import org.opentripplanner.apis.gtfs.datafetchers.RentalVehicleTypeImpl; import org.opentripplanner.apis.gtfs.datafetchers.RideHailingEstimateImpl; import org.opentripplanner.apis.gtfs.datafetchers.RouteImpl; import org.opentripplanner.apis.gtfs.datafetchers.RouteTypeImpl; import org.opentripplanner.apis.gtfs.datafetchers.RoutingErrorImpl; +import org.opentripplanner.apis.gtfs.datafetchers.StopCallImpl; import org.opentripplanner.apis.gtfs.datafetchers.StopGeometriesImpl; import org.opentripplanner.apis.gtfs.datafetchers.StopImpl; import org.opentripplanner.apis.gtfs.datafetchers.StopOnRouteImpl; @@ -72,7 +72,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.TranslatedStringImpl; import org.opentripplanner.apis.gtfs.datafetchers.TripImpl; import org.opentripplanner.apis.gtfs.datafetchers.TripOccupancyImpl; -import org.opentripplanner.apis.gtfs.datafetchers.TripOnServiceDateTypeResolver; +import org.opentripplanner.apis.gtfs.datafetchers.TripOnServiceDateImpl; import org.opentripplanner.apis.gtfs.datafetchers.UnknownImpl; import org.opentripplanner.apis.gtfs.datafetchers.VehicleParkingImpl; import org.opentripplanner.apis.gtfs.datafetchers.VehiclePositionImpl; @@ -129,7 +129,10 @@ protected static GraphQLSchema buildSchema() { .type("StopPosition", type -> type.typeResolver(new StopPosition() {})) .type("FareProduct", type -> type.typeResolver(new FareProductTypeResolver())) .type("AlertEntity", type -> type.typeResolver(new AlertEntityTypeResolver())) - .type("TripOnServiceDate", type -> type.typeResolver(new TripOnServiceDateTypeResolver())) + .type( + "CancellableTripOnServiceDate", + type -> type.typeResolver(new CancellableTripOnServiceDateTypeResolver()) + ) .type(typeWiring.build(AgencyImpl.class)) .type(typeWiring.build(AlertImpl.class)) .type(typeWiring.build(BikeParkImpl.class)) @@ -182,8 +185,8 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(CurrencyImpl.class)) .type(typeWiring.build(FareProductUseImpl.class)) .type(typeWiring.build(DefaultFareProductImpl.class)) - .type(typeWiring.build(RegularTripOnServiceDateImpl.class)) - .type(typeWiring.build(RegularRealTimeStopTimeImpl.class)) + .type(typeWiring.build(TripOnServiceDateImpl.class)) + .type(typeWiring.build(StopCallImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CancellableTripOnServiceDateTypeResolver.java similarity index 79% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CancellableTripOnServiceDateTypeResolver.java index 570177768f0..4c9af823767 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateTypeResolver.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CancellableTripOnServiceDateTypeResolver.java @@ -6,7 +6,7 @@ import graphql.schema.TypeResolver; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; -public class TripOnServiceDateTypeResolver implements TypeResolver { +public class CancellableTripOnServiceDateTypeResolver implements TypeResolver { @Override public GraphQLObjectType getType(TypeResolutionEnvironment environment) { @@ -14,7 +14,7 @@ public GraphQLObjectType getType(TypeResolutionEnvironment environment) { GraphQLSchema schema = environment.getSchema(); if (o instanceof TripOnServiceDate) { - return schema.getObjectType("RegularTripOnServiceDate"); + return schema.getObjectType("TripOnServiceDate"); } return null; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopCallImpl.java similarity index 79% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopCallImpl.java index de4476f6651..cb5ec7e15a5 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularRealTimeStopTimeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopCallImpl.java @@ -8,15 +8,14 @@ import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.model.plan.LegCallTime; +import org.opentripplanner.transit.model.timetable.CallTime; import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.utils.time.ServiceDateUtils; -public class RegularRealTimeStopTimeImpl - implements GraphQLDataFetchers.GraphQLRegularRealTimeStopTime { +public class StopCallImpl implements GraphQLDataFetchers.GraphQLStopCall { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledArrival()); @@ -24,13 +23,13 @@ public DataFetcher arrival() { return null; } return tripTime.isRealtime() - ? LegCallTime.of(scheduledTime, tripTime.getArrivalDelay()) - : LegCallTime.ofStatic(scheduledTime); + ? CallTime.of(scheduledTime, tripTime.getArrivalDelay()) + : CallTime.ofStatic(scheduledTime); }; } @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> { var tripTime = getSource(environment); var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledDeparture()); @@ -38,8 +37,8 @@ public DataFetcher departure() { return null; } return tripTime.isRealtime() - ? LegCallTime.of(scheduledTime, tripTime.getDepartureDelay()) - : LegCallTime.ofStatic(scheduledTime); + ? CallTime.of(scheduledTime, tripTime.getDepartureDelay()) + : CallTime.ofStatic(scheduledTime); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularTripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java similarity index 95% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularTripOnServiceDateImpl.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java index f6b7107aded..22e45a9afda 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RegularTripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java @@ -16,8 +16,7 @@ import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.utils.time.ServiceDateUtils; -public class RegularTripOnServiceDateImpl - implements GraphQLDataFetchers.GraphQLRegularTripOnServiceDate { +public class TripOnServiceDateImpl implements GraphQLDataFetchers.GraphQLTripOnServiceDate { @Override public DataFetcher serviceDate() { @@ -61,7 +60,7 @@ public DataFetcher start() { } @Override - public DataFetcher> stopTimes() { + public DataFetcher> stopCalls() { return environment -> { TransitService transitService = getTransitService(environment); Trip trip = getTrip(environment); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index c2f2d236b41..f4843a31ecf 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -66,6 +66,7 @@ import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.organization.Agency; +import org.opentripplanner.transit.model.timetable.CallTime; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; import org.opentripplanner.transit.model.timetable.booking.BookingInfo; @@ -239,6 +240,26 @@ public interface GraphQLBookingTime { public DataFetcher time(); } + /** Real-time estimates for an arrival or departure at a certain place. */ + public interface GraphQLCallRealTimeEstimate { + public DataFetcher delay(); + + public DataFetcher time(); + } + + /** + * Timing of an arrival or a departure to or from a stop. May contain real-time information if + * available. This is used when there is a known scheduled time. + */ + public interface GraphQLCallTime { + public DataFetcher estimated(); + + public DataFetcher scheduledTime(); + } + + /** An instance of a trip, which can be cancelled, on a service date. */ + public interface GraphQLCancellableTripOnServiceDate extends TypeResolver {} + /** Car park represents a location where cars can be parked. */ public interface GraphQLCarPark { public DataFetcher carParkId(); @@ -846,41 +867,6 @@ public interface GraphQLRealTimeEstimate { public DataFetcher time(); } - /** - * Timing of an arrival or a departure to or from a stop. May contain real-time information if - * available. This is used when there is a known scheduled time. - */ - public interface GraphQLRegularRealTimeArrivalDepartureTime { - public DataFetcher estimated(); - - public DataFetcher scheduledTime(); - } - - /** - * Regular real-time stop time represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. - * This can include real-time estimates. - */ - public interface GraphQLRegularRealTimeStopTime { - public DataFetcher arrival(); - - public DataFetcher departure(); - - public DataFetcher stop(); - } - - /** A regular (i.e. not flexible) trip on a specific service date */ - public interface GraphQLRegularTripOnServiceDate { - public DataFetcher end(); - - public DataFetcher serviceDate(); - - public DataFetcher start(); - - public DataFetcher> stopTimes(); - - public DataFetcher trip(); - } - /** Rental vehicle represents a vehicle that belongs to a rental network. */ public interface GraphQLRentalVehicle { public DataFetcher allowPickupNow(); @@ -1075,6 +1061,18 @@ public interface GraphQLStop { public DataFetcher zoneId(); } + /** + * Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. + * This can include real-time estimates. + */ + public interface GraphQLStopCall { + public DataFetcher arrival(); + + public DataFetcher departure(); + + public DataFetcher stop(); + } + public interface GraphQLStopGeometries { public DataFetcher geoJson(); @@ -1241,11 +1239,17 @@ public interface GraphQLTripOccupancy { public DataFetcher occupancyStatus(); } - /** An instance of a trip on a service date. */ - public interface GraphQLTripOnServiceDate extends TypeResolver { - public default DataFetcher serviceDate() { - return null; - } + /** A regular (i.e. not flexible) trip on a specific service date */ + public interface GraphQLTripOnServiceDate { + public DataFetcher end(); + + public DataFetcher serviceDate(); + + public DataFetcher start(); + + public DataFetcher> stopCalls(); + + public DataFetcher trip(); } /** diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 156053ad5dc..1f2733ee34b 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -59,11 +59,11 @@ config: ContactInfo: org.opentripplanner.transit.model.organization.ContactInfo Cluster: Object Coordinates: org.locationtech.jts.geom.Coordinate#Coordinate - RegularRealTimeStopTime: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate - RegularTripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate + StopCall: org.opentripplanner.model.TripTimeOnDate#TripTimeOnDate + TripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate TripOnServiceDateConnection: graphql.relay.Connection#Connection TripOnServiceDateEdge: graphql.relay.Edge#Edge - RegularRealTimeArrivalDepartureTime: org.opentripplanner.model.plan.LegCallTime#LegCallTime + CallTime: org.opentripplanner.transit.model.timetable.CallTime#CallTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step diff --git a/application/src/main/java/org/opentripplanner/transit/model/timetable/CallRealTimeEstimate.java b/application/src/main/java/org/opentripplanner/transit/model/timetable/CallRealTimeEstimate.java new file mode 100644 index 00000000000..eeac4a321c4 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/transit/model/timetable/CallRealTimeEstimate.java @@ -0,0 +1,31 @@ +package org.opentripplanner.transit.model.timetable; + +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.Objects; + +/** + * Realtime information about a vehicle at a certain place. This is meant to be used in timetables + * (not in transit legs). + */ +public class CallRealTimeEstimate { + + private final ZonedDateTime time; + private final Duration delay; + + /** + * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. + */ + public CallRealTimeEstimate(ZonedDateTime time, Duration delay) { + this.time = Objects.requireNonNull(time); + this.delay = Objects.requireNonNull(delay); + } + + public ZonedDateTime time() { + return time; + } + + public Duration delay() { + return delay; + } +} diff --git a/application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java b/application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java new file mode 100644 index 00000000000..4a7df9fb217 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java @@ -0,0 +1,40 @@ +package org.opentripplanner.transit.model.timetable; + +import java.time.Duration; +import java.time.ZonedDateTime; +import java.util.Objects; +import javax.annotation.Nullable; + +/** + * A scheduled time of a transit vehicle at a certain location with an optional realtime + * information. This is meant to be used in timetables (not in transit legs). + */ +public class CallTime { + + private final ZonedDateTime scheduledTime; + + @Nullable + private final CallRealTimeEstimate estimated; + + private CallTime(ZonedDateTime scheduledTime, @Nullable CallRealTimeEstimate estimated) { + this.scheduledTime = Objects.requireNonNull(scheduledTime); + this.estimated = estimated; + } + + public static CallTime of(ZonedDateTime realtime, int delaySecs) { + var delay = Duration.ofSeconds(delaySecs); + return new CallTime(realtime.minus(delay), new CallRealTimeEstimate(realtime, delay)); + } + + public static CallTime ofStatic(ZonedDateTime staticTime) { + return new CallTime(staticTime, null); + } + + public ZonedDateTime scheduledTime() { + return scheduledTime; + } + + public CallRealTimeEstimate estimated() { + return estimated; + } +} diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 25f7a757131..07a89270370 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -70,21 +70,12 @@ interface PlaceInterface { lon: Float } -"An instance of a trip on a service date." -interface TripOnServiceDate { - """ - The service date when the trip occurs. - - **Note**: A service date is a technical term useful for transit planning purposes and might not - correspond to a how a passenger thinks of a calendar date. For example, a night bus running - on Sunday morning at 1am to 3am, might have the previous Saturday's service date. - """ - serviceDate: LocalDate! -} - "Entity related to an alert" union AlertEntity = Agency | Pattern | Route | RouteType | Stop | StopOnRoute | StopOnTrip | Trip | Unknown +"An instance of a trip, which can be cancelled, on a service date." +union CancellableTripOnServiceDate = TripOnServiceDate + union StopPosition = PositionAtStop | PositionBetweenStops "A public transport agency" @@ -306,6 +297,28 @@ type BookingTime { time: String } +"Real-time estimates for an arrival or departure at a certain place." +type CallRealTimeEstimate { + """ + The delay or "earliness" of the vehicle at a certain place. + + If the vehicle is early then this is a negative duration. + """ + delay: Duration! + time: OffsetDateTime! +} + +""" +Timing of an arrival or a departure to or from a stop. May contain real-time information if +available. This is used when there is a known scheduled time. +""" +type CallTime { + "The estimated time of the event. If no real-time information is available, this is null." + estimated: CallRealTimeEstimate + "The scheduled time of the event." + scheduledTime: OffsetDateTime! +} + "Car park represents a location where cars can be parked." type CarPark implements Node & PlaceInterface { "ID of the car park" @@ -1808,50 +1821,6 @@ type RealTimeEstimate { time: OffsetDateTime! } -""" -Timing of an arrival or a departure to or from a stop. May contain real-time information if -available. This is used when there is a known scheduled time. -""" -type RegularRealTimeArrivalDepartureTime { - "The estimated time of the event. If no real-time information is available, this is null." - estimated: RealTimeEstimate - "The scheduled time of the event." - scheduledTime: OffsetDateTime! -} - -""" -Regular real-time stop time represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. -This can include real-time estimates. -""" -type RegularRealTimeStopTime { - "Scheduled arrival time to the stop and a real-time estimate, if one exists." - arrival: RegularRealTimeArrivalDepartureTime - "Scheduled departure time from the stop and a real-time estimate, if one exists." - departure: RegularRealTimeArrivalDepartureTime - "The stop where this arrival/departure happens" - stop: Stop -} - -"A regular (i.e. not flexible) trip on a specific service date" -type RegularTripOnServiceDate implements TripOnServiceDate { - "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." - end: RegularRealTimeStopTime! - """ - The service date when the trip occurs. - - **Note**: A service date is a technical term useful for transit planning purposes and might not - correspond to a how a passenger thinks of a calendar date. For example, a night bus running - on Sunday morning at 1am to 3am, might have the previous Saturday's service date. - """ - serviceDate: LocalDate! - "Information related to trip's scheduled departure from the first stop. Can contain realtime information." - start: RegularRealTimeStopTime! - "List of times when this trip arrives to or departs from a stop and information related to the stop" - stopTimes: [RegularRealTimeStopTime!]! - "This trip on service date is an instance of this trip." - trip: Trip -} - "Rental vehicle represents a vehicle that belongs to a rental network." type RentalVehicle implements Node & PlaceInterface { "If true, vehicle is currently available for renting." @@ -2214,6 +2183,19 @@ type Stop implements Node & PlaceInterface { zoneId: String } +""" +Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. +This can include real-time estimates. +""" +type StopCall { + "Scheduled arrival time to the stop and a real-time estimate, if one exists." + arrival: CallTime + "Scheduled departure time from the stop and a real-time estimate, if one exists." + departure: CallTime + "The stop where this arrival/departure happens" + stop: Stop +} + type StopGeometries { "Representation of the stop geometries as GeoJSON (https://geojson.org/)" geoJson: GeoJson @@ -2469,6 +2451,26 @@ type TripOccupancy { occupancyStatus: OccupancyStatus } +"A regular (i.e. not flexible) trip on a specific service date" +type TripOnServiceDate { + "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." + end: StopCall! + """ + The service date when the trip occurs. + + **Note**: A service date is a technical term useful for transit planning purposes and might not + correspond to a how a passenger thinks of a calendar date. For example, a night bus running + on Sunday morning at 1am to 3am, might have the previous Saturday's service date. + """ + serviceDate: LocalDate! + "Information related to trip's scheduled departure from the first stop. Can contain realtime information." + start: StopCall! + "List of times when this trip arrives to or departs from a stop and information related to the stop" + stopCalls: [StopCall!]! + "This trip on service date is an instance of this trip." + trip: Trip +} + """ A connection to a list of trips on service dates that follows [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). @@ -2500,7 +2502,7 @@ type TripOnServiceDateEdge { Trip on a service date as a node. Part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). """ - node: TripOnServiceDate + node: CancellableTripOnServiceDate } "This is used for alert entities that we don't explicitly handle or they are missing." diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json index b3facd3da1f..5e32b67fc4e 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json @@ -29,7 +29,7 @@ "scheduledTime": "2024-08-09T11:30:00+02:00" } }, - "stopTimes": [ + "stopCalls": [ { "stop": { "gtfsId": "F:Stop_0" diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index 9629c4ae418..8d5685a06ba 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -8,7 +8,7 @@ } edges { node { - ... on RegularTripOnServiceDate { + ... on TripOnServiceDate { serviceDate end { arrival { @@ -28,7 +28,7 @@ scheduledTime } } - stopTimes { + stopCalls { stop { gtfsId } From 349efb66083bc7041aa563d42c1cd34e260cb432 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 18 Nov 2024 14:38:46 +0200 Subject: [PATCH 38/48] Create implementations for call times --- .../apis/gtfs/GtfsGraphQLIndex.java | 8 ++++++ .../CallRealTimeEstimateImpl.java | 25 +++++++++++++++++++ .../apis/gtfs/datafetchers/CallTimeImpl.java | 25 +++++++++++++++++++ .../apis/gtfs/datafetchers/LegTimeImpl.java | 25 +++++++++++++++++++ .../datafetchers/RealTimeEstimateImpl.java | 25 +++++++++++++++++++ .../gtfs/generated/GraphQLDataFetchers.java | 6 +++-- .../apis/gtfs/generated/graphql-codegen.yml | 2 ++ 7 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallRealTimeEstimateImpl.java create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegTimeImpl.java create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RealTimeEstimateImpl.java diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 2a7599ecfd7..ddf251ea833 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -31,6 +31,8 @@ import org.opentripplanner.apis.gtfs.datafetchers.BikeRentalStationImpl; import org.opentripplanner.apis.gtfs.datafetchers.BookingInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.BookingTimeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.CallRealTimeEstimateImpl; +import org.opentripplanner.apis.gtfs.datafetchers.CallTimeImpl; import org.opentripplanner.apis.gtfs.datafetchers.CancellableTripOnServiceDateTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.CarParkImpl; import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; @@ -44,6 +46,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.GeometryImpl; import org.opentripplanner.apis.gtfs.datafetchers.ItineraryImpl; import org.opentripplanner.apis.gtfs.datafetchers.LegImpl; +import org.opentripplanner.apis.gtfs.datafetchers.LegTimeImpl; import org.opentripplanner.apis.gtfs.datafetchers.MoneyImpl; import org.opentripplanner.apis.gtfs.datafetchers.NodeTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.OpeningHoursImpl; @@ -53,6 +56,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.PlanConnectionImpl; import org.opentripplanner.apis.gtfs.datafetchers.PlanImpl; import org.opentripplanner.apis.gtfs.datafetchers.QueryTypeImpl; +import org.opentripplanner.apis.gtfs.datafetchers.RealTimeEstimateImpl; import org.opentripplanner.apis.gtfs.datafetchers.RentalVehicleImpl; import org.opentripplanner.apis.gtfs.datafetchers.RentalVehicleTypeImpl; import org.opentripplanner.apis.gtfs.datafetchers.RideHailingEstimateImpl; @@ -188,6 +192,10 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(TripOnServiceDateImpl.class)) .type(typeWiring.build(StopCallImpl.class)) .type(typeWiring.build(TripOccupancyImpl.class)) + .type(typeWiring.build(LegTimeImpl.class)) + .type(typeWiring.build(RealTimeEstimateImpl.class)) + .type(typeWiring.build(CallTimeImpl.class)) + .type(typeWiring.build(CallRealTimeEstimateImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallRealTimeEstimateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallRealTimeEstimateImpl.java new file mode 100644 index 00000000000..09439c6e916 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallRealTimeEstimateImpl.java @@ -0,0 +1,25 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import java.time.Duration; +import java.time.OffsetDateTime; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.transit.model.timetable.CallRealTimeEstimate; + +public class CallRealTimeEstimateImpl implements GraphQLDataFetchers.GraphQLCallRealTimeEstimate { + + @Override + public DataFetcher delay() { + return environment -> getSource(environment).delay(); + } + + @Override + public DataFetcher time() { + return environment -> getSource(environment).time().toOffsetDateTime(); + } + + private CallRealTimeEstimate getSource(DataFetchingEnvironment environment) { + return environment.getSource(); + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java new file mode 100644 index 00000000000..5a2da2c2d82 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java @@ -0,0 +1,25 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.transit.model.timetable.CallRealTimeEstimate; +import org.opentripplanner.transit.model.timetable.CallTime; + +public class CallTimeImpl implements GraphQLDataFetchers.GraphQLCallTime { + + @Override + public DataFetcher estimated() { + return environment -> getSource(environment).estimated(); + } + + @Override + public DataFetcher scheduledTime() { + return environment -> getSource(environment).scheduledTime().toOffsetDateTime(); + } + + private CallTime getSource(DataFetchingEnvironment environment) { + return environment.getSource(); + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegTimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegTimeImpl.java new file mode 100644 index 00000000000..571c0f2f38c --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegTimeImpl.java @@ -0,0 +1,25 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.model.plan.LegCallTime; +import org.opentripplanner.model.plan.LegRealTimeEstimate; + +public class LegTimeImpl implements GraphQLDataFetchers.GraphQLLegTime { + + @Override + public DataFetcher estimated() { + return environment -> getSource(environment).estimated(); + } + + @Override + public DataFetcher scheduledTime() { + return environment -> getSource(environment).scheduledTime().toOffsetDateTime(); + } + + private LegCallTime getSource(DataFetchingEnvironment environment) { + return environment.getSource(); + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RealTimeEstimateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RealTimeEstimateImpl.java new file mode 100644 index 00000000000..fbbf5226691 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/RealTimeEstimateImpl.java @@ -0,0 +1,25 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.schema.DataFetcher; +import graphql.schema.DataFetchingEnvironment; +import java.time.Duration; +import java.time.OffsetDateTime; +import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.model.plan.LegRealTimeEstimate; + +public class RealTimeEstimateImpl implements GraphQLDataFetchers.GraphQLRealTimeEstimate { + + @Override + public DataFetcher delay() { + return environment -> getSource(environment).delay(); + } + + @Override + public DataFetcher time() { + return environment -> getSource(environment).time().toOffsetDateTime(); + } + + private LegRealTimeEstimate getSource(DataFetchingEnvironment environment) { + return environment.getSource(); + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index f4843a31ecf..0210a5708dc 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -42,6 +42,7 @@ import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; import org.opentripplanner.model.plan.LegCallTime; +import org.opentripplanner.model.plan.LegRealTimeEstimate; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -66,6 +67,7 @@ import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.organization.Agency; +import org.opentripplanner.transit.model.timetable.CallRealTimeEstimate; import org.opentripplanner.transit.model.timetable.CallTime; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; @@ -252,7 +254,7 @@ public interface GraphQLCallRealTimeEstimate { * available. This is used when there is a known scheduled time. */ public interface GraphQLCallTime { - public DataFetcher estimated(); + public DataFetcher estimated(); public DataFetcher scheduledTime(); } @@ -558,7 +560,7 @@ public interface GraphQLLeg { * available. */ public interface GraphQLLegTime { - public DataFetcher estimated(); + public DataFetcher estimated(); public DataFetcher scheduledTime(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 1f2733ee34b..d5059311cac 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -130,4 +130,6 @@ config: FareMedium: org.opentripplanner.model.fare.FareMedium#FareMedium RiderCategory: org.opentripplanner.model.fare.RiderCategory#RiderCategory StopPosition: org.opentripplanner.apis.gtfs.model.StopPosition#StopPosition + RealTimeEstimate: org.opentripplanner.model.plan.LegRealTimeEstimate#LegRealTimeEstimate + CallRealTimeEstimate: org.opentripplanner.transit.model.timetable.CallRealTimeEstimate#CallRealTimeEstimate From 405f580ec1d1ca7e0df3f8fa2fe5d27aa9ae19cb Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Tue, 19 Nov 2024 17:19:18 +0200 Subject: [PATCH 39/48] Remove support for feeds argument --- .../apis/gtfs/datafetchers/QueryTypeImpl.java | 11 +--------- .../apis/gtfs/generated/GraphQLTypes.java | 10 ---------- .../model/TimetableSnapshot.java | 14 ------------- .../service/DefaultTransitService.java | 20 ------------------- .../transit/service/TransitService.java | 7 ------- .../opentripplanner/apis/gtfs/schema.graphqls | 2 -- .../service/DefaultTransitServiceTest.java | 18 ----------------- .../apis/gtfs/queries/canceled-trips.graphql | 2 +- 8 files changed, 2 insertions(+), 82 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java index 2f886f81734..b36cb0a46ba 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/QueryTypeImpl.java @@ -833,16 +833,7 @@ public DataFetcher> trips() { @Override public DataFetcher> canceledTrips() { return environment -> { - var args = new GraphQLTypes.GraphQLQueryTypeCanceledTripsArgs(environment.getArguments()); - if (args.getGraphQLFeeds() != null && args.getGraphQLFeeds().isEmpty()) { - throw new IllegalArgumentException( - "Feeds need to be either not specified or contain elements." - ); - } - - var trips = args.getGraphQLFeeds() != null - ? getTransitService(environment).findCanceledTrips(args.getGraphQLFeeds()) - : getTransitService(environment).listCanceledTrips(); + var trips = getTransitService(environment).listCanceledTrips(); return new SimpleListConnection<>(trips).get(environment); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java index 37d5ff674dd..32e78eef231 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -2410,7 +2410,6 @@ public static class GraphQLQueryTypeCanceledTripsArgs { private String after; private String before; - private List feeds; private Integer first; private Integer last; @@ -2418,7 +2417,6 @@ public GraphQLQueryTypeCanceledTripsArgs(Map args) { if (args != null) { this.after = (String) args.get("after"); this.before = (String) args.get("before"); - this.feeds = (List) args.get("feeds"); this.first = (Integer) args.get("first"); this.last = (Integer) args.get("last"); } @@ -2432,10 +2430,6 @@ public String getGraphQLBefore() { return this.before; } - public List getGraphQLFeeds() { - return this.feeds; - } - public Integer getGraphQLFirst() { return this.first; } @@ -2452,10 +2446,6 @@ public void setGraphQLBefore(String before) { this.before = before; } - public void setGraphQLFeeds(List feeds) { - this.feeds = feeds; - } - public void setGraphQLFirst(Integer first) { this.first = first; } diff --git a/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java b/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java index 77e5d1f6fbb..44ce1e5cb18 100644 --- a/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java +++ b/application/src/main/java/org/opentripplanner/model/TimetableSnapshot.java @@ -226,20 +226,6 @@ public TripPattern getNewTripPatternForModifiedTrip(FeedScopedId tripId, LocalDa return realTimeNewTripPatternsForModifiedTrips.get(tripIdAndServiceDate); } - /** - * Find trips which have been canceled. - * - * @param feeds only return trips from these feeds. Empty list is not allowed. - */ - public List findCanceledTrips(List feeds) { - if (feeds == null || feeds.isEmpty()) { - throw new IllegalArgumentException("Feeds list cannot be null or empty"); - } - return findTripsOnServiceDates(tripTimes -> - tripTimes.isCanceled() && feeds.contains(tripTimes.getTrip().getId().getFeedId()) - ); - } - /** * List trips which have been canceled. */ diff --git a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java index 2dd31e93da3..8b9e473d193 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/DefaultTransitService.java @@ -295,26 +295,6 @@ public Trip getScheduledTripForId(FeedScopedId id) { return this.timetableRepositoryIndex.getTripForId(id); } - /** - * TODO This only supports realtime cancelled trips for now. - */ - @Override - public List findCanceledTrips(List feeds) { - if (feeds == null || feeds.isEmpty()) { - throw new IllegalArgumentException( - "Feeds list cannot be empty or null. It needs to have elements." - ); - } - OTPRequestTimeoutException.checkForTimeout(); - var timetableSnapshot = lazyGetTimeTableSnapShot(); - if (timetableSnapshot == null) { - return List.of(); - } - List canceledTrips = timetableSnapshot.findCanceledTrips(feeds); - canceledTrips.sort(new TripOnServiceDateComparator()); - return canceledTrips; - } - /** * TODO This only supports realtime cancelled trips for now. */ diff --git a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java index 4e0b49d559f..e534b154dd0 100644 --- a/application/src/main/java/org/opentripplanner/transit/service/TransitService.java +++ b/application/src/main/java/org/opentripplanner/transit/service/TransitService.java @@ -169,13 +169,6 @@ public interface TransitService { */ Collection getAllTrips(); - /** - * Find canceled trips. - * - * @param feeds used for filtering. Empty list is not allowed. - */ - List findCanceledTrips(List feeds); - /** * List all canceled trips. */ diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 07a89270370..2bd7d42a451 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1151,8 +1151,6 @@ type QueryType { and should be used together with the `last` parameter. """ before: String, - "Feed feedIds (e.g. [\"HSL\"])." - feeds: [String], """ Limits how many trips are returned. This parameter is part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm) and can be used together with diff --git a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java index 534b0103854..868d89d61d7 100644 --- a/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java +++ b/application/src/test/java/org/opentripplanner/transit/service/DefaultTransitServiceTest.java @@ -1,6 +1,5 @@ package org.opentripplanner.transit.service; -import static org.junit.Assert.assertThrows; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.opentripplanner.model.plan.PlanTestConstants.T11_30; import static org.opentripplanner.transit.model.basic.TransitMode.BUS; @@ -157,21 +156,4 @@ void listCanceledTrips() { var canceledTrips = service.listCanceledTrips(); assertEquals("[TripOnServiceDate{F:123}, TripOnServiceDate{F:123}]", canceledTrips.toString()); } - - @Test - void findCanceledTrips() { - var canceledTripsForFeedWithCancellations = service.findCanceledTrips(List.of("F", "G")); - assertEquals( - "[TripOnServiceDate{F:123}, TripOnServiceDate{F:123}]", - canceledTripsForFeedWithCancellations.toString() - ); - - var canceledTripsForFeedWithoutCancellations = service.findCanceledTrips(List.of("G")); - assertEquals("[]", canceledTripsForFeedWithoutCancellations.toString()); - } - - @Test - void findCanceledTripsWithEmptyFeeds() { - assertThrows(IllegalArgumentException.class, () -> service.findCanceledTrips(List.of())); - } } diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index 8d5685a06ba..cf767d81f10 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -1,5 +1,5 @@ { - canceledTrips(feeds: "F") { + canceledTrips(first: 2) { pageInfo { hasNextPage hasPreviousPage From ac21d8a099ea751d55ab1b0c6216e5273c8ef82e Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Thu, 21 Nov 2024 14:14:29 +0200 Subject: [PATCH 40/48] Improve doc --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2bd7d42a451..15a877e3ed4 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -300,11 +300,12 @@ type BookingTime { "Real-time estimates for an arrival or departure at a certain place." type CallRealTimeEstimate { """ - The delay or "earliness" of the vehicle at a certain place. + The delay or "earliness" of the vehicle at a certain place. This estimate can change quite often. If the vehicle is early then this is a negative duration. """ delay: Duration! + "The estimate for a call event (such as arrival or departure) at a certain place. This estimate can change quite often." time: OffsetDateTime! } From ca5310034416fae6c6a6907cd91f8b97e12f7b4f Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Fri, 22 Nov 2024 13:03:57 +0200 Subject: [PATCH 41/48] Redesign schema --- .../apis/gtfs/GtfsGraphQLIndex.java | 7 ++----- ...ypeResolver.java => CallTypeResolver.java} | 8 +++---- .../datafetchers/TripOnServiceDateImpl.java | 12 +++++++---- .../gtfs/generated/GraphQLDataFetchers.java | 21 +++++++++++-------- .../opentripplanner/apis/gtfs/schema.graphqls | 19 ++++++++++------- .../apis/gtfs/queries/canceled-trips.graphql | 20 +++++++++++------- 6 files changed, 49 insertions(+), 38 deletions(-) rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{CancellableTripOnServiceDateTypeResolver.java => CallTypeResolver.java} (62%) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index ddf251ea833..10e33c0f777 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -33,7 +33,7 @@ import org.opentripplanner.apis.gtfs.datafetchers.BookingTimeImpl; import org.opentripplanner.apis.gtfs.datafetchers.CallRealTimeEstimateImpl; import org.opentripplanner.apis.gtfs.datafetchers.CallTimeImpl; -import org.opentripplanner.apis.gtfs.datafetchers.CancellableTripOnServiceDateTypeResolver; +import org.opentripplanner.apis.gtfs.datafetchers.CallTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.CarParkImpl; import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.CoordinatesImpl; @@ -133,10 +133,7 @@ protected static GraphQLSchema buildSchema() { .type("StopPosition", type -> type.typeResolver(new StopPosition() {})) .type("FareProduct", type -> type.typeResolver(new FareProductTypeResolver())) .type("AlertEntity", type -> type.typeResolver(new AlertEntityTypeResolver())) - .type( - "CancellableTripOnServiceDate", - type -> type.typeResolver(new CancellableTripOnServiceDateTypeResolver()) - ) + .type("Call", type -> type.typeResolver(new CallTypeResolver())) .type(typeWiring.build(AgencyImpl.class)) .type(typeWiring.build(AlertImpl.class)) .type(typeWiring.build(BikeParkImpl.class)) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CancellableTripOnServiceDateTypeResolver.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTypeResolver.java similarity index 62% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CancellableTripOnServiceDateTypeResolver.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTypeResolver.java index 4c9af823767..02ee6784073 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CancellableTripOnServiceDateTypeResolver.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTypeResolver.java @@ -4,17 +4,17 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; import graphql.schema.TypeResolver; -import org.opentripplanner.transit.model.timetable.TripOnServiceDate; +import org.opentripplanner.model.TripTimeOnDate; -public class CancellableTripOnServiceDateTypeResolver implements TypeResolver { +public class CallTypeResolver implements TypeResolver { @Override public GraphQLObjectType getType(TypeResolutionEnvironment environment) { Object o = environment.getObject(); GraphQLSchema schema = environment.getSchema(); - if (o instanceof TripOnServiceDate) { - return schema.getObjectType("TripOnServiceDate"); + if (o instanceof TripTimeOnDate) { + return schema.getObjectType("StopCall"); } return null; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java index 22e45a9afda..b85f63a9d17 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java @@ -24,7 +24,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> { TransitService transitService = getTransitService(environment); Trip trip = getTrip(environment); @@ -42,7 +42,7 @@ public DataFetcher end() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> { TransitService transitService = getTransitService(environment); Trip trip = getTrip(environment); @@ -60,7 +60,7 @@ public DataFetcher start() { } @Override - public DataFetcher> stopCalls() { + public DataFetcher> stopCalls() { return environment -> { TransitService transitService = getTransitService(environment); Trip trip = getTrip(environment); @@ -73,7 +73,11 @@ public DataFetcher> stopCalls() { if (timetable == null) { return List.of(); } - return TripTimeOnDate.fromTripTimes(timetable, trip, serviceDate, midnight); + return TripTimeOnDate + .fromTripTimes(timetable, trip, serviceDate, midnight) + .stream() + .map(Object.class::cast) + .toList(); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 0210a5708dc..375525b1a1f 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -242,6 +242,12 @@ public interface GraphQLBookingTime { public DataFetcher time(); } + /** + * Call is a visit to a location (a stop or an area) in a trip on service date. It can contain + * exact arrival and departure times and/or a scheduled time window. + */ + public interface GraphQLCall extends TypeResolver {} + /** Real-time estimates for an arrival or departure at a certain place. */ public interface GraphQLCallRealTimeEstimate { public DataFetcher delay(); @@ -259,9 +265,6 @@ public interface GraphQLCallTime { public DataFetcher scheduledTime(); } - /** An instance of a trip, which can be cancelled, on a service date. */ - public interface GraphQLCancellableTripOnServiceDate extends TypeResolver {} - /** Car park represents a location where cars can be parked. */ public interface GraphQLCarPark { public DataFetcher carParkId(); @@ -1065,7 +1068,7 @@ public interface GraphQLStop { /** * Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. - * This can include real-time estimates. + * The times are exact (although can be changed by real-time updates), not time windows. */ public interface GraphQLStopCall { public DataFetcher arrival(); @@ -1241,15 +1244,15 @@ public interface GraphQLTripOccupancy { public DataFetcher occupancyStatus(); } - /** A regular (i.e. not flexible) trip on a specific service date */ + /** A trip on a specific service date. */ public interface GraphQLTripOnServiceDate { - public DataFetcher end(); + public DataFetcher end(); public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); - public DataFetcher> stopCalls(); + public DataFetcher> stopCalls(); public DataFetcher trip(); } @@ -1271,7 +1274,7 @@ public interface GraphQLTripOnServiceDateConnection { public interface GraphQLTripOnServiceDateEdge { public DataFetcher cursor(); - public DataFetcher node(); + public DataFetcher node(); } /** This is used for alert entities that we don't explicitly handle or they are missing. */ diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 15a877e3ed4..b3152a71dd4 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -73,8 +73,11 @@ interface PlaceInterface { "Entity related to an alert" union AlertEntity = Agency | Pattern | Route | RouteType | Stop | StopOnRoute | StopOnTrip | Trip | Unknown -"An instance of a trip, which can be cancelled, on a service date." -union CancellableTripOnServiceDate = TripOnServiceDate +""" +Call is a visit to a location (a stop or an area) in a trip on service date. It can contain +exact arrival and departure times and/or a scheduled time window. +""" +union Call = StopCall union StopPosition = PositionAtStop | PositionBetweenStops @@ -2184,7 +2187,7 @@ type Stop implements Node & PlaceInterface { """ Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. -This can include real-time estimates. +The times are exact (although can be changed by real-time updates), not time windows. """ type StopCall { "Scheduled arrival time to the stop and a real-time estimate, if one exists." @@ -2450,10 +2453,10 @@ type TripOccupancy { occupancyStatus: OccupancyStatus } -"A regular (i.e. not flexible) trip on a specific service date" +"A trip on a specific service date." type TripOnServiceDate { "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." - end: StopCall! + end: Call! """ The service date when the trip occurs. @@ -2463,9 +2466,9 @@ type TripOnServiceDate { """ serviceDate: LocalDate! "Information related to trip's scheduled departure from the first stop. Can contain realtime information." - start: StopCall! + start: Call! "List of times when this trip arrives to or departs from a stop and information related to the stop" - stopCalls: [StopCall!]! + stopCalls: [Call!]! "This trip on service date is an instance of this trip." trip: Trip } @@ -2501,7 +2504,7 @@ type TripOnServiceDateEdge { Trip on a service date as a node. Part of the [GraphQL Cursor Connections Specification](https://relay.dev/graphql/connections.htm). """ - node: CancellableTripOnServiceDate + node: TripOnServiceDate } "This is used for alert entities that we don't explicitly handle or they are missing." diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index cf767d81f10..b3817605f37 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -8,9 +8,9 @@ } edges { node { - ... on TripOnServiceDate { - serviceDate - end { + serviceDate + end { + ... on StopCall { arrival { estimated { delay @@ -19,7 +19,9 @@ scheduledTime } } - start { + } + start { + ... on StopCall { departure { estimated { delay @@ -28,7 +30,9 @@ scheduledTime } } - stopCalls { + } + stopCalls { + ... on StopCall { stop { gtfsId } @@ -47,9 +51,9 @@ } } } - trip { - gtfsId - } + } + trip { + gtfsId } } } From de5758b7b502168df8e882c602d6553d145b3be0 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Nov 2024 12:39:34 +0100 Subject: [PATCH 42/48] Add module test for listing canceled trips --- .../cancellation/CanceledTripTest.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 application/src/test/java/org/opentripplanner/updater/trip/moduletests/cancellation/CanceledTripTest.java diff --git a/application/src/test/java/org/opentripplanner/updater/trip/moduletests/cancellation/CanceledTripTest.java b/application/src/test/java/org/opentripplanner/updater/trip/moduletests/cancellation/CanceledTripTest.java new file mode 100644 index 00000000000..75c8d5caa46 --- /dev/null +++ b/application/src/test/java/org/opentripplanner/updater/trip/moduletests/cancellation/CanceledTripTest.java @@ -0,0 +1,41 @@ +package org.opentripplanner.updater.trip.moduletests.cancellation; + +import static com.google.common.truth.Truth.assertThat; +import static com.google.transit.realtime.GtfsRealtime.TripDescriptor.ScheduleRelationship.CANCELED; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opentripplanner.transit.model._data.TimetableRepositoryForTest.id; +import static org.opentripplanner.updater.spi.UpdateResultAssertions.assertSuccess; + +import org.junit.jupiter.api.Test; +import org.opentripplanner.updater.trip.RealtimeTestConstants; +import org.opentripplanner.updater.trip.RealtimeTestEnvironment; +import org.opentripplanner.updater.trip.TripInput; +import org.opentripplanner.updater.trip.TripUpdateBuilder; + +public class CanceledTripTest implements RealtimeTestConstants { + + @Test + void listCanceledTrips() { + var env = RealtimeTestEnvironment + .gtfs() + .addTrip( + TripInput + .of(TRIP_1_ID) + .addStop(STOP_A1, "0:00:10", "0:00:11") + .addStop(STOP_B1, "0:00:20", "0:00:21") + .build() + ) + .build(); + + assertThat(env.getTransitService().listCanceledTrips()).isEmpty(); + + var update = new TripUpdateBuilder(TRIP_1_ID, SERVICE_DATE, CANCELED, TIME_ZONE).build(); + assertSuccess(env.applyTripUpdate(update)); + + var canceled = env.getTransitService().listCanceledTrips(); + assertThat(canceled).hasSize(1); + var trip = canceled.getFirst(); + assertEquals(id(TRIP_1_ID), trip.getTrip().getId()); + assertEquals(SERVICE_DATE, trip.getServiceDate()); + } +} From e6c003678c86007917c460e17431c7e03ac1daf8 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 25 Nov 2024 13:12:51 +0100 Subject: [PATCH 43/48] Remove duplication --- .../datafetchers/TripOnServiceDateImpl.java | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java index b85f63a9d17..ad419f0c228 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java @@ -26,55 +26,49 @@ public DataFetcher serviceDate() { @Override public DataFetcher end() { return environment -> { - TransitService transitService = getTransitService(environment); - Trip trip = getTrip(environment); - var serviceDate = getSource(environment).getServiceDate(); - - Instant midnight = ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); - Timetable timetable = getTimetable(environment, trip, serviceDate); - if (timetable == null) { + final Result result = getResult(environment); + if (result.timetable() == null) { return null; } - return TripTimeOnDate.lastFromTripTimes(timetable, trip, serviceDate, midnight); + return TripTimeOnDate.lastFromTripTimes(result.timetable(), result.trip(), result.serviceDate(), result.midnight()); }; } + private Result getResult(DataFetchingEnvironment environment) { + TransitService transitService = getTransitService(environment); + Trip trip = getTrip(environment); + var serviceDate = getSource(environment).getServiceDate(); + + Instant midnight = ServiceDateUtils + .asStartOfService(serviceDate, transitService.getTimeZone()) + .toInstant(); + Timetable timetable = getTimetable(environment, trip, serviceDate); + return new Result(trip, serviceDate, midnight, timetable); + } + + private record Result(Trip trip, LocalDate serviceDate, Instant midnight, @Nullable Timetable timetable) { + } + @Override public DataFetcher start() { return environment -> { - TransitService transitService = getTransitService(environment); - Trip trip = getTrip(environment); - var serviceDate = getSource(environment).getServiceDate(); - - Instant midnight = ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); - Timetable timetable = getTimetable(environment, trip, serviceDate); - if (timetable == null) { + var result = getResult(environment); + if (result.timetable() == null) { return null; } - return TripTimeOnDate.firstFromTripTimes(timetable, trip, serviceDate, midnight); + return TripTimeOnDate.firstFromTripTimes(result.timetable, result.trip, result.serviceDate, result.midnight); }; } @Override public DataFetcher> stopCalls() { return environment -> { - TransitService transitService = getTransitService(environment); - Trip trip = getTrip(environment); - var serviceDate = getSource(environment).getServiceDate(); - - Instant midnight = ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); - Timetable timetable = getTimetable(environment, trip, serviceDate); - if (timetable == null) { + var result = getResult(environment); + if (result.timetable == null) { return List.of(); } return TripTimeOnDate - .fromTripTimes(timetable, trip, serviceDate, midnight) + .fromTripTimes(result.timetable, result.trip, result.serviceDate, result.midnight) .stream() .map(Object.class::cast) .toList(); From bee85dee2f4991da17b4b07788fda9ae79f4c0da Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 25 Nov 2024 14:47:06 +0200 Subject: [PATCH 44/48] Renaming or ordering --- .../datafetchers/TripOnServiceDateImpl.java | 67 ++++++++++++------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java index ad419f0c228..aae18085cc1 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java @@ -26,49 +26,49 @@ public DataFetcher serviceDate() { @Override public DataFetcher end() { return environment -> { - final Result result = getResult(environment); - if (result.timetable() == null) { + var arguments = getFromTripTimesArguments(environment); + if (arguments.timetable() == null) { return null; } - return TripTimeOnDate.lastFromTripTimes(result.timetable(), result.trip(), result.serviceDate(), result.midnight()); + return TripTimeOnDate.lastFromTripTimes( + arguments.timetable(), + arguments.trip(), + arguments.serviceDate(), + arguments.midnight() + ); }; } - private Result getResult(DataFetchingEnvironment environment) { - TransitService transitService = getTransitService(environment); - Trip trip = getTrip(environment); - var serviceDate = getSource(environment).getServiceDate(); - - Instant midnight = ServiceDateUtils - .asStartOfService(serviceDate, transitService.getTimeZone()) - .toInstant(); - Timetable timetable = getTimetable(environment, trip, serviceDate); - return new Result(trip, serviceDate, midnight, timetable); - } - - private record Result(Trip trip, LocalDate serviceDate, Instant midnight, @Nullable Timetable timetable) { - } - @Override public DataFetcher start() { return environment -> { - var result = getResult(environment); - if (result.timetable() == null) { + var arguments = getFromTripTimesArguments(environment); + if (arguments.timetable() == null) { return null; } - return TripTimeOnDate.firstFromTripTimes(result.timetable, result.trip, result.serviceDate, result.midnight); + return TripTimeOnDate.firstFromTripTimes( + arguments.timetable(), + arguments.trip(), + arguments.serviceDate(), + arguments.midnight() + ); }; } @Override public DataFetcher> stopCalls() { return environment -> { - var result = getResult(environment); - if (result.timetable == null) { + var arguments = getFromTripTimesArguments(environment); + if (arguments.timetable() == null) { return List.of(); } return TripTimeOnDate - .fromTripTimes(result.timetable, result.trip, result.serviceDate, result.midnight) + .fromTripTimes( + arguments.timetable(), + arguments.trip(), + arguments.serviceDate(), + arguments.midnight() + ) .stream() .map(Object.class::cast) .toList(); @@ -107,4 +107,23 @@ private Trip getTrip(DataFetchingEnvironment environment) { private TripOnServiceDate getSource(DataFetchingEnvironment environment) { return environment.getSource(); } + + private FromTripTimesArguments getFromTripTimesArguments(DataFetchingEnvironment environment) { + TransitService transitService = getTransitService(environment); + Trip trip = getTrip(environment); + var serviceDate = getSource(environment).getServiceDate(); + + Instant midnight = ServiceDateUtils + .asStartOfService(serviceDate, transitService.getTimeZone()) + .toInstant(); + Timetable timetable = getTimetable(environment, trip, serviceDate); + return new FromTripTimesArguments(trip, serviceDate, midnight, timetable); + } + + private record FromTripTimesArguments( + Trip trip, + LocalDate serviceDate, + Instant midnight, + @Nullable Timetable timetable + ) {} } From dba65b0cbb564e0b703e1fe732522e1475f76024 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Tue, 26 Nov 2024 11:47:26 +0200 Subject: [PATCH 45/48] Update application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index fb8baa0eb9a..d7e540e1a1b 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -323,7 +323,7 @@ type CallTime { "The estimated time of the event. If no real-time information is available, this is null." estimated: CallRealTimeEstimate "The scheduled time of the event." - scheduledTime: OffsetDateTime! + scheduledTime: OffsetDateTime } "Car park represents a location where cars can be parked." From b3bad269596f10f452c4e8a208f34b2ea10cd407 Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 2 Dec 2024 10:24:07 +0200 Subject: [PATCH 46/48] Implement new schema design --- .../apis/gtfs/GtfsGraphQLIndex.java | 12 +- .../CallScheduledTimeTypeResolver.java | 21 +++ ...java => CallStopLocationTypeResolver.java} | 8 +- .../apis/gtfs/datafetchers/CallTimeImpl.java | 25 --- ...timateImpl.java => EstimatedTimeImpl.java} | 6 +- .../apis/gtfs/datafetchers/StopCallImpl.java | 41 +++-- .../datafetchers/TripOnServiceDateImpl.java | 22 +-- .../gtfs/generated/GraphQLDataFetchers.java | 65 ++++---- .../apis/gtfs/generated/graphql-codegen.yml | 5 +- .../apis/gtfs/model/ArrivalDepartureTime.java | 9 + .../apis/gtfs/model/CallRealTime.java | 6 + .../apis/gtfs/model/CallSchedule.java | 3 + .../transit/model/timetable/CallTime.java | 40 ----- ...alTimeEstimate.java => EstimatedTime.java} | 9 +- .../opentripplanner/apis/gtfs/schema.graphqls | 86 +++++----- .../gtfs/expectations/canceled-trips.json | 154 ++++++++++-------- .../apis/gtfs/queries/canceled-trips.graphql | 72 +++++--- 17 files changed, 313 insertions(+), 271 deletions(-) create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallScheduledTimeTypeResolver.java rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{CallTypeResolver.java => CallStopLocationTypeResolver.java} (66%) delete mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java rename application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/{CallRealTimeEstimateImpl.java => EstimatedTimeImpl.java} (69%) create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/model/CallRealTime.java create mode 100644 application/src/main/java/org/opentripplanner/apis/gtfs/model/CallSchedule.java delete mode 100644 application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java rename application/src/main/java/org/opentripplanner/transit/model/timetable/{CallRealTimeEstimate.java => EstimatedTime.java} (69%) diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 28194b21856..302458ac656 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -31,15 +31,15 @@ import org.opentripplanner.apis.gtfs.datafetchers.BikeRentalStationImpl; import org.opentripplanner.apis.gtfs.datafetchers.BookingInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.BookingTimeImpl; -import org.opentripplanner.apis.gtfs.datafetchers.CallRealTimeEstimateImpl; -import org.opentripplanner.apis.gtfs.datafetchers.CallTimeImpl; -import org.opentripplanner.apis.gtfs.datafetchers.CallTypeResolver; +import org.opentripplanner.apis.gtfs.datafetchers.CallScheduledTimeTypeResolver; +import org.opentripplanner.apis.gtfs.datafetchers.CallStopLocationTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.CarParkImpl; import org.opentripplanner.apis.gtfs.datafetchers.ContactInfoImpl; import org.opentripplanner.apis.gtfs.datafetchers.CoordinatesImpl; import org.opentripplanner.apis.gtfs.datafetchers.CurrencyImpl; import org.opentripplanner.apis.gtfs.datafetchers.DefaultFareProductImpl; import org.opentripplanner.apis.gtfs.datafetchers.DepartureRowImpl; +import org.opentripplanner.apis.gtfs.datafetchers.EstimatedTimeImpl; import org.opentripplanner.apis.gtfs.datafetchers.FareProductTypeResolver; import org.opentripplanner.apis.gtfs.datafetchers.FareProductUseImpl; import org.opentripplanner.apis.gtfs.datafetchers.FeedImpl; @@ -135,7 +135,8 @@ protected static GraphQLSchema buildSchema() { .type("StopPosition", type -> type.typeResolver(new StopPosition() {})) .type("FareProduct", type -> type.typeResolver(new FareProductTypeResolver())) .type("AlertEntity", type -> type.typeResolver(new AlertEntityTypeResolver())) - .type("Call", type -> type.typeResolver(new CallTypeResolver())) + .type("CallStopLocation", type -> type.typeResolver(new CallStopLocationTypeResolver())) + .type("CallScheduledTime", type -> type.typeResolver(new CallScheduledTimeTypeResolver())) .type(typeWiring.build(AgencyImpl.class)) .type(typeWiring.build(AlertImpl.class)) .type(typeWiring.build(BikeParkImpl.class)) @@ -193,8 +194,7 @@ protected static GraphQLSchema buildSchema() { .type(typeWiring.build(TripOccupancyImpl.class)) .type(typeWiring.build(LegTimeImpl.class)) .type(typeWiring.build(RealTimeEstimateImpl.class)) - .type(typeWiring.build(CallTimeImpl.class)) - .type(typeWiring.build(CallRealTimeEstimateImpl.class)) + .type(typeWiring.build(EstimatedTimeImpl.class)) .build(); SchemaGenerator schemaGenerator = new SchemaGenerator(); return schemaGenerator.makeExecutableSchema(typeRegistry, runtimeWiring); diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallScheduledTimeTypeResolver.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallScheduledTimeTypeResolver.java new file mode 100644 index 00000000000..ac45b3766b6 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallScheduledTimeTypeResolver.java @@ -0,0 +1,21 @@ +package org.opentripplanner.apis.gtfs.datafetchers; + +import graphql.TypeResolutionEnvironment; +import graphql.schema.GraphQLObjectType; +import graphql.schema.GraphQLSchema; +import graphql.schema.TypeResolver; +import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; + +public class CallScheduledTimeTypeResolver implements TypeResolver { + + @Override + public GraphQLObjectType getType(TypeResolutionEnvironment environment) { + Object o = environment.getObject(); + GraphQLSchema schema = environment.getSchema(); + + if (o instanceof ArrivalDepartureTime) { + return schema.getObjectType("ArrivalDepartureTime"); + } + return null; + } +} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTypeResolver.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallStopLocationTypeResolver.java similarity index 66% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTypeResolver.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallStopLocationTypeResolver.java index 02ee6784073..5a7b02320a3 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTypeResolver.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallStopLocationTypeResolver.java @@ -4,17 +4,17 @@ import graphql.schema.GraphQLObjectType; import graphql.schema.GraphQLSchema; import graphql.schema.TypeResolver; -import org.opentripplanner.model.TripTimeOnDate; +import org.opentripplanner.transit.model.site.StopLocation; -public class CallTypeResolver implements TypeResolver { +public class CallStopLocationTypeResolver implements TypeResolver { @Override public GraphQLObjectType getType(TypeResolutionEnvironment environment) { Object o = environment.getObject(); GraphQLSchema schema = environment.getSchema(); - if (o instanceof TripTimeOnDate) { - return schema.getObjectType("StopCall"); + if (o instanceof StopLocation) { + return schema.getObjectType("Stop"); } return null; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java deleted file mode 100644 index 5a2da2c2d82..00000000000 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallTimeImpl.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.opentripplanner.apis.gtfs.datafetchers; - -import graphql.schema.DataFetcher; -import graphql.schema.DataFetchingEnvironment; -import java.time.OffsetDateTime; -import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.transit.model.timetable.CallRealTimeEstimate; -import org.opentripplanner.transit.model.timetable.CallTime; - -public class CallTimeImpl implements GraphQLDataFetchers.GraphQLCallTime { - - @Override - public DataFetcher estimated() { - return environment -> getSource(environment).estimated(); - } - - @Override - public DataFetcher scheduledTime() { - return environment -> getSource(environment).scheduledTime().toOffsetDateTime(); - } - - private CallTime getSource(DataFetchingEnvironment environment) { - return environment.getSource(); - } -} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallRealTimeEstimateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/EstimatedTimeImpl.java similarity index 69% rename from application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallRealTimeEstimateImpl.java rename to application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/EstimatedTimeImpl.java index 09439c6e916..eebb64ee625 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/CallRealTimeEstimateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/EstimatedTimeImpl.java @@ -5,9 +5,9 @@ import java.time.Duration; import java.time.OffsetDateTime; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; -import org.opentripplanner.transit.model.timetable.CallRealTimeEstimate; +import org.opentripplanner.transit.model.timetable.EstimatedTime; -public class CallRealTimeEstimateImpl implements GraphQLDataFetchers.GraphQLCallRealTimeEstimate { +public class EstimatedTimeImpl implements GraphQLDataFetchers.GraphQLEstimatedTime { @Override public DataFetcher delay() { @@ -19,7 +19,7 @@ public DataFetcher time() { return environment -> getSource(environment).time().toOffsetDateTime(); } - private CallRealTimeEstimate getSource(DataFetchingEnvironment environment) { + private EstimatedTime getSource(DataFetchingEnvironment environment) { return environment.getSource(); } } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopCallImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopCallImpl.java index cb5ec7e15a5..4d3ede74c76 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopCallImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StopCallImpl.java @@ -7,43 +7,52 @@ import java.time.ZonedDateTime; import org.opentripplanner.apis.gtfs.GraphQLRequestContext; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; +import org.opentripplanner.apis.gtfs.model.ArrivalDepartureTime; +import org.opentripplanner.apis.gtfs.model.CallRealTime; +import org.opentripplanner.apis.gtfs.model.CallSchedule; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.transit.model.timetable.CallTime; +import org.opentripplanner.transit.model.timetable.EstimatedTime; import org.opentripplanner.transit.service.TransitService; import org.opentripplanner.utils.time.ServiceDateUtils; public class StopCallImpl implements GraphQLDataFetchers.GraphQLStopCall { @Override - public DataFetcher arrival() { + public DataFetcher realTime() { return environment -> { var tripTime = getSource(environment); - var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledArrival()); - if (scheduledTime == null) { + if (!tripTime.isRealtime()) { return null; } - return tripTime.isRealtime() - ? CallTime.of(scheduledTime, tripTime.getArrivalDelay()) - : CallTime.ofStatic(scheduledTime); + var scheduledArrival = getZonedDateTime(environment, tripTime.getScheduledArrival()); + var estimatedArrival = scheduledArrival == null + ? null + : EstimatedTime.of(scheduledArrival, tripTime.getArrivalDelay()); + var scheduledDeparture = getZonedDateTime(environment, tripTime.getScheduledDeparture()); + var estimatedDeparture = scheduledDeparture == null + ? null + : EstimatedTime.of(scheduledDeparture, tripTime.getDepartureDelay()); + return new CallRealTime(estimatedArrival, estimatedDeparture); }; } @Override - public DataFetcher departure() { + public DataFetcher schedule() { return environment -> { var tripTime = getSource(environment); - var scheduledTime = getZonedDateTime(environment, tripTime.getScheduledDeparture()); - if (scheduledTime == null) { - return null; - } - return tripTime.isRealtime() - ? CallTime.of(scheduledTime, tripTime.getDepartureDelay()) - : CallTime.ofStatic(scheduledTime); + var scheduledArrival = getZonedDateTime(environment, tripTime.getScheduledArrival()); + var scheduledDeparture = getZonedDateTime(environment, tripTime.getScheduledDeparture()); + return new CallSchedule( + new ArrivalDepartureTime( + scheduledArrival == null ? null : scheduledArrival.toOffsetDateTime(), + scheduledDeparture == null ? null : scheduledDeparture.toOffsetDateTime() + ) + ); }; } @Override - public DataFetcher stop() { + public DataFetcher stopLocation() { return environment -> getSource(environment).getStop(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java index aae18085cc1..3b00551835e 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/TripOnServiceDateImpl.java @@ -24,7 +24,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> { var arguments = getFromTripTimesArguments(environment); if (arguments.timetable() == null) { @@ -40,7 +40,7 @@ public DataFetcher end() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> { var arguments = getFromTripTimesArguments(environment); if (arguments.timetable() == null) { @@ -56,22 +56,18 @@ public DataFetcher start() { } @Override - public DataFetcher> stopCalls() { + public DataFetcher> stopCalls() { return environment -> { var arguments = getFromTripTimesArguments(environment); if (arguments.timetable() == null) { return List.of(); } - return TripTimeOnDate - .fromTripTimes( - arguments.timetable(), - arguments.trip(), - arguments.serviceDate(), - arguments.midnight() - ) - .stream() - .map(Object.class::cast) - .toList(); + return TripTimeOnDate.fromTripTimes( + arguments.timetable(), + arguments.trip(), + arguments.serviceDate(), + arguments.midnight() + ); }; } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java index 986fb9b8318..fb3c0ddbb41 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -23,6 +23,8 @@ import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRelativeDirection; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLRoutingErrorCode; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode; +import org.opentripplanner.apis.gtfs.model.CallRealTime; +import org.opentripplanner.apis.gtfs.model.CallSchedule; import org.opentripplanner.apis.gtfs.model.FeedPublisher; import org.opentripplanner.apis.gtfs.model.PlanPageInfo; import org.opentripplanner.apis.gtfs.model.RideHailingProvider; @@ -67,8 +69,7 @@ import org.opentripplanner.transit.model.network.Route; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.organization.Agency; -import org.opentripplanner.transit.model.timetable.CallRealTimeEstimate; -import org.opentripplanner.transit.model.timetable.CallTime; +import org.opentripplanner.transit.model.timetable.EstimatedTime; import org.opentripplanner.transit.model.timetable.Trip; import org.opentripplanner.transit.model.timetable.TripOnServiceDate; import org.opentripplanner.transit.model.timetable.booking.BookingInfo; @@ -145,6 +146,13 @@ public interface GraphQLAlert { /** Entity related to an alert */ public interface GraphQLAlertEntity extends TypeResolver {} + /** Arrival and departure time (not relative to midnight). */ + public interface GraphQLArrivalDepartureTime { + public DataFetcher arrival(); + + public DataFetcher departure(); + } + /** Bike park represents a location where bicycles can be parked. */ public interface GraphQLBikePark { public DataFetcher bikeParkId(); @@ -242,28 +250,23 @@ public interface GraphQLBookingTime { public DataFetcher time(); } - /** - * Call is a visit to a location (a stop or an area) in a trip on service date. It can contain - * exact arrival and departure times and/or a scheduled time window. - */ - public interface GraphQLCall extends TypeResolver {} + /** Real-time estimates for arrival and departure times for a stop location. */ + public interface GraphQLCallRealTime { + public DataFetcher arrival(); - /** Real-time estimates for an arrival or departure at a certain place. */ - public interface GraphQLCallRealTimeEstimate { - public DataFetcher delay(); + public DataFetcher departure(); + } - public DataFetcher time(); + /** What is scheduled for a trip on a service date for a stop location. */ + public interface GraphQLCallSchedule { + public DataFetcher time(); } - /** - * Timing of an arrival or a departure to or from a stop. May contain real-time information if - * available. This is used when there is a known scheduled time. - */ - public interface GraphQLCallTime { - public DataFetcher estimated(); + /** Scheduled times for a trip on a service date for a stop location. */ + public interface GraphQLCallScheduledTime extends TypeResolver {} - public DataFetcher scheduledTime(); - } + /** Location where a transit vehicle stops at. */ + public interface GraphQLCallStopLocation extends TypeResolver {} /** Car park represents a location where cars can be parked. */ public interface GraphQLCarPark { @@ -385,6 +388,13 @@ public interface GraphQLEmissions { public DataFetcher co2(); } + /** Real-time estimates for an arrival or departure at a certain place. */ + public interface GraphQLEstimatedTime { + public DataFetcher delay(); + + public DataFetcher time(); + } + /** A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'. */ public interface GraphQLFareMedium { public DataFetcher id(); @@ -1073,16 +1083,13 @@ public interface GraphQLStop { public DataFetcher zoneId(); } - /** - * Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. - * The times are exact (although can be changed by real-time updates), not time windows. - */ + /** Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop location. */ public interface GraphQLStopCall { - public DataFetcher arrival(); + public DataFetcher realTime(); - public DataFetcher departure(); + public DataFetcher schedule(); - public DataFetcher stop(); + public DataFetcher stopLocation(); } public interface GraphQLStopGeometries { @@ -1253,13 +1260,13 @@ public interface GraphQLTripOccupancy { /** A trip on a specific service date. */ public interface GraphQLTripOnServiceDate { - public DataFetcher end(); + public DataFetcher end(); public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); - public DataFetcher> stopCalls(); + public DataFetcher> stopCalls(); public DataFetcher trip(); } diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml index 117744d314a..a12f9ff2c64 100644 --- a/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/generated/graphql-codegen.yml @@ -63,7 +63,6 @@ config: TripOnServiceDate: org.opentripplanner.transit.model.timetable.TripOnServiceDate#TripOnServiceDate TripOnServiceDateConnection: graphql.relay.Connection#Connection TripOnServiceDateEdge: graphql.relay.Edge#Edge - CallTime: org.opentripplanner.transit.model.timetable.CallTime#CallTime debugOutput: org.opentripplanner.api.resource.DebugOutput#DebugOutput DepartureRow: org.opentripplanner.routing.graphfinder.PatternAtStop#PatternAtStop elevationProfileComponent: org.opentripplanner.model.plan.ElevationProfile.Step @@ -131,6 +130,8 @@ config: RiderCategory: org.opentripplanner.model.fare.RiderCategory#RiderCategory StopPosition: org.opentripplanner.apis.gtfs.model.StopPosition#StopPosition RealTimeEstimate: org.opentripplanner.model.plan.LegRealTimeEstimate#LegRealTimeEstimate - CallRealTimeEstimate: org.opentripplanner.transit.model.timetable.CallRealTimeEstimate#CallRealTimeEstimate + EstimatedTime: org.opentripplanner.transit.model.timetable.EstimatedTime#EstimatedTime + CallRealTime: org.opentripplanner.apis.gtfs.model.CallRealTime#CallRealTime RentalPlace: org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace#VehicleRentalPlace + CallSchedule: org.opentripplanner.apis.gtfs.model.CallSchedule#CallSchedule diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java b/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java new file mode 100644 index 00000000000..f72bdd0b3e9 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/model/ArrivalDepartureTime.java @@ -0,0 +1,9 @@ +package org.opentripplanner.apis.gtfs.model; + +import java.time.OffsetDateTime; +import javax.annotation.Nullable; + +public record ArrivalDepartureTime( + @Nullable OffsetDateTime arrival, + @Nullable OffsetDateTime departure +) {} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/model/CallRealTime.java b/application/src/main/java/org/opentripplanner/apis/gtfs/model/CallRealTime.java new file mode 100644 index 00000000000..94caf731627 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/model/CallRealTime.java @@ -0,0 +1,6 @@ +package org.opentripplanner.apis.gtfs.model; + +import javax.annotation.Nullable; +import org.opentripplanner.transit.model.timetable.EstimatedTime; + +public record CallRealTime(@Nullable EstimatedTime arrival, @Nullable EstimatedTime departure) {} diff --git a/application/src/main/java/org/opentripplanner/apis/gtfs/model/CallSchedule.java b/application/src/main/java/org/opentripplanner/apis/gtfs/model/CallSchedule.java new file mode 100644 index 00000000000..6b35d2ed425 --- /dev/null +++ b/application/src/main/java/org/opentripplanner/apis/gtfs/model/CallSchedule.java @@ -0,0 +1,3 @@ +package org.opentripplanner.apis.gtfs.model; + +public record CallSchedule(ArrivalDepartureTime time) {} diff --git a/application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java b/application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java deleted file mode 100644 index 4a7df9fb217..00000000000 --- a/application/src/main/java/org/opentripplanner/transit/model/timetable/CallTime.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.opentripplanner.transit.model.timetable; - -import java.time.Duration; -import java.time.ZonedDateTime; -import java.util.Objects; -import javax.annotation.Nullable; - -/** - * A scheduled time of a transit vehicle at a certain location with an optional realtime - * information. This is meant to be used in timetables (not in transit legs). - */ -public class CallTime { - - private final ZonedDateTime scheduledTime; - - @Nullable - private final CallRealTimeEstimate estimated; - - private CallTime(ZonedDateTime scheduledTime, @Nullable CallRealTimeEstimate estimated) { - this.scheduledTime = Objects.requireNonNull(scheduledTime); - this.estimated = estimated; - } - - public static CallTime of(ZonedDateTime realtime, int delaySecs) { - var delay = Duration.ofSeconds(delaySecs); - return new CallTime(realtime.minus(delay), new CallRealTimeEstimate(realtime, delay)); - } - - public static CallTime ofStatic(ZonedDateTime staticTime) { - return new CallTime(staticTime, null); - } - - public ZonedDateTime scheduledTime() { - return scheduledTime; - } - - public CallRealTimeEstimate estimated() { - return estimated; - } -} diff --git a/application/src/main/java/org/opentripplanner/transit/model/timetable/CallRealTimeEstimate.java b/application/src/main/java/org/opentripplanner/transit/model/timetable/EstimatedTime.java similarity index 69% rename from application/src/main/java/org/opentripplanner/transit/model/timetable/CallRealTimeEstimate.java rename to application/src/main/java/org/opentripplanner/transit/model/timetable/EstimatedTime.java index eeac4a321c4..359a8c7de6a 100644 --- a/application/src/main/java/org/opentripplanner/transit/model/timetable/CallRealTimeEstimate.java +++ b/application/src/main/java/org/opentripplanner/transit/model/timetable/EstimatedTime.java @@ -8,7 +8,7 @@ * Realtime information about a vehicle at a certain place. This is meant to be used in timetables * (not in transit legs). */ -public class CallRealTimeEstimate { +public class EstimatedTime { private final ZonedDateTime time; private final Duration delay; @@ -16,11 +16,16 @@ public class CallRealTimeEstimate { /** * @param delay Delay or "earliness" of a vehicle. Earliness is expressed as a negative number. */ - public CallRealTimeEstimate(ZonedDateTime time, Duration delay) { + private EstimatedTime(ZonedDateTime time, Duration delay) { this.time = Objects.requireNonNull(time); this.delay = Objects.requireNonNull(delay); } + public static EstimatedTime of(ZonedDateTime scheduledTime, int delaySecs) { + var delay = Duration.ofSeconds(delaySecs); + return new EstimatedTime(scheduledTime.minus(delay), delay); + } + public ZonedDateTime time() { return time; } diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index d7e540e1a1b..10aa3f8c524 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -73,11 +73,11 @@ interface PlaceInterface { "Entity related to an alert" union AlertEntity = Agency | Pattern | Route | RouteType | Stop | StopOnRoute | StopOnTrip | Trip | Unknown -""" -Call is a visit to a location (a stop or an area) in a trip on service date. It can contain -exact arrival and departure times and/or a scheduled time window. -""" -union Call = StopCall +"Scheduled times for a trip on a service date for a stop location." +union CallScheduledTime = ArrivalDepartureTime + +"Location where a transit vehicle stops at." +union CallStopLocation = Stop "Rental place union that represents either a VehicleRentalStation or a RentalVehicle" union RentalPlace = RentalVehicle | VehicleRentalStation @@ -172,6 +172,14 @@ type Alert implements Node { trip: Trip @deprecated(reason : "Alert can have multiple affected entities now instead of there being duplicate alerts\nfor different entities. This will return only one of the affected trips.\nUse entities instead.") } +"Arrival and departure time (not relative to midnight)." +type ArrivalDepartureTime { + "Arrival time as an ISO-8601-formatted datetime." + arrival: OffsetDateTime + "Departure time as an ISO-8601-formatted datetime." + departure: OffsetDateTime +} + "Bike park represents a location where bicycles can be parked." type BikePark implements Node & PlaceInterface { "ID of the bike park" @@ -303,27 +311,18 @@ type BookingTime { time: String } -"Real-time estimates for an arrival or departure at a certain place." -type CallRealTimeEstimate { - """ - The delay or "earliness" of the vehicle at a certain place. This estimate can change quite often. - - If the vehicle is early then this is a negative duration. - """ - delay: Duration! - "The estimate for a call event (such as arrival or departure) at a certain place. This estimate can change quite often." - time: OffsetDateTime! +"Real-time estimates for arrival and departure times for a stop location." +type CallRealTime { + "Real-time estimates for the arrival." + arrival: EstimatedTime + "Real-time estimates for the departure." + departure: EstimatedTime } -""" -Timing of an arrival or a departure to or from a stop. May contain real-time information if -available. This is used when there is a known scheduled time. -""" -type CallTime { - "The estimated time of the event. If no real-time information is available, this is null." - estimated: CallRealTimeEstimate - "The scheduled time of the event." - scheduledTime: OffsetDateTime +"What is scheduled for a trip on a service date for a stop location." +type CallSchedule { + "Scheduled time for a trip on a service date for a stop location." + time: CallScheduledTime } "Car park represents a location where cars can be parked." @@ -485,6 +484,18 @@ type Emissions { co2: Grams } +"Real-time estimates for an arrival or departure at a certain place." +type EstimatedTime { + """ + The delay or "earliness" of the vehicle at a certain place. This estimate can change quite often. + + If the vehicle is early then this is a negative duration. + """ + delay: Duration! + "The estimate for a call event (such as arrival or departure) at a certain place. This estimate can change quite often." + time: OffsetDateTime! +} + "A 'medium' that a fare product applies to, for example cash, 'Oyster Card' or 'DB Navigator App'." type FareMedium { "ID of the medium" @@ -2217,17 +2228,14 @@ type Stop implements Node & PlaceInterface { zoneId: String } -""" -Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop. -The times are exact (although can be changed by real-time updates), not time windows. -""" +"Stop call represents the time when a specific trip on a specific date arrives to and/or departs from a specific stop location." type StopCall { - "Scheduled arrival time to the stop and a real-time estimate, if one exists." - arrival: CallTime - "Scheduled departure time from the stop and a real-time estimate, if one exists." - departure: CallTime + "Real-time estimates for arrival and departure times for this stop location." + realTime: CallRealTime + "Scheduled arrival and departure times for this stop location." + schedule: CallSchedule "The stop where this arrival/departure happens" - stop: Stop + stopLocation: CallStopLocation! } type StopGeometries { @@ -2487,8 +2495,8 @@ type TripOccupancy { "A trip on a specific service date." type TripOnServiceDate { - "Information related to trip's scheduled arrival to the final stop. Can contain realtime information." - end: Call! + "Information related to trip's scheduled arrival to the final stop location. Can contain realtime information." + end: StopCall! """ The service date when the trip occurs. @@ -2497,10 +2505,10 @@ type TripOnServiceDate { on Sunday morning at 1am to 3am, might have the previous Saturday's service date. """ serviceDate: LocalDate! - "Information related to trip's scheduled departure from the first stop. Can contain realtime information." - start: Call! - "List of times when this trip arrives to or departs from a stop and information related to the stop" - stopCalls: [Call!]! + "Information related to trip's scheduled departure from the first stop location. Can contain realtime information." + start: StopCall! + "List of times when this trip arrives to or departs from a stop location and information related to the visit to the stop location." + stopCalls: [StopCall!]! "This trip on service date is an instance of this trip." trip: Trip } diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json index 5e32b67fc4e..1e2b4d39a3f 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/canceled-trips.json @@ -1,99 +1,119 @@ { - "data": { - "canceledTrips": { - "pageInfo": { - "hasNextPage": false, - "hasPreviousPage": false, - "startCursor": "c2ltcGxlLWN1cnNvcjA=", - "endCursor": "c2ltcGxlLWN1cnNvcjA=" + "data" : { + "canceledTrips" : { + "pageInfo" : { + "hasNextPage" : false, + "hasPreviousPage" : false, + "startCursor" : "c2ltcGxlLWN1cnNvcjA=", + "endCursor" : "c2ltcGxlLWN1cnNvcjA=" }, - "edges": [ + "edges" : [ { - "node": { - "serviceDate": "2024-08-09", - "end": { - "arrival": { - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:40:00+02:00" - }, - "scheduledTime": "2024-08-09T11:40:00+02:00" + "node" : { + "serviceDate" : "2024-08-09", + "end" : { + "schedule" : { + "time" : { + "arrival" : "2024-08-09T11:40:00+02:00" + } + }, + "realTime" : { + "arrival" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:40:00+02:00" + } + }, + "stopLocation" : { + "gtfsId" : "F:Stop_2" } }, - "start": { - "departure": { - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:30:00+02:00" - }, - "scheduledTime": "2024-08-09T11:30:00+02:00" + "start" : { + "schedule" : { + "time" : { + "departure" : "2024-08-09T11:30:00+02:00" + } + }, + "realTime" : { + "departure" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:30:00+02:00" + } + }, + "stopLocation" : { + "gtfsId" : "F:Stop_0" } }, - "stopCalls": [ + "stopCalls" : [ { - "stop": { - "gtfsId": "F:Stop_0" - }, - "arrival": { - "scheduledTime": "2024-08-09T11:30:00+02:00", - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:30:00+02:00" + "schedule" : { + "time" : { + "arrival" : "2024-08-09T11:30:00+02:00", + "departure" : "2024-08-09T11:30:00+02:00" } }, - "departure": { - "scheduledTime": "2024-08-09T11:30:00+02:00", - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:30:00+02:00" + "realTime" : { + "arrival" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:30:00+02:00" + }, + "departure" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:30:00+02:00" } + }, + "stopLocation" : { + "gtfsId" : "F:Stop_0" } }, { - "stop": { - "gtfsId": "F:Stop_1" - }, - "arrival": { - "scheduledTime": "2024-08-09T11:35:00+02:00", - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:35:00+02:00" + "schedule" : { + "time" : { + "arrival" : "2024-08-09T11:35:00+02:00", + "departure" : "2024-08-09T11:35:00+02:00" } }, - "departure": { - "scheduledTime": "2024-08-09T11:35:00+02:00", - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:35:00+02:00" + "realTime" : { + "arrival" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:35:00+02:00" + }, + "departure" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:35:00+02:00" } + }, + "stopLocation" : { + "gtfsId" : "F:Stop_1" } }, { - "stop": { - "gtfsId": "F:Stop_2" - }, - "arrival": { - "scheduledTime": "2024-08-09T11:40:00+02:00", - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:40:00+02:00" + "schedule" : { + "time" : { + "arrival" : "2024-08-09T11:40:00+02:00", + "departure" : "2024-08-09T11:40:00+02:00" } }, - "departure": { - "scheduledTime": "2024-08-09T11:40:00+02:00", - "estimated": { - "delay": "PT0S", - "time": "2024-08-09T11:40:00+02:00" + "realTime" : { + "arrival" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:40:00+02:00" + }, + "departure" : { + "delay" : "PT0S", + "time" : "2024-08-09T11:40:00+02:00" } + }, + "stopLocation" : { + "gtfsId" : "F:Stop_2" } } ], - "trip": { - "gtfsId": "F:321Canceled" + "trip" : { + "gtfsId" : "F:321Canceled" } } } ] } } -} +} \ No newline at end of file diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql index b3817605f37..988a1e62cd9 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/queries/canceled-trips.graphql @@ -10,45 +10,67 @@ node { serviceDate end { - ... on StopCall { - arrival { - estimated { - delay - time + schedule { + time { + ... on ArrivalDepartureTime { + arrival } - scheduledTime + } + } + realTime { + arrival { + delay + time + } + } + stopLocation { + ... on Stop { + gtfsId } } } start { - ... on StopCall { - departure { - estimated { - delay - time + schedule { + time { + ... on ArrivalDepartureTime { + departure } - scheduledTime + } + } + realTime { + departure { + delay + time + } + } + stopLocation { + ... on Stop { + gtfsId } } } stopCalls { - ... on StopCall { - stop { - gtfsId + schedule { + time { + ... on ArrivalDepartureTime { + arrival + departure + } } + } + realTime { arrival { - scheduledTime - estimated { - delay - time - } + delay + time } departure { - scheduledTime - estimated { - delay - time - } + delay + time + } + } + stopLocation { + ... on Stop { + gtfsId } } } From 6a485a35c7282c915be8e491af863be450cc787c Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 2 Dec 2024 11:05:02 +0200 Subject: [PATCH 47/48] Minor schema doc fixes --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 10aa3f8c524..04fd2220283 100644 --- a/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/application/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2234,7 +2234,7 @@ type StopCall { realTime: CallRealTime "Scheduled arrival and departure times for this stop location." schedule: CallSchedule - "The stop where this arrival/departure happens" + "The stop where this arrival/departure happens." stopLocation: CallStopLocation! } @@ -2495,7 +2495,7 @@ type TripOccupancy { "A trip on a specific service date." type TripOnServiceDate { - "Information related to trip's scheduled arrival to the final stop location. Can contain realtime information." + "Information related to trip's scheduled arrival to the final stop location. Can contain real-time information." end: StopCall! """ The service date when the trip occurs. @@ -2505,7 +2505,7 @@ type TripOnServiceDate { on Sunday morning at 1am to 3am, might have the previous Saturday's service date. """ serviceDate: LocalDate! - "Information related to trip's scheduled departure from the first stop location. Can contain realtime information." + "Information related to trip's scheduled departure from the first stop location. Can contain real-time information." start: StopCall! "List of times when this trip arrives to or departs from a stop location and information related to the visit to the stop location." stopCalls: [StopCall!]! From 5217ce51f2c66c978b33f1f71a89d8f54a41dcaa Mon Sep 17 00:00:00 2001 From: Joel Lappalainen Date: Mon, 2 Dec 2024 11:05:09 +0200 Subject: [PATCH 48/48] Formatting --- .../apis/gtfs/expectations/patterns.json | 208 +++++++++--------- 1 file changed, 104 insertions(+), 104 deletions(-) diff --git a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json index e9882981a13..4aac9295cc9 100644 --- a/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json +++ b/application/src/test/resources/org/opentripplanner/apis/gtfs/expectations/patterns.json @@ -1,145 +1,145 @@ { - "data" : { - "patterns" : [ + "data": { + "patterns": [ { - "code" : "F:BUS", - "headsign" : "Trip Headsign", - "trips" : [ + "code": "F:BUS", + "headsign": "Trip Headsign", + "trips": [ { - "gtfsId" : "F:123", - "stoptimes" : [ + "gtfsId": "F:123", + "stoptimes": [ { - "stop" : { - "gtfsId" : "F:Stop_0", - "name" : "Stop_0" + "stop": { + "gtfsId": "F:Stop_0", + "name": "Stop_0" }, - "headsign" : "Stop headsign at stop 10", - "scheduledArrival" : 39600, - "scheduledDeparture" : 39600, - "stopPosition" : 10, - "stopPositionInPattern" : 0, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 10", + "scheduledArrival": 39600, + "scheduledDeparture": 39600, + "stopPosition": 10, + "stopPositionInPattern": 0, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" }, { - "stop" : { - "gtfsId" : "F:Stop_1", - "name" : "Stop_1" + "stop": { + "gtfsId": "F:Stop_1", + "name": "Stop_1" }, - "headsign" : "Stop headsign at stop 20", - "scheduledArrival" : 39900, - "scheduledDeparture" : 39900, - "stopPosition" : 20, - "stopPositionInPattern" : 1, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 20", + "scheduledArrival": 39900, + "scheduledDeparture": 39900, + "stopPosition": 20, + "stopPositionInPattern": 1, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" }, { - "stop" : { - "gtfsId" : "F:Stop_2", - "name" : "Stop_2" + "stop": { + "gtfsId": "F:Stop_2", + "name": "Stop_2" }, - "headsign" : "Stop headsign at stop 30", - "scheduledArrival" : 40200, - "scheduledDeparture" : 40200, - "stopPosition" : 30, - "stopPositionInPattern" : 2, - "realtimeState" : "SCHEDULED", - "pickupType" : "SCHEDULED", - "dropoffType" : "SCHEDULED" + "headsign": "Stop headsign at stop 30", + "scheduledArrival": 40200, + "scheduledDeparture": 40200, + "stopPosition": 30, + "stopPositionInPattern": 2, + "realtimeState": "SCHEDULED", + "pickupType": "SCHEDULED", + "dropoffType": "SCHEDULED" } ], - "occupancy" : { - "occupancyStatus" : "FEW_SEATS_AVAILABLE" + "occupancy": { + "occupancyStatus": "FEW_SEATS_AVAILABLE" } }, { - "gtfsId" : "F:321Canceled", - "stoptimes" : [ + "gtfsId": "F:321Canceled", + "stoptimes": [ { - "stop" : { - "gtfsId" : "F:Stop_0", - "name" : "Stop_0" + "stop": { + "gtfsId": "F:Stop_0", + "name": "Stop_0" }, - "headsign" : "Stop headsign at stop 10", - "scheduledArrival" : 41400, - "scheduledDeparture" : 41400, - "stopPosition" : 10, - "stopPositionInPattern" : 0, - "realtimeState" : "CANCELED", - "pickupType" : null, - "dropoffType" : null + "headsign": "Stop headsign at stop 10", + "scheduledArrival": 41400, + "scheduledDeparture": 41400, + "stopPosition": 10, + "stopPositionInPattern": 0, + "realtimeState": "CANCELED", + "pickupType": null, + "dropoffType": null }, { - "stop" : { - "gtfsId" : "F:Stop_1", - "name" : "Stop_1" + "stop": { + "gtfsId": "F:Stop_1", + "name": "Stop_1" }, - "headsign" : "Stop headsign at stop 20", - "scheduledArrival" : 41700, - "scheduledDeparture" : 41700, - "stopPosition" : 20, - "stopPositionInPattern" : 1, - "realtimeState" : "CANCELED", - "pickupType" : null, - "dropoffType" : null + "headsign": "Stop headsign at stop 20", + "scheduledArrival": 41700, + "scheduledDeparture": 41700, + "stopPosition": 20, + "stopPositionInPattern": 1, + "realtimeState": "CANCELED", + "pickupType": null, + "dropoffType": null }, { - "stop" : { - "gtfsId" : "F:Stop_2", - "name" : "Stop_2" + "stop": { + "gtfsId": "F:Stop_2", + "name": "Stop_2" }, - "headsign" : "Stop headsign at stop 30", - "scheduledArrival" : 42000, - "scheduledDeparture" : 42000, - "stopPosition" : 30, - "stopPositionInPattern" : 2, - "realtimeState" : "CANCELED", - "pickupType" : null, - "dropoffType" : null + "headsign": "Stop headsign at stop 30", + "scheduledArrival": 42000, + "scheduledDeparture": 42000, + "stopPosition": 30, + "stopPositionInPattern": 2, + "realtimeState": "CANCELED", + "pickupType": null, + "dropoffType": null } ], - "occupancy" : { - "occupancyStatus" : "NO_DATA_AVAILABLE" + "occupancy": { + "occupancyStatus": "NO_DATA_AVAILABLE" } } ], - "vehiclePositions" : [ + "vehiclePositions": [ { - "vehicleId" : "F:vehicle-1", - "label" : null, - "lat" : null, - "lon" : null, - "stopRelationship" : null, - "speed" : null, - "heading" : null, - "lastUpdated" : 31556889864403199, - "trip" : { - "gtfsId" : "F:123" + "vehicleId": "F:vehicle-1", + "label": null, + "lat": null, + "lon": null, + "stopRelationship": null, + "speed": null, + "heading": null, + "lastUpdated": 31556889864403199, + "trip": { + "gtfsId": "F:123" } }, { - "vehicleId" : "F:vehicle-2", - "label" : "vehicle2", - "lat" : 60.0, - "lon" : 80.0, - "stopRelationship" : { - "status" : "IN_TRANSIT_TO", - "stop" : { - "gtfsId" : "F:Stop_0" + "vehicleId": "F:vehicle-2", + "label": "vehicle2", + "lat": 60.0, + "lon": 80.0, + "stopRelationship": { + "status": "IN_TRANSIT_TO", + "stop": { + "gtfsId": "F:Stop_0" } }, - "speed" : 10.2, - "heading" : 80.0, - "lastUpdated" : -31557014167219200, - "trip" : { - "gtfsId" : "F:123" + "speed": 10.2, + "heading": 80.0, + "lastUpdated": -31557014167219200, + "trip": { + "gtfsId": "F:123" } } ] } ] } -} \ No newline at end of file +}