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 3744868d275..1b3b2ceced0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLTypes.java @@ -1421,6 +1421,35 @@ public void setGraphQLTags(List tags) { } } + public static class GraphQLPassThroughLocationInput { + + private String label; + private String stopLocationId; + + public GraphQLPassThroughLocationInput(Map args) { + if (args != null) { + this.label = (String) args.get("label"); + this.stopLocationId = (String) args.get("stopLocationId"); + } + } + + public String getGraphQLLabel() { + return this.label; + } + + public String getGraphQLStopLocationId() { + return this.stopLocationId; + } + + public void setGraphQLLabel(String label) { + this.label = label; + } + + public void setGraphQLStopLocationId(String stopLocationId) { + this.stopLocationId = stopLocationId; + } + } + public static class GraphQLPatternAlertsArgs { private List types; @@ -2673,7 +2702,7 @@ public static class GraphQLQueryTypePlanArgs { private List transportModes; private GraphQLInputTriangleInput triangle; private GraphQLInputUnpreferredInput unpreferred; - private List viaPoints; + private List via; private Double waitAtBeginningFactor; private Double waitReluctance; private Integer walkBoardCost; @@ -2755,8 +2784,8 @@ public GraphQLQueryTypePlanArgs(Map args) { this.triangle = new GraphQLInputTriangleInput((Map) args.get("triangle")); this.unpreferred = new GraphQLInputUnpreferredInput((Map) args.get("unpreferred")); - if (args.get("viaPoints") != null) { - this.viaPoints = (List) args.get("viaPoints"); + if (args.get("via") != null) { + this.via = (List) args.get("via"); } this.waitAtBeginningFactor = (Double) args.get("waitAtBeginningFactor"); this.waitReluctance = (Double) args.get("waitReluctance"); @@ -2989,8 +3018,8 @@ public GraphQLInputUnpreferredInput getGraphQLUnpreferred() { return this.unpreferred; } - public List getGraphQLViaPoints() { - return this.viaPoints; + public List getGraphQLVia() { + return this.via; } public Double getGraphQLWaitAtBeginningFactor() { @@ -3251,8 +3280,8 @@ public void setGraphQLUnpreferred(GraphQLInputUnpreferredInput unpreferred) { this.unpreferred = unpreferred; } - public void setGraphQLViaPoints(List viaPoints) { - this.viaPoints = viaPoints; + public void setGraphQLVia(List via) { + this.via = via; } public void setGraphQLWaitAtBeginningFactor(Double waitAtBeginningFactor) { @@ -5075,49 +5104,23 @@ public enum GraphQLVertexType { public static class GraphQLViaLocationInput { - private List locationIds; + private GraphQLPassThroughLocationInput passThroughLocation; public GraphQLViaLocationInput(Map args) { if (args != null) { - this.locationIds = (List) args.get("locationIds"); - } - } - - public List getGraphQLLocationIds() { - return this.locationIds; - } - - public void setGraphQLLocationIds(List locationIds) { - this.locationIds = locationIds; - } - } - - public static class GraphQLViaPointInput { - - private String label; - private GraphQLViaLocationInput place; - - public GraphQLViaPointInput(Map args) { - if (args != null) { - this.label = (String) args.get("label"); - this.place = new GraphQLViaLocationInput((Map) args.get("place")); + this.passThroughLocation = + new GraphQLPassThroughLocationInput( + (Map) args.get("passThroughLocation") + ); } } - public String getGraphQLLabel() { - return this.label; - } - - public GraphQLViaLocationInput getGraphQLPlace() { - return this.place; - } - - public void setGraphQLLabel(String label) { - this.label = label; + public GraphQLPassThroughLocationInput getGraphQLPassThroughLocation() { + return this.passThroughLocation; } - public void setGraphQLPlace(GraphQLViaLocationInput place) { - this.place = place; + public void setGraphQLPassThroughLocation(GraphQLPassThroughLocationInput passThroughLocation) { + this.passThroughLocation = passThroughLocation; } } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapper.java b/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapper.java index 930176f45ee..a107f1f1aad 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapper.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapper.java @@ -266,7 +266,7 @@ static void mapViaPoints( TransitService transitService ) { callWith.argument( - "viaPoints", + "via", (List> v) -> request.setPassThroughPoints(PassThroughLocationMapper.toLocations(transitService, v)) ); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapper.java b/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapper.java index 370bc2c3917..6cdcc234bcd 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapper.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapper.java @@ -1,10 +1,8 @@ package org.opentripplanner.apis.gtfs.mapping.routerequest; -import static java.util.stream.Collectors.collectingAndThen; -import static java.util.stream.Collectors.toList; - import java.util.List; import java.util.Map; +import org.opentripplanner.framework.lang.StringUtils; import org.opentripplanner.routing.api.request.PassThroughPoint; import org.opentripplanner.transit.model.framework.FeedScopedId; import org.opentripplanner.transit.service.TransitService; @@ -22,24 +20,19 @@ private static PassThroughPoint handlePoint( final TransitService transitService, Map map ) { - Map element = (Map) map.get("place"); - List stops = (List) element.get("locationIds"); + Map element = (Map) map.get("passThroughLocation"); + String id = (String) element.get("stopLocationId"); final String name = (String) element.get("name"); - if (stops == null || stops.isEmpty()) { + if (StringUtils.hasNoValue(id)) { throw new IllegalArgumentException("No stops in pass-through point"); } - return stops - .stream() - .map(FeedScopedId::parse) - .flatMap(id -> { - var stopLocations = transitService.getStopOrChildStops(id); - if (stopLocations.isEmpty()) { - throw new IllegalArgumentException("No match for %s.".formatted(id)); - } - return stopLocations.stream(); - }) - .collect(collectingAndThen(toList(), sls -> new PassThroughPoint(sls, name))); + var stopLocationId = FeedScopedId.parse(id); + var stopLocations = List.copyOf(transitService.getStopOrChildStops(stopLocationId)); + if (stopLocations.isEmpty()) { + throw new IllegalArgumentException("No match for %s.".formatted(id)); + } + return new PassThroughPoint(stopLocations, name); } } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index aab9ca93fbf..a2ad9a7bf71 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1473,7 +1473,7 @@ type QueryType { "List of routes and agencies which are given lower preference when planning the itinerary" unpreferred: InputUnpreferred, "The list of points the journey is required to pass through." - viaPoints: [ViaPointInput!], + via: [ViaLocationInput!], """ How much less bad is waiting at the beginning of the trip (replaces `waitReluctance` on the first boarding). Default value: 0.4 @@ -3945,6 +3945,14 @@ input ParkingFilterOperation { tags: [String] } +"A stop that must be visited by the routing result." +input PassThroughLocationInput { + "Optional label of the via point for debugging and logging. It is not used in routing." + label: String + "The ID of the stop or station to visit. Should be in the format :." + stopLocationId: String! +} + "A coordinate used for a location in a plan query." input PlanCoordinateInput { "Latitude as a WGS84 format number." @@ -4324,23 +4332,7 @@ Right now only stop or station IDs are supported but this will be extended to su coordinates as well. """ input ViaLocationInput { - """ - The list of *stop location ids* which define the pass-through point. At least one id is required. - Stop and Station are supported location types. - The journey must pass through at least one of these entities - not all of them. - """ - locationIds: [String!] -} - -"Defines a point which the routing result must visit." -input ViaPointInput { - "Optional label of the via point for debugging and logging. It is not used in routing." - label: String - """ - The place that must be visited by the via routing result. Right now only stops and stations are - supported but this will be extended to cover coordinates as well. - """ - place: ViaLocationInput! + passThroughLocation: PassThroughLocationInput } "Preferences related to walking (excluding walking a bicycle or a scooter)." diff --git a/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java b/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java index 385242a49d0..e7b879f0501 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/LegacyRouteRequestMapperTest.java @@ -264,8 +264,8 @@ void transferSlack() { @Test void passThroughPoints() { Map arguments = Map.of( - "viaPoints", - List.of(Map.of("place", Map.of("locationIds", List.of("F:stop1")))) + "via", + List.of(Map.of("passThroughLocation", Map.of("stopLocationId", "F:stop1"))) ); var routeRequest = LegacyRouteRequestMapper.toRouteRequest( diff --git a/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapperTest.java b/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapperTest.java index fd2126496ac..ec34df90378 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapperTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/mapping/routerequest/PassThroughLocationMapperTest.java @@ -16,12 +16,9 @@ class PassThroughLocationMapperTest { public static List>> failureCases() { return List.of( - List.of(Map.of("place", Map.of("locationIds", List.of("fantasy:id")))), - List.of(Map.of("place", Map.of("locationIds", List.of()))), - List.of( - Map.of("place", Map.of("locationIds", List.of())), - Map.of("place", Map.of("locationIds", List.of())) - ) + List.of(Map.of("passThroughLocation", Map.of("stopLocationId", "fantasy:id"))), + List.of(Map.of("passThroughLocation", Map.of())), + List.of(Map.of("passThroughLocation", Map.of()), Map.of("passThroughLocation", Map.of())) ); } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql index 6970b59140c..4bbcec39d06 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan-extended.graphql @@ -10,8 +10,13 @@ filters: [{ select: [{ tags: ["e"] }] }] } transportModes: [{ mode: CAR, qualifier: HAIL }] - viaPoints: [ - { label: "Flower shop", place: { locationIds: ["F:A", "F:B"] } } + via: [ + { + passThroughLocation: { + label: "A stop that you want to visit along the route" + stopLocationId: "F:A" + } + } ] ) { itineraries {