From 6d5be573ea5e88713a19c3551f6470890601f913 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:40:25 +0200 Subject: [PATCH 01/49] Add ISO date times to GraphQL API --- .../apis/gtfs/GraphQLScalars.java | 32 +++++++++++++++++++ .../apis/gtfs/datafetchers/LegImpl.java | 13 ++++++++ .../gtfs/generated/GraphQLDataFetchers.java | 4 +++ .../apis/gtfs/generated/graphql-codegen.yml | 1 + .../opentripplanner/apis/gtfs/schema.graphqls | 5 +++ .../apis/gtfs/queries/plan-extended.graphql | 2 ++ 6 files changed, 57 insertions(+) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 6280ac28ac2..0e21df48dc1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -10,6 +10,10 @@ import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import javax.annotation.Nonnull; import org.locationtech.jts.geom.Geometry; import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.graphql.scalar.DurationScalarFactory; @@ -50,6 +54,34 @@ public String parseLiteral(Object input) { ) .build(); + public static GraphQLScalarType dateTimeScalar = GraphQLScalarType + .newScalar() + .name("DateTime") + .coercing( + new Coercing() { + @Override + public String serialize(@Nonnull Object dataFetcherResult) + throws CoercingSerializeException { + if (dataFetcherResult instanceof ZonedDateTime zdt) { + return zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } else if (dataFetcherResult instanceof OffsetDateTime odt) { + return odt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); + } else return null; + } + + @Override + public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { + return null; + } + + @Override + public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { + return null; + } + } + ) + .build(); + public static GraphQLScalarType geoJsonScalar = GraphQLScalarType .newScalar() .name("GeoJson") 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 639cb95bf28..94cda56b652 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -2,6 +2,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -78,6 +79,12 @@ public DataFetcher duration() { } @Override + public DataFetcher end() { + return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + } + + @Override + @Deprecated public DataFetcher endTime() { return environment -> getSource(environment).getEndTime().toInstant().toEpochMilli(); } @@ -216,6 +223,12 @@ public DataFetcher serviceDate() { } @Override + public DataFetcher start() { + return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + } + + @Override + @Deprecated public DataFetcher startTime() { return environment -> getSource(environment).getStartTime().toInstant().toEpochMilli(); } 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 2f39f7f4030..8194a0c5f4f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -440,6 +440,8 @@ public interface GraphQLLeg { public DataFetcher duration(); + public DataFetcher end(); + public DataFetcher endTime(); public DataFetcher> fareProducts(); @@ -480,6 +482,8 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); + public DataFetcher start(); + public DataFetcher startTime(); public DataFetcher> steps(); 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 c141266d2e6..24cde3afe43 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 @@ -26,6 +26,7 @@ config: Polyline: String GeoJson: org.locationtech.jts.geom.Geometry Grams: org.opentripplanner.framework.model.Grams + DateTime: java.time.OffsetDateTime Duration: java.time.Duration mappers: AbsoluteDirection: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLAbsoluteDirection#GraphQLAbsoluteDirection diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index daeb57d655e..2576dcf6441 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1640,12 +1640,17 @@ type RideHailingEstimate { productName: String } +scalar DateTime + type Leg { """ The date and time when this leg begins. Format: Unix timestamp in milliseconds. """ startTime: Long + start: DateTime + end: DateTime + """ The date and time when this leg ends. Format: Unix timestamp in milliseconds. """ 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 db30d8489ef..7eb4552b63d 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 @@ -28,6 +28,8 @@ walkTime legs { mode + start + end from { name lat From 67cf67ee842e2bdccc787e957563575d1fe4352d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:40:36 +0200 Subject: [PATCH 02/49] Add scalar --- .../java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index ff3e8681ce8..5ddfb2ba6d1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -111,6 +111,7 @@ protected static GraphQLSchema buildSchema() { .scalar(GraphQLScalars.geoJsonScalar) .scalar(GraphQLScalars.graphQLIDScalar) .scalar(GraphQLScalars.gramsScalar) + .scalar(GraphQLScalars.dateTimeScalar) .scalar(ExtendedScalars.GraphQLLong) .type("Node", type -> type.typeResolver(new NodeTypeResolver())) .type("PlaceInterface", type -> type.typeResolver(new PlaceInterfaceTypeResolver())) From 5835324d8e9226e007e8cfc28e13c462b94be843 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:51:37 +0200 Subject: [PATCH 03/49] Implement start/end for Itinerary --- .../apis/gtfs/datafetchers/ItineraryImpl.java | 12 ++++++++++++ .../apis/gtfs/generated/GraphQLDataFetchers.java | 4 +++- .../org/opentripplanner/apis/gtfs/schema.graphqls | 9 ++++++--- .../apis/gtfs/expectations/plan-extended.json | 10 ++++++++++ .../apis/gtfs/queries/plan-extended.graphql | 3 +++ 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java index c7ae82a2355..5396f66024f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java @@ -2,6 +2,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; import java.util.List; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.mapping.NumberMapper; @@ -32,6 +33,11 @@ public DataFetcher elevationLost() { return environment -> getSource(environment).getElevationLost(); } + @Override + public DataFetcher end() { + return environment -> getSource(environment).endTime().toOffsetDateTime(); + } + @Override public DataFetcher endTime() { return environment -> getSource(environment).endTime().toInstant().toEpochMilli(); @@ -57,6 +63,12 @@ public DataFetcher numberOfTransfers() { return environment -> getSource(environment).getNumberOfTransfers(); } + @Override + public DataFetcher start() { + return environment -> getSource(environment).startTime().toOffsetDateTime(); + } + + @Override public DataFetcher startTime() { return environment -> getSource(environment).startTime().toInstant().toEpochMilli(); 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 8194a0c5f4f..87ab5ad7b1d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -398,7 +398,7 @@ public interface GraphQLItinerary { public DataFetcher elevationLost(); - public DataFetcher emissionsPerPerson(); + public DataFetcher end(); public DataFetcher endTime(); @@ -408,6 +408,8 @@ public interface GraphQLItinerary { public DataFetcher> legs(); + public DataFetcher start(); + public DataFetcher numberOfTransfers(); public DataFetcher startTime(); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2576dcf6441..d77b63a0956 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1500,12 +1500,15 @@ type Itinerary { """ Time when the user leaves from the origin. Format: Unix timestamp in milliseconds. """ - startTime: Long + startTime: Long @deprecated(reason: "Use `start` instead which includes timezone information.") """ - Time when the user arrives to the destination.. Format: Unix timestamp in milliseconds. + Time when the user arrives to the destination. Format: Unix timestamp in milliseconds. """ - endTime: Long + endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") + + start: DateTime + end: DateTime """Duration of the trip on this itinerary, in seconds.""" duration: Long diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 557cdec8659..378e87838e9 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -3,6 +3,8 @@ "plan" : { "itineraries" : [ { + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T12:00:00Z", "startTime" : 1580641200000, "endTime" : 1580644800000, "generalizedCost" : 4072, @@ -16,6 +18,8 @@ "legs" : [ { "mode" : "WALK", + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T11:00:00Z", "from" : { "name" : "A", "lat" : 5.0, @@ -41,6 +45,8 @@ }, { "mode" : "BUS", + "start" : "2020-02-02T11:01:00Z", + "end" : "2020-02-02T11:01:00Z", "from" : { "name" : "B", "lat" : 6.0, @@ -68,6 +74,8 @@ }, { "mode" : "RAIL", + "start" : "2020-02-02T11:30:00Z", + "end" : "2020-02-02T11:30:00Z", "from" : { "name" : "C", "lat" : 7.0, @@ -115,6 +123,8 @@ }, { "mode" : "CAR", + "start" : "2020-02-02T11:50:00Z", + "end" : "2020-02-02T11:50:00Z", "from" : { "name" : "D", "lat" : 8.0, 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 7eb4552b63d..cde918e43b0 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 @@ -16,6 +16,9 @@ } ]) { itineraries { + start + end + # next two are deprecated startTime endTime generalizedCost From 8a966c2fd44cd478ac8f071dbe5a8b8d25850d5e Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 12:54:02 +0200 Subject: [PATCH 04/49] Use correct times for leg --- .../apis/gtfs/datafetchers/LegImpl.java | 2 +- .../apis/gtfs/expectations/plan-extended.json | 8 ++++---- .../apis/gtfs/expectations/plan.json | 20 +++++++++---------- .../apis/gtfs/queries/plan.graphql | 8 ++++---- 4 files changed, 19 insertions(+), 19 deletions(-) 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 94cda56b652..50e935ce7ea 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -80,7 +80,7 @@ public DataFetcher duration() { @Override public DataFetcher end() { - return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + return environment -> getSource(environment).getEndTime().toOffsetDateTime(); } @Override diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 378e87838e9..739e0453e08 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -19,7 +19,7 @@ { "mode" : "WALK", "start" : "2020-02-02T11:00:00Z", - "end" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T11:00:20Z", "from" : { "name" : "A", "lat" : 5.0, @@ -46,7 +46,7 @@ { "mode" : "BUS", "start" : "2020-02-02T11:01:00Z", - "end" : "2020-02-02T11:01:00Z", + "end" : "2020-02-02T11:15:00Z", "from" : { "name" : "B", "lat" : 6.0, @@ -75,7 +75,7 @@ { "mode" : "RAIL", "start" : "2020-02-02T11:30:00Z", - "end" : "2020-02-02T11:30:00Z", + "end" : "2020-02-02T11:50:00Z", "from" : { "name" : "C", "lat" : 7.0, @@ -124,7 +124,7 @@ { "mode" : "CAR", "start" : "2020-02-02T11:50:00Z", - "end" : "2020-02-02T11:50:00Z", + "end" : "2020-02-02T12:00:00Z", "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 06fd20be150..408b1c17ed5 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -3,13 +3,13 @@ "plan" : { "itineraries" : [ { - "startTime" : 1580641200000, - "endTime" : 1580644800000, + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T12:00:00Z", "legs" : [ { "mode" : "WALK", - "startTime" : 1580641200000, - "endTime" : 1580641220000, + "start" : "2020-02-02T11:00:00Z", + "end" : "2020-02-02T11:00:20Z", "from" : { "name" : "A", "lat" : 5.0, @@ -29,8 +29,8 @@ }, { "mode" : "BUS", - "startTime" : 1580641260000, - "endTime" : 1580642100000, + "start" : "2020-02-02T11:01:00Z", + "end" : "2020-02-02T11:15:00Z", "from" : { "name" : "B", "lat" : 6.0, @@ -56,8 +56,8 @@ }, { "mode" : "RAIL", - "startTime" : 1580643000000, - "endTime" : 1580644200000, + "start" : "2020-02-02T11:30:00Z", + "end" : "2020-02-02T11:50:00Z", "from" : { "name" : "C", "lat" : 7.0, @@ -83,8 +83,8 @@ }, { "mode" : "CAR", - "startTime" : 1580644200000, - "endTime" : 1580644800000, + "start" : "2020-02-02T11:50:00Z", + "end" : "2020-02-02T12:00:00Z", "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index d71c991234d..4e638d93759 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -17,12 +17,12 @@ }, ]) { itineraries { - startTime - endTime + start + end legs { mode - startTime - endTime + start + end from { name lat From ed766e651d5a9b602ea9ca053850dad4c1ddbc59 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 13:25:27 +0200 Subject: [PATCH 05/49] Add iso time to Place --- docs/apis/GraphQL-Tutorial.md | 16 +++---- .../apis/gtfs/datafetchers/ItineraryImpl.java | 3 +- .../apis/gtfs/datafetchers/PlaceImpl.java | 13 ++++++ .../gtfs/generated/GraphQLDataFetchers.java | 4 ++ .../opentripplanner/apis/gtfs/schema.graphqls | 43 +++++++++++-------- .../apis/gtfs/expectations/plan.json | 32 +++++++------- .../apis/gtfs/queries/plan.graphql | 8 ++-- 7 files changed, 72 insertions(+), 47 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 8df6d6f38ee..480e2ef10ee 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -88,25 +88,25 @@ Most people want to get routing results out of OTP, so lets see the query for th }, ]) { itineraries { - startTime - endTime + start + end legs { mode - startTime - endTime + start + end from { name lat lon - departureTime - arrivalTime + departure + arrival } to { name lat lon - departureTime - arrivalTime + departure + arrival } route { gtfsId diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java index 5396f66024f..20d5a9c348d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/ItineraryImpl.java @@ -38,6 +38,7 @@ public DataFetcher end() { return environment -> getSource(environment).endTime().toOffsetDateTime(); } + @Deprecated @Override public DataFetcher endTime() { return environment -> getSource(environment).endTime().toInstant().toEpochMilli(); @@ -68,7 +69,7 @@ public DataFetcher start() { return environment -> getSource(environment).startTime().toOffsetDateTime(); } - + @Deprecated @Override public DataFetcher startTime() { return environment -> getSource(environment).startTime().toInstant().toEpochMilli(); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index ce3ca0986b1..28cd088cf86 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -2,6 +2,7 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.OffsetDateTime; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLVertexType; import org.opentripplanner.apis.gtfs.model.StopPosition; @@ -17,6 +18,12 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { + @Override + public DataFetcher arrival() { + return environment -> getSource(environment).arrival.toOffsetDateTime(); + } + + @Deprecated @Override public DataFetcher arrivalTime() { return environment -> getSource(environment).arrival.toInstant().toEpochMilli(); @@ -45,6 +52,12 @@ public DataFetcher carPark() { return this::getCarPark; } + @Deprecated + @Override + public DataFetcher departure() { + return environment -> getSource(environment).departure.toOffsetDateTime(); + } + @Override public DataFetcher departureTime() { return environment -> getSource(environment).departure.toInstant().toEpochMilli(); 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 87ab5ad7b1d..431cf874152 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -582,6 +582,8 @@ public interface GraphQLPattern { } public interface GraphQLPlace { + public DataFetcher arrival(); + public DataFetcher arrivalTime(); public DataFetcher bikePark(); @@ -590,6 +592,8 @@ public interface GraphQLPlace { public DataFetcher carPark(); + public DataFetcher departure(); + public DataFetcher departureTime(); public DataFetcher lat(); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index d77b63a0956..f6abf30aacb 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1646,19 +1646,9 @@ type RideHailingEstimate { scalar DateTime type Leg { - """ - The date and time when this leg begins. Format: Unix timestamp in milliseconds. - """ - startTime: Long - start: DateTime end: DateTime - """ - The date and time when this leg ends. Format: Unix timestamp in milliseconds. - """ - endTime: Long - """ For transit leg, the offset from the scheduled departure time of the boarding stop in this leg, i.e. scheduled time of departure at boarding stop = @@ -1833,6 +1823,17 @@ type Leg { that applies to multiple legs can appear several times. """ fareProducts: [FareProductUse] + + """ + The date and time when this leg begins. Format: Unix timestamp in milliseconds. + """ + startTime: Long @deprecated(reason: "Use `start` instead which contains timezone information.") + + """ + The date and time when this leg ends. Format: Unix timestamp in milliseconds. + """ + endTime: Long @deprecated(reason: "Use `end` instead which contains timezone information.") + } """A span of time.""" @@ -2267,15 +2268,11 @@ type Place { """Longitude of the place (WGS 84)""" lon: Float! - """ - The time the rider will arrive at the place. Format: Unix timestamp in milliseconds. - """ - arrivalTime: Long! + "The time the rider will arrive at the place." + arrival: DateTime - """ - The time the rider will depart the place. Format: Unix timestamp in milliseconds. - """ - departureTime: Long! + "The time the rider will depart the place." + departure: DateTime """The stop related to the place.""" stop: Stop @@ -2313,6 +2310,16 @@ type Place { """The car parking related to the place""" carPark: CarPark @deprecated(reason: "carPark is deprecated. Use vehicleParking instead.") + + """ + The time the rider will arrive at the place. Format: Unix timestamp in milliseconds. + """ + arrivalTime: Long! @deprecated(reason: "Use `arrival` which includes timezone information.") + + """ + The time the rider will depart the place. Format: Unix timestamp in milliseconds. + """ + departureTime: Long! @deprecated(reason: "Use `departure` which includes timezone information.") } type placeAtDistance implements Node { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 408b1c17ed5..1a4d09f5756 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -14,15 +14,15 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departureTime" : 1580641200000, - "arrivalTime" : 1580641200000 + "departure" : "2020-02-02T11:00:00Z", + "arrival" : "2020-02-02T11:00:00Z" }, "to" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departureTime" : 1580641220000, - "arrivalTime" : 1580641220000 + "departure" : "2020-02-02T11:00:20Z", + "arrival" : "2020-02-02T11:00:20Z" }, "route" : null, "legGeometry" : null @@ -35,15 +35,15 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departureTime" : 1580641260000, - "arrivalTime" : 1580641260000 + "departure" : "2020-02-02T11:01:00Z", + "arrival" : "2020-02-02T11:01:00Z" }, "to" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departureTime" : 1580642100000, - "arrivalTime" : 1580642100000 + "departure" : "2020-02-02T11:15:00Z", + "arrival" : "2020-02-02T11:15:00Z" }, "route" : { "gtfsId" : "F:BUS", @@ -62,15 +62,15 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departureTime" : 1580643000000, - "arrivalTime" : 1580643000000 + "departure" : "2020-02-02T11:30:00Z", + "arrival" : "2020-02-02T11:30:00Z" }, "to" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departureTime" : 1580644200000, - "arrivalTime" : 1580644200000 + "departure" : "2020-02-02T11:50:00Z", + "arrival" : "2020-02-02T11:50:00Z" }, "route" : { "gtfsId" : "F:2", @@ -89,15 +89,15 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departureTime" : 1580644200000, - "arrivalTime" : 1580644200000 + "departure" : "2020-02-02T11:50:00Z", + "arrival" : "2020-02-02T11:50:00Z" }, "to" : { "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departureTime" : 1580644800000, - "arrivalTime" : 1580644800000 + "departure" : "2020-02-02T12:00:00Z", + "arrival" : "2020-02-02T12:00:00Z" }, "route" : null, "legGeometry" : null diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 4e638d93759..c37499eb5e7 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -27,15 +27,15 @@ name lat lon - departureTime - arrivalTime + departure + arrival } to { name lat lon - departureTime - arrivalTime + departure + arrival } route { gtfsId From cb938be6c488c06666bf69c36e4fb326fe6f9830 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 14:35:52 +0200 Subject: [PATCH 06/49] Introduce consolidated times for legs --- docs/apis/GraphQL-Tutorial.md | 12 ++++- .../impl/CombinedInterlinedTransitLeg.java | 11 +++++ .../ext/flex/FlexibleTransitLeg.java | 11 +++++ .../apis/gtfs/datafetchers/LegImpl.java | 10 ++-- .../gtfs/generated/GraphQLDataFetchers.java | 13 ++++- .../apis/gtfs/generated/graphql-codegen.yml | 1 + .../org/opentripplanner/model/plan/Leg.java | 3 ++ .../opentripplanner/model/plan/LegTime.java | 17 +++++++ .../model/plan/ScheduledTransitLeg.java | 10 ++++ .../opentripplanner/model/plan/StreetLeg.java | 10 ++++ .../model/plan/UnknownTransitPathLeg.java | 10 ++++ .../opentripplanner/apis/gtfs/schema.graphqls | 11 ++++- .../apis/gtfs/expectations/plan-extended.json | 48 +++++++++++++++---- .../apis/gtfs/expectations/plan.json | 48 +++++++++++++++---- .../apis/gtfs/queries/plan-extended.graphql | 12 ++++- .../apis/gtfs/queries/plan.graphql | 12 ++++- 16 files changed, 208 insertions(+), 31 deletions(-) create mode 100644 src/main/java/org/opentripplanner/model/plan/LegTime.java diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 480e2ef10ee..c98411fd20d 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -92,8 +92,16 @@ Most people want to get routing results out of OTP, so lets see the query for th end legs { mode - start - end + start { + scheduled + actual + delay + } + end { + scheduled + actual + delay + } from { name lat diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 0e9c10de7eb..43266f8e35f 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -9,6 +9,7 @@ import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Leg; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; @@ -56,6 +57,16 @@ public Trip getTrip() { return first.getTrip(); } + @Override + public LegTime start() { + return LegTime.of(getEndTime(), getDepartureDelay()); + } + + @Override + public LegTime end() { + return LegTime.of(getStartTime(), getArrivalDelay()); + } + @Override public ZonedDateTime getStartTime() { return first.getStartTime(); diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index 0e83372175a..e0bdb6cc899 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,6 +16,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.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -84,6 +85,16 @@ public Accessibility getTripWheelchairAccessibility() { return edge.getFlexTrip().getTrip().getWheelchairBoarding(); } + @Override + public LegTime start() { + return LegTime.of(startTime, getArrivalDelay()); + } + + @Override + public LegTime end() { + return LegTime.of(endTime, getDepartureDelay()); + } + @Override @Nonnull public TransitMode getMode() { 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 50e935ce7ea..093f6bda5e1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -2,7 +2,6 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.time.OffsetDateTime; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -19,6 +18,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.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,8 +79,8 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { - return environment -> getSource(environment).getEndTime().toOffsetDateTime(); + public DataFetcher end() { + return environment -> getSource(environment).end(); } @Override @@ -223,8 +223,8 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { - return environment -> getSource(environment).getStartTime().toOffsetDateTime(); + public DataFetcher start() { + return environment -> getSource(environment).start(); } @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 431cf874152..c1d9df3678d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,6 +36,7 @@ import org.opentripplanner.model.plan.Emissions; 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; @@ -442,7 +443,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -484,7 +485,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -499,6 +500,14 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } + public interface GraphQLLegTime { + public DataFetcher actual(); + + public DataFetcher delay(); + + public DataFetcher scheduled(); + } + /** A span of time. */ public interface GraphQLLocalTimeSpan { public DataFetcher from(); 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 24cde3afe43..f1d984a9ecd 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 @@ -60,6 +60,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 Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 05213dbdf5e..1e6ca916a63 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,6 +200,9 @@ default Accessibility getTripWheelchairAccessibility() { return null; } + LegTime start(); + LegTime end(); + /** * The date and time this leg begins. */ diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java new file mode 100644 index 00000000000..a65a3109987 --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -0,0 +1,17 @@ +package org.opentripplanner.model.plan; + +import java.time.Duration; +import java.time.ZonedDateTime; +import javax.annotation.Nonnull; + +public record LegTime(ZonedDateTime scheduled, ZonedDateTime actual, Duration delay) { + @Nonnull + public static LegTime of(ZonedDateTime realtime, int delaySecs) { + var delay = Duration.ofSeconds(delaySecs); + return new LegTime(realtime.minus(delay), realtime, delay); + } + @Nonnull + public static LegTime ofStatic(ZonedDateTime staticTime) { + return new LegTime(staticTime, staticTime, Duration.ZERO); + } +} diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 876567035dd..0e4923f9de1 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -162,6 +162,16 @@ public Accessibility getTripWheelchairAccessibility() { return tripTimes.getWheelchairAccessibility(); } + @Override + public LegTime start() { + return LegTime.of(startTime, getDepartureDelay()); + } + + @Override + public LegTime end() { + return LegTime.of(endTime, getArrivalDelay()); + } + @Override @Nonnull public TransitMode getMode() { diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 319c9e01f69..6384159a4ec 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -156,6 +156,16 @@ public boolean hasSameMode(Leg other) { return other instanceof StreetLeg oSL && mode.equals(oSL.mode); } + @Override + public LegTime start() { + return LegTime.ofStatic(startTime); + } + + @Override + public LegTime end() { + return LegTime.ofStatic(endTime); + } + @Override public Leg withTimeShift(Duration duration) { return StreetLegBuilder diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index 382a09d34e2..df43bbcb411 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -68,6 +68,16 @@ public boolean hasSameMode(Leg other) { return false; } + @Override + public LegTime start() { + return LegTime.ofStatic(startTime); + } + + @Override + public LegTime end() { + return LegTime.ofStatic(endTime); + } + @Override public double getDistanceMeters() { return UNKNOWN; diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index f6abf30aacb..0f4bba3de18 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1645,9 +1645,16 @@ type RideHailingEstimate { scalar DateTime +type LegTime { + scheduled: DateTime + actual: DateTime + delay: Duration +} + type Leg { - start: DateTime - end: DateTime + + start: LegTime + end: LegTime """ For transit leg, the offset from the scheduled departure time of the boarding diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 739e0453e08..5ccd1e7bdea 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -18,8 +18,16 @@ "legs" : [ { "mode" : "WALK", - "start" : "2020-02-02T11:00:00Z", - "end" : "2020-02-02T11:00:20Z", + "start" : { + "scheduled" : "2020-02-02T11:00:00Z", + "actual" : "2020-02-02T11:00:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:00:20Z", + "actual" : "2020-02-02T11:00:20Z", + "delay" : "PT0S" + }, "from" : { "name" : "A", "lat" : 5.0, @@ -45,8 +53,16 @@ }, { "mode" : "BUS", - "start" : "2020-02-02T11:01:00Z", - "end" : "2020-02-02T11:15:00Z", + "start" : { + "scheduled" : "2020-02-02T11:01:00Z", + "actual" : "2020-02-02T11:01:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:15:00Z", + "actual" : "2020-02-02T11:15:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "B", "lat" : 6.0, @@ -74,8 +90,16 @@ }, { "mode" : "RAIL", - "start" : "2020-02-02T11:30:00Z", - "end" : "2020-02-02T11:50:00Z", + "start" : { + "scheduled" : "2020-02-02T11:30:00Z", + "actual" : "2020-02-02T11:30:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "C", "lat" : 7.0, @@ -123,8 +147,16 @@ }, { "mode" : "CAR", - "start" : "2020-02-02T11:50:00Z", - "end" : "2020-02-02T12:00:00Z", + "start" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T12:00:00Z", + "actual" : "2020-02-02T12:00:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "D", "lat" : 8.0, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 1a4d09f5756..6865eb282d4 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -8,8 +8,16 @@ "legs" : [ { "mode" : "WALK", - "start" : "2020-02-02T11:00:00Z", - "end" : "2020-02-02T11:00:20Z", + "start" : { + "scheduled" : "2020-02-02T11:00:00Z", + "actual" : "2020-02-02T11:00:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:00:20Z", + "actual" : "2020-02-02T11:00:20Z", + "delay" : "PT0S" + }, "from" : { "name" : "A", "lat" : 5.0, @@ -29,8 +37,16 @@ }, { "mode" : "BUS", - "start" : "2020-02-02T11:01:00Z", - "end" : "2020-02-02T11:15:00Z", + "start" : { + "scheduled" : "2020-02-02T11:01:00Z", + "actual" : "2020-02-02T11:01:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:15:00Z", + "actual" : "2020-02-02T11:15:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "B", "lat" : 6.0, @@ -56,8 +72,16 @@ }, { "mode" : "RAIL", - "start" : "2020-02-02T11:30:00Z", - "end" : "2020-02-02T11:50:00Z", + "start" : { + "scheduled" : "2020-02-02T11:30:00Z", + "actual" : "2020-02-02T11:30:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "C", "lat" : 7.0, @@ -83,8 +107,16 @@ }, { "mode" : "CAR", - "start" : "2020-02-02T11:50:00Z", - "end" : "2020-02-02T12:00:00Z", + "start" : { + "scheduled" : "2020-02-02T11:50:00Z", + "actual" : "2020-02-02T11:50:00Z", + "delay" : "PT0S" + }, + "end" : { + "scheduled" : "2020-02-02T12:00:00Z", + "actual" : "2020-02-02T12:00:00Z", + "delay" : "PT0S" + }, "from" : { "name" : "D", "lat" : 8.0, 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 cde918e43b0..3d4ec134b47 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 @@ -31,8 +31,16 @@ walkTime legs { mode - start - end + start { + scheduled + actual + delay + } + end { + scheduled + actual + delay + } from { name lat diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index c37499eb5e7..5af473c7323 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -21,8 +21,16 @@ end legs { mode - start - end + start { + scheduled + actual + delay + } + end { + scheduled + actual + delay + } from { name lat From 6e620e77b671873e5abf8adad121f951dccc9214 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 14:54:37 +0200 Subject: [PATCH 07/49] Update deprecation notice --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 0f4bba3de18..8fdfd0133d8 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1834,12 +1834,12 @@ type Leg { """ The date and time when this leg begins. Format: Unix timestamp in milliseconds. """ - startTime: Long @deprecated(reason: "Use `start` instead which contains timezone information.") + startTime: Long @deprecated(reason: "Use `start.actual` instead which contains timezone information.") """ The date and time when this leg ends. Format: Unix timestamp in milliseconds. """ - endTime: Long @deprecated(reason: "Use `end` instead which contains timezone information.") + endTime: Long @deprecated(reason: "Use `end.actual` instead which contains timezone information.") } From d1a123acdb0b99408c86322e897502681a6e0a63 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 8 Aug 2023 15:38:36 +0200 Subject: [PATCH 08/49] Add ISO times to stop time --- .../apis/gtfs/datafetchers/StoptimeImpl.java | 23 ++++++++++++ .../gtfs/generated/GraphQLDataFetchers.java | 4 ++ .../opentripplanner/model/TripTimeOnDate.java | 37 +++++++++++++++++++ .../opentripplanner/model/plan/LegTime.java | 3 +- .../opentripplanner/apis/gtfs/schema.graphqls | 4 ++ 5 files changed, 70 insertions(+), 1 deletion(-) 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..e7881aea867 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -2,20 +2,39 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; +import java.time.ZoneId; +import org.opentripplanner.apis.gtfs.GraphQLRequestContext; 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.model.plan.LegTime; import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; public class StoptimeImpl implements GraphQLDataFetchers.GraphQLStoptime { + @Override + public DataFetcher arrival() { + return environment -> { + var tripTime = getSource(environment); + return tripTime.arrival(getZoneId(environment)); + }; + } + @Override public DataFetcher arrivalDelay() { return environment -> missingValueToNull(getSource(environment).getArrivalDelay()); } + @Override + public DataFetcher departure() { + return environment -> { + var tripTime = getSource(environment); + return tripTime.departure(getZoneId(environment)); + }; + } + @Override public DataFetcher departureDelay() { return environment -> getSource(environment).getDepartureDelay(); @@ -113,6 +132,10 @@ private TripTimeOnDate getSource(DataFetchingEnvironment environment) { return environment.getSource(); } + private ZoneId getZoneId(DataFetchingEnvironment environment) { + return environment.getContext().transitService().getTimeZone(); + } + /** * 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. 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 c1d9df3678d..832d3c65d31 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -980,8 +980,12 @@ public interface GraphQLStopRelationship { /** Stoptime represents the time when a specific trip arrives to or departs from a specific stop. */ public interface GraphQLStoptime { + public DataFetcher arrival(); + public DataFetcher arrivalDelay(); + public DataFetcher departure(); + public DataFetcher departureDelay(); public DataFetcher dropoffType(); diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 9ba85d6b532..24f33cf35b6 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -1,11 +1,16 @@ package org.opentripplanner.model; +import java.time.Duration; import java.time.Instant; import java.time.LocalDate; +import java.time.ZoneId; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; +import javax.annotation.Nonnull; import org.opentripplanner.framework.i18n.I18NString; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.OccupancyStatus; @@ -268,4 +273,36 @@ public BookingInfo getPickupBookingInfo() { public BookingInfo getDropOffBookingInfo() { return tripTimes.getDropOffBookingInfo(stopIndex); } + + public LegTime arrival(ZoneId zoneId) { + var delay = getArrivalDelay(); + var scheduled = getScheduledArrival(); + var actual = getActualDeparture(); + return buildLegTime(zoneId, scheduled, actual, delay); + } + + public LegTime departure(ZoneId zoneId) { + var delay = getDepartureDelay(); + var scheduled = getScheduledDeparture(); + var actual = getActualDeparture(); + return buildLegTime(zoneId, scheduled, actual, delay); + } + + @Nonnull + private LegTime buildLegTime( + ZoneId zoneId, + int scheduled, + int actual, + int delay + ) { + var midnight = serviceDate.atStartOfDay(zoneId); + var scheduledTime = midnight.plusSeconds(scheduled); + ZonedDateTime actualTime; + if (actual == UNDEFINED) { + actualTime = null; + } else { + actualTime = midnight.plusSeconds(actual); + } + return new LegTime(scheduledTime, actualTime, Duration.ofSeconds(delay)); + } } diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index a65a3109987..5a940a40b2c 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -3,8 +3,9 @@ import java.time.Duration; import java.time.ZonedDateTime; import javax.annotation.Nonnull; +import javax.annotation.Nullable; -public record LegTime(ZonedDateTime scheduled, ZonedDateTime actual, Duration delay) { +public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable ZonedDateTime actual, Duration delay) { @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 8fdfd0133d8..9e04f493c1a 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -3896,6 +3896,10 @@ type Stoptime { """ stopPosition: Int + + departure: LegTime + arrival: LegTime + """ Scheduled arrival time. Format: seconds since midnight of the departure date """ From d5f4926545eaf8d533a059fdb16410ec0efa07f5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 Nov 2023 18:24:10 +0100 Subject: [PATCH 09/49] Rename LegTime to LegTimes --- .../impl/CombinedInterlinedTransitLeg.java | 10 ++++----- .../ext/flex/FlexibleTransitLeg.java | 10 ++++----- .../apis/gtfs/datafetchers/LegImpl.java | 6 ++--- .../apis/gtfs/datafetchers/StoptimeImpl.java | 6 ++--- .../gtfs/generated/GraphQLDataFetchers.java | 11 +++++----- .../opentripplanner/model/TripTimeOnDate.java | 15 +++++-------- .../org/opentripplanner/model/plan/Leg.java | 4 ++-- .../opentripplanner/model/plan/LegTime.java | 18 --------------- .../opentripplanner/model/plan/LegTimes.java | 22 +++++++++++++++++++ .../model/plan/ScheduledTransitLeg.java | 8 +++---- .../opentripplanner/model/plan/StreetLeg.java | 8 +++---- .../model/plan/UnknownTransitPathLeg.java | 8 +++---- 12 files changed, 62 insertions(+), 64 deletions(-) delete mode 100644 src/main/java/org/opentripplanner/model/plan/LegTime.java create mode 100644 src/main/java/org/opentripplanner/model/plan/LegTimes.java diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 43266f8e35f..c1497373851 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -9,8 +9,8 @@ import org.locationtech.jts.geom.LineString; import org.opentripplanner.framework.collection.ListUtils; import org.opentripplanner.model.fare.FareProductUse; -import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Leg; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -58,13 +58,13 @@ public Trip getTrip() { } @Override - public LegTime start() { - return LegTime.of(getEndTime(), getDepartureDelay()); + public LegTimes start() { + return LegTimes.of(getEndTime(), getDepartureDelay()); } @Override - public LegTime end() { - return LegTime.of(getStartTime(), getArrivalDelay()); + public LegTimes end() { + return LegTimes.of(getStartTime(), getArrivalDelay()); } @Override diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index e0bdb6cc899..25caa9089e9 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,7 +16,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.LegTimes; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -86,13 +86,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTime start() { - return LegTime.of(startTime, getArrivalDelay()); + public LegTimes start() { + return LegTimes.of(startTime, getArrivalDelay()); } @Override - public LegTime end() { - return LegTime.of(endTime, getDepartureDelay()); + public LegTimes end() { + return LegTimes.of(endTime, getDepartureDelay()); } @Override 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 093f6bda5e1..239ba0e28cf 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -18,7 +18,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.LegTimes; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,7 +79,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -223,7 +223,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } 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 e7881aea867..85ef1608771 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -8,14 +8,14 @@ import org.opentripplanner.framework.graphql.GraphQLUtils; import org.opentripplanner.model.StopTime; import org.opentripplanner.model.TripTimeOnDate; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; public class StoptimeImpl implements GraphQLDataFetchers.GraphQLStoptime { @Override - public DataFetcher arrival() { + public DataFetcher arrival() { return environment -> { var tripTime = getSource(environment); return tripTime.arrival(getZoneId(environment)); @@ -28,7 +28,7 @@ public DataFetcher arrivalDelay() { } @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> { var tripTime = getSource(environment); return tripTime.departure(getZoneId(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 832d3c65d31..9ab6f39bb77 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,7 +36,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -51,7 +51,6 @@ import org.opentripplanner.service.realtimevehicles.model.RealtimeVehicle.StopRelationship; import org.opentripplanner.service.vehiclerental.model.RentalVehicleEntityCounts; import org.opentripplanner.service.vehiclerental.model.RentalVehicleType; -import org.opentripplanner.service.vehiclerental.model.RentalVehicleTypeCount; import org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStation; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; @@ -443,7 +442,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -485,7 +484,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -980,11 +979,11 @@ public interface GraphQLStopRelationship { /** Stoptime represents the time when a specific trip arrives to or departs from a specific stop. */ public interface GraphQLStoptime { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalDelay(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureDelay(); diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index 24f33cf35b6..c1c916eb33f 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -10,7 +10,7 @@ import java.util.List; import javax.annotation.Nonnull; import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.model.plan.LegTime; +import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.OccupancyStatus; @@ -274,14 +274,14 @@ public BookingInfo getDropOffBookingInfo() { return tripTimes.getDropOffBookingInfo(stopIndex); } - public LegTime arrival(ZoneId zoneId) { + public LegTimes arrival(ZoneId zoneId) { var delay = getArrivalDelay(); var scheduled = getScheduledArrival(); var actual = getActualDeparture(); return buildLegTime(zoneId, scheduled, actual, delay); } - public LegTime departure(ZoneId zoneId) { + public LegTimes departure(ZoneId zoneId) { var delay = getDepartureDelay(); var scheduled = getScheduledDeparture(); var actual = getActualDeparture(); @@ -289,12 +289,7 @@ public LegTime departure(ZoneId zoneId) { } @Nonnull - private LegTime buildLegTime( - ZoneId zoneId, - int scheduled, - int actual, - int delay - ) { + private LegTimes buildLegTime(ZoneId zoneId, int scheduled, int actual, int delay) { var midnight = serviceDate.atStartOfDay(zoneId); var scheduledTime = midnight.plusSeconds(scheduled); ZonedDateTime actualTime; @@ -303,6 +298,6 @@ private LegTime buildLegTime( } else { actualTime = midnight.plusSeconds(actual); } - return new LegTime(scheduledTime, actualTime, Duration.ofSeconds(delay)); + return new LegTimes(scheduledTime, actualTime, Duration.ofSeconds(delay)); } } diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 1e6ca916a63..906e09989c5 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,8 +200,8 @@ default Accessibility getTripWheelchairAccessibility() { return null; } - LegTime start(); - LegTime end(); + LegTimes start(); + LegTimes end(); /** * The date and time this leg begins. diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java deleted file mode 100644 index 5a940a40b2c..00000000000 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.opentripplanner.model.plan; - -import java.time.Duration; -import java.time.ZonedDateTime; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable ZonedDateTime actual, Duration delay) { - @Nonnull - public static LegTime of(ZonedDateTime realtime, int delaySecs) { - var delay = Duration.ofSeconds(delaySecs); - return new LegTime(realtime.minus(delay), realtime, delay); - } - @Nonnull - public static LegTime ofStatic(ZonedDateTime staticTime) { - return new LegTime(staticTime, staticTime, Duration.ZERO); - } -} diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java new file mode 100644 index 00000000000..e6614b2ed01 --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -0,0 +1,22 @@ +package org.opentripplanner.model.plan; + +import java.time.Duration; +import java.time.ZonedDateTime; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public record LegTimes( + @Nonnull ZonedDateTime scheduled, + @Nullable ZonedDateTime actual, + @Nullable Duration delay +) { + @Nonnull + public static LegTimes of(ZonedDateTime realtime, int delaySecs) { + var delay = Duration.ofSeconds(delaySecs); + return new LegTimes(realtime.minus(delay), realtime, delay); + } + @Nonnull + public static LegTimes ofStatic(ZonedDateTime staticTime) { + return new LegTimes(staticTime, staticTime, Duration.ZERO); + } +} diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 0e4923f9de1..4f6bf98def3 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -163,13 +163,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTime start() { - return LegTime.of(startTime, getDepartureDelay()); + public LegTimes start() { + return LegTimes.of(startTime, getDepartureDelay()); } @Override - public LegTime end() { - return LegTime.of(endTime, getArrivalDelay()); + public LegTimes end() { + return LegTimes.of(endTime, getArrivalDelay()); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 6384159a4ec..41062995cf4 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/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 LegTimes start() { + return LegTimes.ofStatic(startTime); } @Override - public LegTime end() { - return LegTime.ofStatic(endTime); + public LegTimes end() { + return LegTimes.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index df43bbcb411..4dfefb086e3 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -69,13 +69,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTime start() { - return LegTime.ofStatic(startTime); + public LegTimes start() { + return LegTimes.ofStatic(startTime); } @Override - public LegTime end() { - return LegTime.ofStatic(endTime); + public LegTimes end() { + return LegTimes.ofStatic(endTime); } @Override From 2b21e8f11bd269787a9de3c22aa61df5ab9d6c35 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 6 Nov 2023 18:31:33 +0100 Subject: [PATCH 10/49] Move deprecated methods to bottom --- .../opentripplanner/apis/gtfs/schema.graphqls | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 9e04f493c1a..2d454d6a3e8 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1645,7 +1645,7 @@ type RideHailingEstimate { scalar DateTime -type LegTime { +type LegTimes { scheduled: DateTime actual: DateTime delay: Duration @@ -1653,22 +1653,8 @@ type LegTime { type Leg { - start: LegTime - end: LegTime - - """ - For transit leg, the offset from the scheduled departure time of the boarding - stop in this leg, i.e. scheduled time of departure at boarding stop = - `startTime - departureDelay` - """ - departureDelay: Int - - """ - For transit leg, the offset from the scheduled arrival time of the alighting - stop in this leg, i.e. scheduled time of arrival at alighting stop = `endTime - - arrivalDelay` - """ - arrivalDelay: Int + start: LegTimes + end: LegTimes """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode @@ -1841,6 +1827,20 @@ type Leg { """ endTime: Long @deprecated(reason: "Use `end.actual` instead which contains timezone information.") + """ + For transit leg, the offset from the scheduled departure time of the boarding + stop in this leg, i.e. scheduled time of departure at boarding stop = + `startTime - departureDelay` + """ + departureDelay: Int @deprecated(reason: "Use `end.delay` instead.") + + """ + For transit leg, the offset from the scheduled arrival time of the alighting + stop in this leg, i.e. scheduled time of arrival at alighting stop = `endTime + - arrivalDelay` + """ + arrivalDelay: Int @deprecated(reason: "Use `start.delay` instead.") + } """A span of time.""" From e12ecfbb1f80811a374cda06912f2aa2bf2eb61d Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 7 Nov 2023 09:21:51 +0100 Subject: [PATCH 11/49] Rename LegTime to LegTimes --- .../apis/gtfs/generated/GraphQLDataFetchers.java | 3 ++- .../opentripplanner/apis/gtfs/generated/graphql-codegen.yml | 2 +- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 ++-- 3 files changed, 5 insertions(+), 4 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 9ab6f39bb77..f95496990a2 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -51,6 +51,7 @@ import org.opentripplanner.service.realtimevehicles.model.RealtimeVehicle.StopRelationship; import org.opentripplanner.service.vehiclerental.model.RentalVehicleEntityCounts; import org.opentripplanner.service.vehiclerental.model.RentalVehicleType; +import org.opentripplanner.service.vehiclerental.model.RentalVehicleTypeCount; import org.opentripplanner.service.vehiclerental.model.VehicleRentalPlace; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStation; import org.opentripplanner.service.vehiclerental.model.VehicleRentalStationUris; @@ -499,7 +500,7 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } - public interface GraphQLLegTime { + public interface GraphQLLegTimes { public DataFetcher actual(); public DataFetcher delay(); 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 f1d984a9ecd..c248d787088 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 @@ -60,7 +60,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 + LegTimes: org.opentripplanner.model.plan.LegTimes#LegTimes Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2d454d6a3e8..82c0fb9c207 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -3897,8 +3897,8 @@ type Stoptime { stopPosition: Int - departure: LegTime - arrival: LegTime + departure: LegTimes + arrival: LegTimes """ Scheduled arrival time. Format: seconds since midnight of the departure date From 644dbcb86d9d85a1c53da3f7323bd873707aebeb Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 7 Nov 2023 09:40:29 +0100 Subject: [PATCH 12/49] Remove changes to StopTime --- .../apis/gtfs/datafetchers/StoptimeImpl.java | 23 ------------- .../gtfs/generated/GraphQLDataFetchers.java | 4 --- .../opentripplanner/model/TripTimeOnDate.java | 32 ------------------- .../opentripplanner/apis/gtfs/schema.graphqls | 4 --- 4 files changed, 63 deletions(-) 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 85ef1608771..faf59ef9d6e 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/StoptimeImpl.java @@ -2,39 +2,20 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.time.ZoneId; -import org.opentripplanner.apis.gtfs.GraphQLRequestContext; 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.model.plan.LegTimes; import org.opentripplanner.transit.model.timetable.RealTimeState; import org.opentripplanner.transit.model.timetable.Trip; public class StoptimeImpl implements GraphQLDataFetchers.GraphQLStoptime { - @Override - public DataFetcher arrival() { - return environment -> { - var tripTime = getSource(environment); - return tripTime.arrival(getZoneId(environment)); - }; - } - @Override public DataFetcher arrivalDelay() { return environment -> missingValueToNull(getSource(environment).getArrivalDelay()); } - @Override - public DataFetcher departure() { - return environment -> { - var tripTime = getSource(environment); - return tripTime.departure(getZoneId(environment)); - }; - } - @Override public DataFetcher departureDelay() { return environment -> getSource(environment).getDepartureDelay(); @@ -132,10 +113,6 @@ private TripTimeOnDate getSource(DataFetchingEnvironment environment) { return environment.getSource(); } - private ZoneId getZoneId(DataFetchingEnvironment environment) { - return environment.getContext().transitService().getTimeZone(); - } - /** * 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. 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 f95496990a2..d9991d9dff3 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -980,12 +980,8 @@ public interface GraphQLStopRelationship { /** Stoptime represents the time when a specific trip arrives to or departs from a specific stop. */ public interface GraphQLStoptime { - public DataFetcher arrival(); - public DataFetcher arrivalDelay(); - public DataFetcher departure(); - public DataFetcher departureDelay(); public DataFetcher dropoffType(); diff --git a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java index c1c916eb33f..9ba85d6b532 100644 --- a/src/main/java/org/opentripplanner/model/TripTimeOnDate.java +++ b/src/main/java/org/opentripplanner/model/TripTimeOnDate.java @@ -1,16 +1,11 @@ package org.opentripplanner.model; -import java.time.Duration; import java.time.Instant; import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; -import javax.annotation.Nonnull; import org.opentripplanner.framework.i18n.I18NString; -import org.opentripplanner.model.plan.LegTimes; import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.OccupancyStatus; @@ -273,31 +268,4 @@ public BookingInfo getPickupBookingInfo() { public BookingInfo getDropOffBookingInfo() { return tripTimes.getDropOffBookingInfo(stopIndex); } - - public LegTimes arrival(ZoneId zoneId) { - var delay = getArrivalDelay(); - var scheduled = getScheduledArrival(); - var actual = getActualDeparture(); - return buildLegTime(zoneId, scheduled, actual, delay); - } - - public LegTimes departure(ZoneId zoneId) { - var delay = getDepartureDelay(); - var scheduled = getScheduledDeparture(); - var actual = getActualDeparture(); - return buildLegTime(zoneId, scheduled, actual, delay); - } - - @Nonnull - private LegTimes buildLegTime(ZoneId zoneId, int scheduled, int actual, int delay) { - var midnight = serviceDate.atStartOfDay(zoneId); - var scheduledTime = midnight.plusSeconds(scheduled); - ZonedDateTime actualTime; - if (actual == UNDEFINED) { - actualTime = null; - } else { - actualTime = midnight.plusSeconds(actual); - } - return new LegTimes(scheduledTime, actualTime, Duration.ofSeconds(delay)); - } } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 82c0fb9c207..490228ad01c 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -3896,10 +3896,6 @@ type Stoptime { """ stopPosition: Int - - departure: LegTimes - arrival: LegTimes - """ Scheduled arrival time. Format: seconds since midnight of the departure date """ From f69ca284e3f37b4922e629dc348f5008785280f4 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 7 Nov 2023 10:03:29 +0100 Subject: [PATCH 13/49] Rename to OffsetDateTime --- .../opentripplanner/apis/gtfs/GraphQLScalars.java | 4 ++-- .../apis/gtfs/GtfsGraphQLIndex.java | 2 +- .../org/opentripplanner/apis/gtfs/schema.graphqls | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 0e21df48dc1..3e376b60b35 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -54,9 +54,9 @@ public String parseLiteral(Object input) { ) .build(); - public static GraphQLScalarType dateTimeScalar = GraphQLScalarType + public static GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType .newScalar() - .name("DateTime") + .name("OffsetDateTime") .coercing( new Coercing() { @Override diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 5ddfb2ba6d1..0d76de16dc1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -111,7 +111,7 @@ protected static GraphQLSchema buildSchema() { .scalar(GraphQLScalars.geoJsonScalar) .scalar(GraphQLScalars.graphQLIDScalar) .scalar(GraphQLScalars.gramsScalar) - .scalar(GraphQLScalars.dateTimeScalar) + .scalar(GraphQLScalars.offsetDateTimeScalar) .scalar(ExtendedScalars.GraphQLLong) .type("Node", type -> type.typeResolver(new NodeTypeResolver())) .type("PlaceInterface", type -> type.typeResolver(new PlaceInterfaceTypeResolver())) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 490228ad01c..0ca9d2e8011 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1507,8 +1507,8 @@ type Itinerary { """ endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") - start: DateTime - end: DateTime + start: OffsetDateTime + end: OffsetDateTime """Duration of the trip on this itinerary, in seconds.""" duration: Long @@ -1643,11 +1643,11 @@ type RideHailingEstimate { productName: String } -scalar DateTime +scalar OffsetDateTime type LegTimes { - scheduled: DateTime - actual: DateTime + scheduled: OffsetDateTime + actual: OffsetDateTime delay: Duration } @@ -2276,10 +2276,10 @@ type Place { lon: Float! "The time the rider will arrive at the place." - arrival: DateTime + arrival: OffsetDateTime "The time the rider will depart the place." - departure: DateTime + departure: OffsetDateTime """The stop related to the place.""" stop: Stop From f2e394fbc1742469aba55ca37e383517c7267705 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 6 Jan 2024 14:35:46 +0100 Subject: [PATCH 14/49] Regenerate types, move deprecated fields to the bottom --- .../gtfs/generated/GraphQLDataFetchers.java | 6 ++++-- .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../opentripplanner/apis/gtfs/schema.graphqls | 20 +++++++++---------- 3 files changed, 15 insertions(+), 13 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 d9991d9dff3..639ba7c8744 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -399,6 +399,8 @@ public interface GraphQLItinerary { public DataFetcher elevationLost(); + public DataFetcher emissionsPerPerson(); + public DataFetcher end(); public DataFetcher endTime(); @@ -409,10 +411,10 @@ public interface GraphQLItinerary { public DataFetcher> legs(); - public DataFetcher start(); - public DataFetcher numberOfTransfers(); + public DataFetcher start(); + public DataFetcher startTime(); public DataFetcher> systemNotices(); 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 c248d787088..ecc7a89fb44 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 @@ -26,7 +26,7 @@ config: Polyline: String GeoJson: org.locationtech.jts.geom.Geometry Grams: org.opentripplanner.framework.model.Grams - DateTime: java.time.OffsetDateTime + OffsetDateTime: java.time.OffsetDateTime Duration: java.time.Duration mappers: AbsoluteDirection: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLAbsoluteDirection#GraphQLAbsoluteDirection diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 0ca9d2e8011..15cd4ae8ed3 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1497,16 +1497,6 @@ type DefaultFareProduct implements FareProduct { } type Itinerary { - """ - Time when the user leaves from the origin. Format: Unix timestamp in milliseconds. - """ - startTime: Long @deprecated(reason: "Use `start` instead which includes timezone information.") - - """ - Time when the user arrives to the destination. Format: Unix timestamp in milliseconds. - """ - endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") - start: OffsetDateTime end: OffsetDateTime @@ -1587,6 +1577,16 @@ type Itinerary { and always returns an empty list. Use the leg's `fareProducts` instead. """ fares: [fare] @deprecated(reason: "Use the leg's `fareProducts`.") + + """ + Time when the user leaves from the origin. Format: Unix timestamp in milliseconds. + """ + startTime: Long @deprecated(reason: "Use `start` instead which includes timezone information.") + + """ + Time when the user arrives to the destination. Format: Unix timestamp in milliseconds. + """ + endTime: Long @deprecated(reason: "Use `end` instead which includes timezone information.") } "A currency" From dc7521e9694bc4810582ad705ee80175e7f12a95 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 6 Jan 2024 14:56:50 +0100 Subject: [PATCH 15/49] Add tests for Duration --- .../opentripplanner/apis/gtfs/schema.graphqls | 7 ++++++ .../apis/gtfs/GraphQLScalarsTest.java | 22 +++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 15cd4ae8ed3..ff60ed183cb 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1621,6 +1621,8 @@ type Money { """" An ISO-8601-formatted duration, i.e. `PT2H30M` for 2 hours and 30 minutes. + +Negative durations are formatted like `PT-10M`. """ scalar Duration @@ -1648,6 +1650,11 @@ scalar OffsetDateTime type LegTimes { scheduled: OffsetDateTime actual: OffsetDateTime + """ + The delay of the vehicle at a certain place. + + If the vehicle is early then this is a negative duration. + """ delay: Duration } diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 90b35a31b9f..1c4472827c5 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -1,22 +1,36 @@ package org.opentripplanner.apis.gtfs; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.of; import com.fasterxml.jackson.core.JsonProcessingException; import graphql.schema.CoercingSerializeException; import java.time.Duration; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.opentripplanner.framework.json.ObjectMappers; class GraphQLScalarsTest { - @Test - void duration() { - var string = GraphQLScalars.durationScalar.getCoercing().serialize(Duration.ofMinutes(30)); - assertEquals("PT30M", string); + static List durationCases() { + return List.of( + of(Duration.ofMinutes(30), "PT30M"), + of(Duration.ofHours(23), "PT23H"), + of(Duration.ofMinutes(-10), "PT-10M") + ); + } + + @ParameterizedTest + @MethodSource("durationCases") + void duration(Duration duration, String expected) { + var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); + assertEquals(expected, string); } @Test From d319e5ba67a2e7349bd74197cc61e9dc6047cfa2 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sat, 6 Jan 2024 20:10:46 +0100 Subject: [PATCH 16/49] Add nullability check --- src/main/java/org/opentripplanner/model/plan/LegTimes.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index e6614b2ed01..06b2fb3662b 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -2,6 +2,7 @@ import java.time.Duration; import java.time.ZonedDateTime; +import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -10,6 +11,9 @@ public record LegTimes( @Nullable ZonedDateTime actual, @Nullable Duration delay ) { + public LegTimes { + Objects.requireNonNull(scheduled); + } @Nonnull public static LegTimes of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); From 67895bee4eb0b1d8313e5010848145c834ad49f2 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 17:12:19 +0100 Subject: [PATCH 17/49] Add documentation for OffsetDateTime --- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index ff60ed183cb..3b6bdad5fa4 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1645,6 +1645,9 @@ type RideHailingEstimate { productName: String } +""" +An ISO-8601-formatted datetime with offset, i.e. `2023-06-13T14:30+03:00` for 2:30pm on June 13th 2023 at Helsinki's offset from UTC at that time. +""" scalar OffsetDateTime type LegTimes { From 4f757dae87d3f67ec9622df8e49c6894c6445029 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 17:19:29 +0100 Subject: [PATCH 18/49] Add test for intermediate places --- .../apis/gtfs/expectations/plan-extended.json | 20 +++++++++++++++++++ .../apis/gtfs/queries/plan-extended.graphql | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 5ccd1e7bdea..fde24b8697a 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -47,6 +47,7 @@ "generalizedCost" : 40, "headsign" : null, "trip" : null, + "intermediatePlaces" : null, "alerts" : [ ], "rideHailingEstimate" : null, "accessibilityScore" : null @@ -84,6 +85,15 @@ "trip" : { "tripHeadsign" : "Trip headsign 122" }, + "intermediatePlaces" : [ + { + "arrival" : "2020-02-02T11:01:00Z", + "departure" : "2020-02-02T11:01:00Z", + "stop" : { + "name" : "B" + } + } + ], "alerts" : [ ], "rideHailingEstimate" : null, "accessibilityScore" : null @@ -121,6 +131,15 @@ "trip" : { "tripHeadsign" : "Trip headsign 439" }, + "intermediatePlaces" : [ + { + "arrival" : "2020-02-02T11:30:00Z", + "departure" : "2020-02-02T11:30:00Z", + "stop" : { + "name" : "C" + } + } + ], "alerts" : [ { "id" : "QWxlcnQ6Rjphbi1hbGVydA", @@ -176,6 +195,7 @@ "generalizedCost" : 1000, "headsign" : null, "trip" : null, + "intermediatePlaces" : null, "alerts" : [ ], "rideHailingEstimate" : { "provider" : { 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 3d4ec134b47..1c90f773677 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 @@ -63,6 +63,13 @@ trip { tripHeadsign } + intermediatePlaces { + arrival + departure + stop { + name + } + } alerts { id alertHeaderText From 980d620e7ba9104720a6b4ef33c0c3ee91ab3f95 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 17:28:20 +0100 Subject: [PATCH 19/49] Add test cases --- .../apis/gtfs/GraphQLScalarsTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 1c4472827c5..079749f3ccc 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -6,6 +6,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import graphql.schema.CoercingSerializeException; import java.time.Duration; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -14,10 +18,17 @@ import org.junit.jupiter.params.provider.MethodSource; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; +import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.framework.json.ObjectMappers; class GraphQLScalarsTest { + private static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( + LocalDate.of(2024, 2, 4), + LocalTime.MIDNIGHT, + ZoneOffset.UTC + ); + static List durationCases() { return List.of( of(Duration.ofMinutes(30), "PT30M"), @@ -59,4 +70,26 @@ void geoJson() throws JsonProcessingException { .readTree("{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[1,1],[2,2],[0,0]]]}"); assertEquals(jsonNode.toString(), geoJson.toString()); } + + static List offsetDateTimeCases() { + return List.of( + of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), + of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), + "2024-02-04T01:00:00+01:00" + ), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), + "2024-02-03T19:00:00-05:00" + ) + ); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void duration(OffsetDateTime odt, String expected) { + var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + assertEquals(expected, string); + } } From dcaa04a41bd5cd8afd2a34605256d08e5415840c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 5 Feb 2024 18:06:02 +0100 Subject: [PATCH 20/49] Add example for OffsetDateTime --- magidoc.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/magidoc.mjs b/magidoc.mjs index a02976f4bcc..bb138f3c87d 100644 --- a/magidoc.mjs +++ b/magidoc.mjs @@ -35,7 +35,8 @@ To learn how to deactivate it, read the appTitle: 'OTP GTFS GraphQL API', queryGenerationFactories: { 'Polyline': '<>', - 'GeoJson': '<>' + 'GeoJson': '<>', + 'OffsetDateTime': '2024-02-05T18:04:23+0100' }, } }, From 691bdd4735e2bdba6fd5372edd5f68c606dc6cfa Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Feb 2024 14:55:24 +0100 Subject: [PATCH 21/49] Put realtime information into separate object --- .../gtfs/generated/GraphQLDataFetchers.java | 19 +++++++++++---- .../opentripplanner/model/plan/LegTimes.java | 12 ++++------ .../model/plan/ScheduledTransitLeg.java | 12 ++++++++-- .../opentripplanner/apis/gtfs/schema.graphqls | 18 +++++++++----- .../apis/gtfs/expectations/plan-extended.json | 24 +++++++------------ .../apis/gtfs/expectations/plan.json | 24 +++++++------------ .../apis/gtfs/queries/plan-extended.graphql | 12 ++++++---- .../apis/gtfs/queries/plan.graphql | 12 ++++++---- 8 files changed, 74 insertions(+), 59 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 639ba7c8744..fbb246168e1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -503,9 +503,7 @@ public interface GraphQLLeg { } public interface GraphQLLegTimes { - public DataFetcher actual(); - - public DataFetcher delay(); + public DataFetcher realTime(); public DataFetcher scheduled(); } @@ -761,6 +759,12 @@ public interface GraphQLQueryType { public DataFetcher viewer(); } + public interface GraphQLRealtimeInformation { + public DataFetcher predicted(); + + public DataFetcher scheduleOffset(); + } + /** Rental vehicle represents a vehicle that belongs to a rental network. */ public interface GraphQLRentalVehicle { public DataFetcher allowPickupNow(); @@ -1256,6 +1260,10 @@ public interface GraphQLElevationProfileComponent { public DataFetcher elevation(); } + /** + * This type is only here for backwards-compatibility and this API will never return it anymore. + * Please use the leg's `fareProducts` instead. + */ public interface GraphQLFare { public DataFetcher cents(); @@ -1266,7 +1274,10 @@ public interface GraphQLFare { public DataFetcher type(); } - /** Component of the fare (i.e. ticket) for a part of the itinerary */ + /** + * This type is only here for backwards-compatibility and this API will never return it anymore. + * Please use the leg's `fareProducts` instead. + */ public interface GraphQLFareComponent { public DataFetcher cents(); diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index 06b2fb3662b..f3ffe66e0e2 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -1,26 +1,24 @@ package org.opentripplanner.model.plan; import java.time.Duration; +import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimes( - @Nonnull ZonedDateTime scheduled, - @Nullable ZonedDateTime actual, - @Nullable Duration delay -) { +public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable Realtime realTime) { public LegTimes { Objects.requireNonNull(scheduled); } @Nonnull public static LegTimes of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimes(realtime.minus(delay), realtime, delay); + return new LegTimes(realtime.minus(delay), new Realtime(realtime, delay)); } @Nonnull public static LegTimes ofStatic(ZonedDateTime staticTime) { - return new LegTimes(staticTime, staticTime, Duration.ZERO); + return new LegTimes(staticTime, null); } + record Realtime(ZonedDateTime predicted, Duration scheduleOffset) {} } diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 4f6bf98def3..7a1fcacbf31 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -164,12 +164,20 @@ public Accessibility getTripWheelchairAccessibility() { @Override public LegTimes start() { - return LegTimes.of(startTime, getDepartureDelay()); + if (getRealTime()) { + return LegTimes.of(startTime, getDepartureDelay()); + } else { + return LegTimes.ofStatic(startTime); + } } @Override public LegTimes end() { - return LegTimes.of(endTime, getArrivalDelay()); + if (getRealTime()) { + return LegTimes.of(endTime, getArrivalDelay()); + } else { + return LegTimes.ofStatic(endTime); + } } @Override diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 3b6bdad5fa4..3ee9cebe030 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1647,18 +1647,24 @@ type RideHailingEstimate { """ An ISO-8601-formatted datetime with offset, i.e. `2023-06-13T14:30+03:00` for 2:30pm on June 13th 2023 at Helsinki's offset from UTC at that time. + +ISO-8601 allows many different formats but OTP will only return the profile specified in RFC3339. """ -scalar OffsetDateTime +scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") -type LegTimes { - scheduled: OffsetDateTime - actual: OffsetDateTime +type RealtimeInformation { + predicted: OffsetDateTime """ - The delay of the vehicle at a certain place. + The delay or "earliness" of the vehicle at a certain place. If the vehicle is early then this is a negative duration. """ - delay: Duration + scheduleOffset: Duration +} + +type LegTimes { + scheduled: OffsetDateTime + realTime: RealtimeInformation } type Leg { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index fde24b8697a..ade6fa4465d 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -20,13 +20,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "actual" : "2020-02-02T11:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "actual" : "2020-02-02T11:00:20Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "A", @@ -56,13 +54,11 @@ "mode" : "BUS", "start" : { "scheduled" : "2020-02-02T11:01:00Z", - "actual" : "2020-02-02T11:01:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:15:00Z", - "actual" : "2020-02-02T11:15:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "B", @@ -102,13 +98,11 @@ "mode" : "RAIL", "start" : { "scheduled" : "2020-02-02T11:30:00Z", - "actual" : "2020-02-02T11:30:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "C", @@ -168,13 +162,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "actual" : "2020-02-02T12:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "D", diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 6865eb282d4..522f43723df 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -10,13 +10,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "actual" : "2020-02-02T11:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "actual" : "2020-02-02T11:00:20Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "A", @@ -39,13 +37,11 @@ "mode" : "BUS", "start" : { "scheduled" : "2020-02-02T11:01:00Z", - "actual" : "2020-02-02T11:01:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:15:00Z", - "actual" : "2020-02-02T11:15:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "B", @@ -74,13 +70,11 @@ "mode" : "RAIL", "start" : { "scheduled" : "2020-02-02T11:30:00Z", - "actual" : "2020-02-02T11:30:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "C", @@ -109,13 +103,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "actual" : "2020-02-02T11:50:00Z", - "delay" : "PT0S" + "realTime" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "actual" : "2020-02-02T12:00:00Z", - "delay" : "PT0S" + "realTime" : null }, "from" : { "name" : "D", 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 1c90f773677..8b3e0c6db16 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 @@ -33,13 +33,17 @@ mode start { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } end { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } from { name diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 5af473c7323..e21a24737ea 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -23,13 +23,17 @@ mode start { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } end { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } from { name From ce002b8da60044966f42ff675507399cf6164578 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Feb 2024 14:58:33 +0100 Subject: [PATCH 22/49] Fix combined leg --- .../ext/fares/impl/CombinedInterlinedTransitLeg.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index c1497373851..0b192a9ec77 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java @@ -59,12 +59,12 @@ public Trip getTrip() { @Override public LegTimes start() { - return LegTimes.of(getEndTime(), getDepartureDelay()); + return first.start(); } @Override public LegTimes end() { - return LegTimes.of(getStartTime(), getArrivalDelay()); + return second.end(); } @Override From afb53e193e9f528b8f58430806e329d1ce2845bb Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 9 Feb 2024 15:09:45 +0100 Subject: [PATCH 23/49] Fix tutorial docs --- docs/apis/GraphQL-Tutorial.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index c98411fd20d..0eff55fff7b 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -94,13 +94,17 @@ Most people want to get routing results out of OTP, so lets see the query for th mode start { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } end { scheduled - actual - delay + realTime { + predicted + scheduleOffset + } } from { name From 4197aed06d652c52aa2667cb3e9618f91560f260 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 11 Feb 2024 22:24:06 +0100 Subject: [PATCH 24/49] Set transit delay --- .../apis/gtfs/GraphQLIntegrationTest.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index d89afea6f9d..4ce1c181f97 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -52,6 +52,7 @@ import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.RelativeDirection; import org.opentripplanner.model.plan.ScheduledTransitLeg; +import org.opentripplanner.model.plan.ScheduledTransitLegBuilder; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.model.plan.WalkStepBuilder; import org.opentripplanner.routing.alertpatch.AlertCause; @@ -61,7 +62,6 @@ import org.opentripplanner.routing.alertpatch.TimePeriod; import org.opentripplanner.routing.alertpatch.TransitAlert; import org.opentripplanner.routing.api.request.RouteRequest; -import org.opentripplanner.routing.core.FareType; import org.opentripplanner.routing.graph.Graph; import org.opentripplanner.routing.graphfinder.GraphFinder; import org.opentripplanner.routing.graphfinder.NearbyStop; @@ -86,6 +86,7 @@ import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.RegularStop; import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; import org.opentripplanner.transit.model.timetable.TripTimesFactory; import org.opentripplanner.transit.service.DefaultTransitService; import org.opentripplanner.transit.service.TransitModel; @@ -179,6 +180,23 @@ static void setup() { .carHail(D10m, E) .build(); + i1.transformTransitLegs(tl -> { + if(tl instanceof ScheduledTransitLeg stl){ + var x= new ScheduledTransitLegBuilder<>(stl); + var rtt = (RealTimeTripTimes) stl.getTripTimes(); + + for(var i=0; i < rtt.getNumStops();i++){ + + var time = rtt.getArrivalTime(i); + rtt.updateArrivalTime(i, time + 10*60); + + } + return x.withTripTimes(rtt).build(); + + } + else return tl; + }); + var busLeg = i1.getTransitLeg(1); var railLeg = (ScheduledTransitLeg) i1.getTransitLeg(2); From a534dd34e8dc7b65bce6632e5f46094812e6e470 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 12 Feb 2024 13:16:57 +0100 Subject: [PATCH 25/49] Use 'estimated' instead of 'realTime' --- docs/apis/GraphQL-Tutorial.md | 8 ++-- .../gtfs/generated/GraphQLDataFetchers.java | 8 ++-- .../opentripplanner/model/plan/LegTimes.java | 7 ++- .../opentripplanner/apis/gtfs/schema.graphqls | 6 +-- .../apis/gtfs/GraphQLIntegrationTest.java | 33 +++++++------- .../apis/gtfs/expectations/plan-extended.json | 44 ++++++++++++------- .../apis/gtfs/expectations/plan.json | 36 ++++++++++----- .../apis/gtfs/queries/plan-extended.graphql | 8 ++-- .../apis/gtfs/queries/plan.graphql | 8 ++-- 9 files changed, 90 insertions(+), 68 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 0eff55fff7b..5701ea20954 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -94,15 +94,15 @@ Most people want to get routing results out of OTP, so lets see the query for th mode start { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } end { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } 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 fbb246168e1..b2d37626cf2 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -503,7 +503,7 @@ public interface GraphQLLeg { } public interface GraphQLLegTimes { - public DataFetcher realTime(); + public DataFetcher estimated(); public DataFetcher scheduled(); } @@ -759,10 +759,10 @@ public interface GraphQLQueryType { public DataFetcher viewer(); } - public interface GraphQLRealtimeInformation { - public DataFetcher predicted(); - + public interface GraphQLRealtimeEstimate { public DataFetcher scheduleOffset(); + + public DataFetcher time(); } /** Rental vehicle represents a vehicle that belongs to a rental network. */ diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index f3ffe66e0e2..9206d00b4e3 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -1,24 +1,23 @@ package org.opentripplanner.model.plan; import java.time.Duration; -import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable Realtime realTime) { +public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { public LegTimes { Objects.requireNonNull(scheduled); } @Nonnull public static LegTimes of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimes(realtime.minus(delay), new Realtime(realtime, delay)); + return new LegTimes(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); } @Nonnull public static LegTimes ofStatic(ZonedDateTime staticTime) { return new LegTimes(staticTime, null); } - record Realtime(ZonedDateTime predicted, Duration scheduleOffset) {} + record RealtimeEstimate(ZonedDateTime time, Duration scheduleOffset) {} } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 3ee9cebe030..dc2f61133bf 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1652,8 +1652,8 @@ ISO-8601 allows many different formats but OTP will only return the profile spec """ scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") -type RealtimeInformation { - predicted: OffsetDateTime +type RealtimeEstimate { + time: OffsetDateTime """ The delay or "earliness" of the vehicle at a certain place. @@ -1664,7 +1664,7 @@ type RealtimeInformation { type LegTimes { scheduled: OffsetDateTime - realTime: RealtimeInformation + estimated: RealtimeEstimate } type Leg { diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java index 4ce1c181f97..f630e0cee3c 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLIntegrationTest.java @@ -52,7 +52,6 @@ import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.RelativeDirection; import org.opentripplanner.model.plan.ScheduledTransitLeg; -import org.opentripplanner.model.plan.ScheduledTransitLegBuilder; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.model.plan.WalkStepBuilder; import org.opentripplanner.routing.alertpatch.AlertCause; @@ -116,6 +115,7 @@ class GraphQLIntegrationTest { .parse("2023-02-15T12:03:28+01:00") .toInstant(); static final Instant ALERT_END_TIME = ALERT_START_TIME.plus(1, ChronoUnit.DAYS); + private static final int TEN_MINUTES = 10 * 60; private static GraphQLRequestContext context; @@ -180,22 +180,7 @@ static void setup() { .carHail(D10m, E) .build(); - i1.transformTransitLegs(tl -> { - if(tl instanceof ScheduledTransitLeg stl){ - var x= new ScheduledTransitLegBuilder<>(stl); - var rtt = (RealTimeTripTimes) stl.getTripTimes(); - - for(var i=0; i < rtt.getNumStops();i++){ - - var time = rtt.getArrivalTime(i); - rtt.updateArrivalTime(i, time + 10*60); - - } - return x.withTripTimes(rtt).build(); - - } - else return tl; - }); + add10MinuteDelay(i1); var busLeg = i1.getTransitLeg(1); var railLeg = (ScheduledTransitLeg) i1.getTransitLeg(2); @@ -298,6 +283,20 @@ public TransitAlertService getTransitAlertService() { ); } + private static void add10MinuteDelay(Itinerary i1) { + i1.transformTransitLegs(tl -> { + if (tl instanceof ScheduledTransitLeg stl) { + var rtt = (RealTimeTripTimes) stl.getTripTimes(); + + for (var i = 0; i < rtt.getNumStops(); i++) { + rtt.updateArrivalTime(i, rtt.getArrivalTime(i) + TEN_MINUTES); + rtt.updateDepartureTime(i, rtt.getDepartureTime(i) + TEN_MINUTES); + } + } + return tl; + }); + } + @FilePatternSource(pattern = "src/test/resources/org/opentripplanner/apis/gtfs/queries/*.graphql") @ParameterizedTest(name = "Check GraphQL query in {0}") void graphQL(Path path) throws IOException { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index ade6fa4465d..5a76c7be06e 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -20,11 +20,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "A", @@ -53,12 +53,18 @@ { "mode" : "BUS", "start" : { - "scheduled" : "2020-02-02T11:01:00Z", - "realTime" : null + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:15:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "B", @@ -83,8 +89,8 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:01:00Z", - "departure" : "2020-02-02T11:01:00Z", + "arrival" : "2020-02-02T11:11:00Z", + "departure" : "2020-02-02T11:11:00Z", "stop" : { "name" : "B" } @@ -97,12 +103,18 @@ { "mode" : "RAIL", "start" : { - "scheduled" : "2020-02-02T11:30:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "C", @@ -127,8 +139,8 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:30:00Z", - "departure" : "2020-02-02T11:30:00Z", + "arrival" : "2020-02-02T11:40:00Z", + "departure" : "2020-02-02T11:40:00Z", "stop" : { "name" : "C" } @@ -162,11 +174,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "D", diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 522f43723df..8076a4887d3 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -10,11 +10,11 @@ "mode" : "WALK", "start" : { "scheduled" : "2020-02-02T11:00:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T11:00:20Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "A", @@ -36,12 +36,18 @@ { "mode" : "BUS", "start" : { - "scheduled" : "2020-02-02T11:01:00Z", - "realTime" : null + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:15:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "B", @@ -69,12 +75,18 @@ { "mode" : "RAIL", "start" : { - "scheduled" : "2020-02-02T11:30:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } }, "end" : { - "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "scheduled" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "scheduleOffset" : "PT10M" + } }, "from" : { "name" : "C", @@ -103,11 +115,11 @@ "mode" : "CAR", "start" : { "scheduled" : "2020-02-02T11:50:00Z", - "realTime" : null + "estimated" : null }, "end" : { "scheduled" : "2020-02-02T12:00:00Z", - "realTime" : null + "estimated" : null }, "from" : { "name" : "D", 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 8b3e0c6db16..b805a94a3c2 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 @@ -33,15 +33,15 @@ mode start { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } end { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index e21a24737ea..4bff431420c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -23,15 +23,15 @@ mode start { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } end { scheduled - realTime { - predicted + estimated { + time scheduleOffset } } From 01b04e0e7b5cb337523ab303cc10d4a822c1a968 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 12 Feb 2024 13:54:40 +0100 Subject: [PATCH 26/49] Use LegTimes for intermediate stops --- docs/apis/GraphQL-Tutorial.md | 24 +++++- .../flex/trip/ScheduledDeviatedTripTest.java | 2 +- .../ext/restapi/mapping/PlaceMapper.java | 10 +-- .../apis/gtfs/datafetchers/LegImpl.java | 10 +-- .../apis/gtfs/datafetchers/PlaceImpl.java | 38 ++++----- .../gtfs/generated/GraphQLDataFetchers.java | 4 +- .../apis/transmodel/model/plan/LegType.java | 2 +- .../model/plan/FrequencyTransitLeg.java | 11 +-- .../org/opentripplanner/model/plan/Leg.java | 2 +- .../opentripplanner/model/plan/LegTimes.java | 9 ++ .../model/plan/ScheduledTransitLeg.java | 23 ++++- .../model/plan/StopArrival.java | 56 ++++--------- .../algorithm/mapping/AlertToLegMapper.java | 6 +- .../opentripplanner/apis/gtfs/schema.graphqls | 4 +- .../apis/gtfs/expectations/plan-extended.json | 32 ++++++- .../apis/gtfs/expectations/plan.json | 84 +++++++++++++++---- .../apis/gtfs/queries/plan-extended.graphql | 16 +++- .../apis/gtfs/queries/plan.graphql | 24 +++++- 18 files changed, 237 insertions(+), 120 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 5701ea20954..863aa8bd57c 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -110,15 +110,31 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - departure - arrival + departure { + scheduled + estimated { + time + scheduleOffset + } + } + arrival { + scheduled + estimated { + time + scheduleOffset + } + } } to { name lat lon - departure - arrival + departure { + scheduled + } + arrival { + scheduled + } } route { gtfsId diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java index e0f85676034..c8450a2e7cb 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java @@ -185,7 +185,7 @@ void flexTripInTransitMode() { var intermediateStops = leg.getIntermediateStops(); assertEquals(1, intermediateStops.size()); - assertEquals("zone_1", intermediateStops.get(0).place.stop.getId().getId()); + assertEquals("zone_1", intermediateStops.get(0).place().stop.getId().getId()); EncodedPolyline legGeometry = EncodedPolyline.encode(leg.getLegGeometry()); assertThatPolylinesAreEqual( diff --git a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java index b1eb3410af8..95669d4b7ca 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java @@ -38,11 +38,11 @@ public List mapStopArrivals(Collection domain) { public ApiPlace mapStopArrival(StopArrival domain) { return mapPlace( - domain.place, - domain.arrival, - domain.departure, - domain.stopPosInPattern, - domain.gtfsStopSequence + domain.place(), + domain.arrival().time(), + domain.departure().time(), + domain.stopPosInPattern(), + domain.gtfsStopSequence() ); } 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 239ba0e28cf..9a6076ecd08 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -100,8 +100,8 @@ public DataFetcher from() { Leg source = getSource(environment); return new StopArrival( source.getFrom(), - source.getStartTime(), - source.getStartTime(), + source.start(), + source.start(), source.getBoardStopPosInPattern(), source.getBoardingGtfsStopSequence() ); @@ -144,7 +144,7 @@ public DataFetcher> intermediateStops() { } return intermediateStops .stream() - .map(intermediateStop -> intermediateStop.place.stop) + .map(intermediateStop -> intermediateStop.place().stop) .filter(Objects::nonNull) .collect(Collectors.toList()); }; @@ -244,8 +244,8 @@ public DataFetcher to() { Leg source = getSource(environment); return new StopArrival( source.getTo(), - source.getEndTime(), - source.getEndTime(), + source.end(), + source.end(), source.getAlightStopPosInPattern(), source.getAlightGtfsStopSequence() ); diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 28cd088cf86..8d1434a033c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -2,12 +2,12 @@ import graphql.schema.DataFetcher; import graphql.schema.DataFetchingEnvironment; -import java.time.OffsetDateTime; import org.opentripplanner.apis.gtfs.generated.GraphQLDataFetchers; import org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLVertexType; 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.LegTimes; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.VertexType; @@ -19,14 +19,14 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override - public DataFetcher arrival() { - return environment -> getSource(environment).arrival.toOffsetDateTime(); + public DataFetcher arrival() { + return environment -> getSource(environment).arrival(); } @Deprecated @Override public DataFetcher arrivalTime() { - return environment -> getSource(environment).arrival.toInstant().toEpochMilli(); + return environment -> getSource(environment).arrival().time().toInstant().toEpochMilli(); } @Override @@ -37,7 +37,7 @@ public DataFetcher bikePark() { @Override public DataFetcher bikeRentalStation() { return environment -> { - Place place = getSource(environment).place; + Place place = getSource(environment).place(); if (!place.vertexType.equals(VertexType.VEHICLERENTAL)) { return null; @@ -54,35 +54,35 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { - return environment -> getSource(environment).departure.toOffsetDateTime(); + public DataFetcher departure() { + return environment -> getSource(environment).departure(); } @Override public DataFetcher departureTime() { - return environment -> getSource(environment).departure.toInstant().toEpochMilli(); + return environment -> getSource(environment).departure().time().toInstant().toEpochMilli(); } @Override public DataFetcher lat() { - return environment -> getSource(environment).place.coordinate.latitude(); + return environment -> getSource(environment).place().coordinate.latitude(); } @Override public DataFetcher lon() { - return environment -> getSource(environment).place.coordinate.longitude(); + return environment -> getSource(environment).place().coordinate.longitude(); } @Override public DataFetcher name() { return environment -> - GraphQLUtils.getTranslation(getSource(environment).place.name, environment); + GraphQLUtils.getTranslation(getSource(environment).place().name, environment); } @Override public DataFetcher rentalVehicle() { return environment -> { - Place place = getSource(environment).place; + Place place = getSource(environment).place(); if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -97,13 +97,13 @@ public DataFetcher rentalVehicle() { @Override public DataFetcher stop() { - return environment -> getSource(environment).place.stop; + return environment -> getSource(environment).place().stop; } @Override public DataFetcher stopPosition() { return environment -> { - var seq = getSource(environment).gtfsStopSequence; + var seq = getSource(environment).gtfsStopSequence(); if (seq != null) { return new PositionAtStop(seq); } else { @@ -120,7 +120,7 @@ public DataFetcher vehicleParking() { @Override public DataFetcher vehicleRentalStation() { return environment -> { - Place place = getSource(environment).place; + Place place = getSource(environment).place(); if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -136,7 +136,7 @@ public DataFetcher vehicleRentalStation() { @Override public DataFetcher vertexType() { return environment -> { - var place = getSource(environment).place; + var place = getSource(environment).place(); return switch (place.vertexType) { case NORMAL -> GraphQLVertexType.NORMAL.name(); case TRANSIT -> GraphQLVertexType.TRANSIT.name(); @@ -147,7 +147,7 @@ public DataFetcher vertexType() { } private VehicleParking getBikePark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place.vehicleParkingWithEntrance; + var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasBicyclePlaces() @@ -159,7 +159,7 @@ private VehicleParking getBikePark(DataFetchingEnvironment environment) { } private VehicleParking getCarPark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place.vehicleParkingWithEntrance; + var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasAnyCarPlaces() @@ -171,7 +171,7 @@ private VehicleParking getCarPark(DataFetchingEnvironment environment) { } private VehicleParking getVehicleParking(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place.vehicleParkingWithEntrance; + var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; if (vehicleParkingWithEntrance == null) { 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 b2d37626cf2..ec8556c45b0 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -591,7 +591,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -601,7 +601,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); 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..99ead9fd8c0 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 @@ -340,7 +340,7 @@ public static GraphQLObjectType create( return ( stops .stream() - .map(stop -> stop.place.stop) + .map(stop -> stop.place().stop) .filter(Objects::nonNull) .collect(Collectors.toList()) ); diff --git a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index d2188fb1b0b..31ccbe31a53 100644 --- a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -1,16 +1,9 @@ package org.opentripplanner.model.plan; -import java.time.LocalDate; -import java.time.ZoneId; -import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nullable; import org.opentripplanner.framework.time.ServiceDateUtils; -import org.opentripplanner.model.transfer.ConstrainedTransfer; -import org.opentripplanner.transit.model.network.TripPattern; import org.opentripplanner.transit.model.site.StopLocation; -import org.opentripplanner.transit.model.timetable.TripTimes; /** * One leg of a trip -- that is, a temporally continuous piece of the journey that takes place on a @@ -62,8 +55,8 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime), + LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), + LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 906e09989c5..139d60b5171 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -455,7 +455,7 @@ default Leg withTimeShift(Duration duration) { default Set getFareZones() { var intermediate = getIntermediateStops() .stream() - .flatMap(stopArrival -> stopArrival.place.stop.getFareZones().stream()); + .flatMap(stopArrival -> stopArrival.place().stop.getFareZones().stream()); var start = getFareZones(this.getFrom()); var end = getFareZones(this.getTo()); diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimes.java index 9206d00b4e3..5e0802c6e4f 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimes.java @@ -19,5 +19,14 @@ public static LegTimes of(ZonedDateTime realtime, int delaySecs) { public static LegTimes ofStatic(ZonedDateTime staticTime) { return new LegTimes(staticTime, null); } + + public ZonedDateTime time() { + if (estimated == null) { + return scheduled; + } else { + return estimated.time; + } + } + record RealtimeEstimate(ZonedDateTime time, Duration scheduleOffset) {} } diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 7a1fcacbf31..0babb9a652f 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -279,10 +279,29 @@ public List getIntermediateStops() { for (int i = boardStopPosInPattern + 1; i < alightStopPosInPattern; i++) { StopLocation stop = tripPattern.getStop(i); + final var arrivalTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getArrivalTime(i) + ); + final var departureTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getDepartureTime(i) + ); + + var arrival = LegTimes.ofStatic(arrivalTime); + var departure = LegTimes.ofStatic(departureTime); + + if (getRealTime()) { + arrival = LegTimes.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTimes.of(departureTime, tripTimes.getDepartureDelay(i)); + } + StopArrival visit = new StopArrival( Place.forStop(stop), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, tripTimes.getArrivalTime(i)), - ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, tripTimes.getDepartureTime(i)), + arrival, + departure, i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 10398768c85..9f5f058ee86 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -1,55 +1,31 @@ package org.opentripplanner.model.plan; -import java.time.ZonedDateTime; import org.opentripplanner.framework.tostring.ToStringBuilder; /** * This class is used to represent a stop arrival event mostly for intermediate visits to a stops * along a route. + * + * @param arrival The time the rider will arrive at the place. + * @param departure The time the rider will depart the place. + * @param stopPosInPattern For transit trips, the stop index (numbered from zero from the start of + * the trip). + * @param gtfsStopSequence For transit trips, the sequence number of the stop. Per GTFS, these + * numbers are increasing. */ -public class StopArrival { - - public final Place place; - /** - * The time the rider will arrive at the place. - */ - public final ZonedDateTime arrival; - - /** - * The time the rider will depart the place. - */ - public final ZonedDateTime departure; - - /** - * For transit trips, the stop index (numbered from zero from the start of the trip). - */ - public final Integer stopPosInPattern; - - /** - * For transit trips, the sequence number of the stop. Per GTFS, these numbers are increasing. - */ - public final Integer gtfsStopSequence; - - public StopArrival( - Place place, - ZonedDateTime arrival, - ZonedDateTime departure, - Integer stopPosInPattern, - Integer gtfsStopSequence - ) { - this.place = place; - this.arrival = arrival; - this.departure = departure; - this.stopPosInPattern = stopPosInPattern; - this.gtfsStopSequence = gtfsStopSequence; - } - +public record StopArrival( + Place place, + LegTimes arrival, + LegTimes departure, + Integer stopPosInPattern, + Integer gtfsStopSequence +) { @Override public String toString() { return ToStringBuilder .of(StopArrival.class) - .addTime("arrival", arrival) - .addTime("departure", departure) + .addObj("arrival", arrival) + .addObj("departure", departure) .addObj("place", place) .toString(); } diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java index dd08ab6095d..425bbf27e35 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java @@ -81,7 +81,7 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { if (leg.getIntermediateStops() != null) { Set stopConditions = StopCondition.PASSING; for (StopArrival visit : leg.getIntermediateStops()) { - if (visit.place.stop instanceof RegularStop stop) { + if (visit.place().stop instanceof RegularStop stop) { Collection alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions); alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions)); alerts.addAll( @@ -91,8 +91,8 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { ) ); - ZonedDateTime stopArrival = visit.arrival; - ZonedDateTime stopDeparture = visit.departure; + ZonedDateTime stopArrival = visit.arrival().time(); + ZonedDateTime stopDeparture = visit.departure().time(); addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture); } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index dc2f61133bf..4fd0a1c3d10 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -2292,10 +2292,10 @@ type Place { lon: Float! "The time the rider will arrive at the place." - arrival: OffsetDateTime + arrival: LegTimes "The time the rider will depart the place." - departure: OffsetDateTime + departure: LegTimes """The stop related to the place.""" stop: Stop diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 5a76c7be06e..6090cdfbf48 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -89,8 +89,20 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:11:00Z", - "departure" : "2020-02-02T11:11:00Z", + "arrival" : { + "scheduled" : "2020-02-02T11:01:00Z", + "estimated" : { + "time" : "2020-02-02T11:11:00Z", + "scheduleOffset" : "PT10M" + } + }, + "departure" : { + "scheduled" : "2020-02-02T11:01:00Z", + "estimated" : { + "time" : "2020-02-02T11:11:00Z", + "scheduleOffset" : "PT10M" + } + }, "stop" : { "name" : "B" } @@ -139,8 +151,20 @@ }, "intermediatePlaces" : [ { - "arrival" : "2020-02-02T11:40:00Z", - "departure" : "2020-02-02T11:40:00Z", + "arrival" : { + "scheduled" : "2020-02-02T11:30:00Z", + "estimated" : { + "time" : "2020-02-02T11:40:00Z", + "scheduleOffset" : "PT10M" + } + }, + "departure" : { + "scheduled" : "2020-02-02T11:30:00Z", + "estimated" : { + "time" : "2020-02-02T11:40:00Z", + "scheduleOffset" : "PT10M" + } + }, "stop" : { "name" : "C" } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 8076a4887d3..a150bd8bf04 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -20,15 +20,25 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departure" : "2020-02-02T11:00:00Z", - "arrival" : "2020-02-02T11:00:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:00:00Z", + "estimated" : null + }, + "arrival" : { + "scheduled" : "2020-02-02T11:00:00Z", + "estimated" : null + } }, "to" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : "2020-02-02T11:00:20Z", - "arrival" : "2020-02-02T11:00:20Z" + "departure" : { + "scheduled" : "2020-02-02T11:00:20Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T11:00:20Z" + } }, "route" : null, "legGeometry" : null @@ -53,15 +63,31 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : "2020-02-02T11:01:00Z", - "arrival" : "2020-02-02T11:01:00Z" + "departure" : { + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } + }, + "arrival" : { + "scheduled" : "2020-02-02T10:51:00Z", + "estimated" : { + "time" : "2020-02-02T11:01:00Z", + "scheduleOffset" : "PT10M" + } + } }, "to" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : "2020-02-02T11:15:00Z", - "arrival" : "2020-02-02T11:15:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:05:00Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T11:05:00Z" + } }, "route" : { "gtfsId" : "F:BUS", @@ -92,15 +118,31 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : "2020-02-02T11:30:00Z", - "arrival" : "2020-02-02T11:30:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } + }, + "arrival" : { + "scheduled" : "2020-02-02T11:20:00Z", + "estimated" : { + "time" : "2020-02-02T11:30:00Z", + "scheduleOffset" : "PT10M" + } + } }, "to" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : "2020-02-02T11:50:00Z", - "arrival" : "2020-02-02T11:50:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:40:00Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T11:40:00Z" + } }, "route" : { "gtfsId" : "F:2", @@ -125,15 +167,25 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : "2020-02-02T11:50:00Z", - "arrival" : "2020-02-02T11:50:00Z" + "departure" : { + "scheduled" : "2020-02-02T11:50:00Z", + "estimated" : null + }, + "arrival" : { + "scheduled" : "2020-02-02T11:50:00Z", + "estimated" : null + } }, "to" : { "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departure" : "2020-02-02T12:00:00Z", - "arrival" : "2020-02-02T12:00:00Z" + "departure" : { + "scheduled" : "2020-02-02T12:00:00Z" + }, + "arrival" : { + "scheduled" : "2020-02-02T12:00:00Z" + } }, "route" : null, "legGeometry" : null 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 b805a94a3c2..e877e05ffe4 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 @@ -68,8 +68,20 @@ tripHeadsign } intermediatePlaces { - arrival - departure + arrival { + scheduled + estimated { + time + scheduleOffset + } + } + departure { + scheduled + estimated { + time + scheduleOffset + } + } stop { name } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 4bff431420c..4a9d7a174ba 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -39,15 +39,31 @@ name lat lon - departure - arrival + departure { + scheduled + estimated { + time + scheduleOffset + } + } + arrival { + scheduled + estimated { + time + scheduleOffset + } + } } to { name lat lon - departure - arrival + departure { + scheduled + } + arrival { + scheduled + } } route { gtfsId From b836c3b664a20d5ac0341c438cef2a7b1bafd110 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 13 Feb 2024 17:23:13 +0100 Subject: [PATCH 27/49] Apply review feedback --- .../impl/CombinedInterlinedTransitLeg.java | 6 +-- .../ext/flex/FlexibleTransitLeg.java | 10 ++--- .../apis/gtfs/datafetchers/LegImpl.java | 6 +-- .../apis/gtfs/datafetchers/PlaceImpl.java | 6 +-- .../gtfs/generated/GraphQLDataFetchers.java | 12 +++--- .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../model/plan/FrequencyTransitLeg.java | 4 +- .../org/opentripplanner/model/plan/Leg.java | 4 +- .../plan/{LegTimes.java => LegTimeEvent.java} | 12 +++--- .../model/plan/ScheduledTransitLeg.java | 20 +++++----- .../model/plan/StopArrival.java | 4 +- .../opentripplanner/model/plan/StreetLeg.java | 8 ++-- .../model/plan/UnknownTransitPathLeg.java | 8 ++-- .../opentripplanner/apis/gtfs/schema.graphqls | 38 +++++++++++++++---- 14 files changed, 81 insertions(+), 59 deletions(-) rename src/main/java/org/opentripplanner/model/plan/{LegTimes.java => LegTimeEvent.java} (56%) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 0b192a9ec77..27a9685b560 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/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.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -58,12 +58,12 @@ public Trip getTrip() { } @Override - public LegTimes start() { + public LegTimeEvent start() { return first.start(); } @Override - public LegTimes end() { + public LegTimeEvent end() { return second.end(); } diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index 25caa9089e9..d793ad1956d 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,7 +16,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -86,13 +86,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimes start() { - return LegTimes.of(startTime, getArrivalDelay()); + public LegTimeEvent start() { + return LegTimeEvent.of(startTime, getArrivalDelay()); } @Override - public LegTimes end() { - return LegTimes.of(endTime, getDepartureDelay()); + public LegTimeEvent end() { + return LegTimeEvent.of(endTime, getDepartureDelay()); } @Override 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 9a6076ecd08..7dc9492fbe3 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -18,7 +18,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,7 +79,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -223,7 +223,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 8d1434a033c..c4908b40aec 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/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.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; 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(); } @@ -54,7 +54,7 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> getSource(environment).departure(); } 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 ec8556c45b0..e84ecfc20f4 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,7 +36,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimes; +import org.opentripplanner.model.plan.LegTimeEvent; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -445,7 +445,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -487,7 +487,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -502,7 +502,7 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } - public interface GraphQLLegTimes { + public interface GraphQLLegTimeEvent { public DataFetcher estimated(); public DataFetcher scheduled(); @@ -591,7 +591,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -601,7 +601,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); 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 ecc7a89fb44..fee61cee936 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 @@ -60,7 +60,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 - LegTimes: org.opentripplanner.model.plan.LegTimes#LegTimes + LegTimeEvent: org.opentripplanner.model.plan.LegTimeEvent#LegTimeEvent Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index 31ccbe31a53..0a620e6c681 100644 --- a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -55,8 +55,8 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), - LegTimes.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), + LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), + LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 139d60b5171..cfb60519572 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,8 +200,8 @@ default Accessibility getTripWheelchairAccessibility() { return null; } - LegTimes start(); - LegTimes end(); + LegTimeEvent start(); + LegTimeEvent end(); /** * The date and time this leg begins. diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimes.java b/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java similarity index 56% rename from src/main/java/org/opentripplanner/model/plan/LegTimes.java rename to src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java index 5e0802c6e4f..b5256429b1f 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimes.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java @@ -6,18 +6,18 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimes(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { - public LegTimes { +public record LegTimeEvent(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { + public LegTimeEvent { Objects.requireNonNull(scheduled); } @Nonnull - public static LegTimes of(ZonedDateTime realtime, int delaySecs) { + public static LegTimeEvent of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimes(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); + return new LegTimeEvent(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); } @Nonnull - public static LegTimes ofStatic(ZonedDateTime staticTime) { - return new LegTimes(staticTime, null); + public static LegTimeEvent ofStatic(ZonedDateTime staticTime) { + return new LegTimeEvent(staticTime, null); } public ZonedDateTime time() { diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index 0babb9a652f..a537e9b81f8 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -163,20 +163,20 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimes start() { + public LegTimeEvent start() { if (getRealTime()) { - return LegTimes.of(startTime, getDepartureDelay()); + return LegTimeEvent.of(startTime, getDepartureDelay()); } else { - return LegTimes.ofStatic(startTime); + return LegTimeEvent.ofStatic(startTime); } } @Override - public LegTimes end() { + public LegTimeEvent end() { if (getRealTime()) { - return LegTimes.of(endTime, getArrivalDelay()); + return LegTimeEvent.of(endTime, getArrivalDelay()); } else { - return LegTimes.ofStatic(endTime); + return LegTimeEvent.ofStatic(endTime); } } @@ -290,12 +290,12 @@ public List getIntermediateStops() { tripTimes.getDepartureTime(i) ); - var arrival = LegTimes.ofStatic(arrivalTime); - var departure = LegTimes.ofStatic(departureTime); + var arrival = LegTimeEvent.ofStatic(arrivalTime); + var departure = LegTimeEvent.ofStatic(departureTime); if (getRealTime()) { - arrival = LegTimes.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = LegTimes.of(departureTime, tripTimes.getDepartureDelay(i)); + arrival = LegTimeEvent.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTimeEvent.of(departureTime, tripTimes.getDepartureDelay(i)); } StopArrival visit = new StopArrival( diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 9f5f058ee86..a1186fb4461 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -15,8 +15,8 @@ */ public record StopArrival( Place place, - LegTimes arrival, - LegTimes departure, + LegTimeEvent arrival, + LegTimeEvent departure, Integer stopPosInPattern, Integer gtfsStopSequence ) { diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 41062995cf4..372c987a5e4 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimes start() { - return LegTimes.ofStatic(startTime); + public LegTimeEvent start() { + return LegTimeEvent.ofStatic(startTime); } @Override - public LegTimes end() { - return LegTimes.ofStatic(endTime); + public LegTimeEvent end() { + return LegTimeEvent.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index 4dfefb086e3..8d1e1c134dd 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -69,13 +69,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimes start() { - return LegTimes.ofStatic(startTime); + public LegTimeEvent start() { + return LegTimeEvent.ofStatic(startTime); } @Override - public LegTimes end() { - return LegTimes.ofStatic(endTime); + public LegTimeEvent end() { + return LegTimeEvent.ofStatic(endTime); } @Override diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 4fd0a1c3d10..4b43dc091e5 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1497,7 +1497,10 @@ type DefaultFareProduct implements FareProduct { } type Itinerary { + "Time when the user leaves from the origin." start: OffsetDateTime + + "Time when the user leaves arrives at the destination." end: OffsetDateTime """Duration of the trip on this itinerary, in seconds.""" @@ -1662,15 +1665,28 @@ type RealtimeEstimate { scheduleOffset: Duration } -type LegTimes { - scheduled: OffsetDateTime +""" +Time information about a passenger at a certain place. May contain real-time information if +available. +""" +type LegTimeEvent { + "The scheduled time of the event." + scheduled: OffsetDateTime! + "The estimated time of the event, if available." estimated: RealtimeEstimate } type Leg { - start: LegTimes - end: LegTimes + """ + The time when the leg starts including real-time information, if available. + """ + start: LegTimeEvent + + """ + The time when the leg ends including real-time information, if available. + """ + end: LegTimeEvent """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode @@ -2291,11 +2307,17 @@ type Place { """Longitude of the place (WGS 84)""" lon: Float! - "The time the rider will arrive at the place." - arrival: LegTimes + """ + The time the rider will arrive at the place. This also includes real-time information + if available. + """ + arrival: LegTimeEvent - "The time the rider will depart the place." - departure: LegTimes + """ + The time the rider will depart the place. This also includes real-time information + if available. + """ + departure: LegTimeEvent """The stop related to the place.""" stop: Stop From bf7dc55191a5cfcd24c853b703769120ccf51eaa Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Wed, 14 Feb 2024 08:11:44 +0100 Subject: [PATCH 28/49] Implement OffsetDateTimeParser --- .../apis/gtfs/GraphQLScalars.java | 39 ++++++++++++---- .../model/scalars/DateTimeScalarFactory.java | 19 +------- .../framework/time/OffsetDateTimeParser.java | 42 +++++++++++++++++ .../time/OffsetDateTimeParserTest.java | 45 +++++++++++++++++++ 4 files changed, 120 insertions(+), 25 deletions(-) create mode 100644 src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java create mode 100644 src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 3e376b60b35..82ef8090d86 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -18,6 +18,7 @@ import org.opentripplanner.framework.geometry.GeometryUtils; import org.opentripplanner.framework.graphql.scalar.DurationScalarFactory; import org.opentripplanner.framework.model.Grams; +import org.opentripplanner.framework.time.OffsetDateTimeParser; public class GraphQLScalars { @@ -25,7 +26,7 @@ public class GraphQLScalars { .registerModule(new JtsModule(GeometryUtils.getGeometryFactory())); public static GraphQLScalarType durationScalar = DurationScalarFactory.createDurationScalar(); - public static GraphQLScalarType polylineScalar = GraphQLScalarType + public static final GraphQLScalarType polylineScalar = GraphQLScalarType .newScalar() .name("Polyline") .description( @@ -54,7 +55,7 @@ public String parseLiteral(Object input) { ) .build(); - public static GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType + public static final GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType .newScalar() .name("OffsetDateTime") .coercing( @@ -66,23 +67,45 @@ public String serialize(@Nonnull Object dataFetcherResult) return zdt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); } else if (dataFetcherResult instanceof OffsetDateTime odt) { return odt.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME); - } else return null; + } else { + throw new CoercingSerializeException( + "Cannot serialize object of class %s".formatted( + dataFetcherResult.getClass().getSimpleName() + ) + ); + } } @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { - return null; + if (input instanceof CharSequence cs) { + return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); + } + throw valueException(input); } @Override public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { - return null; + if (input instanceof StringValue sv) { + return OffsetDateTimeParser + .parseLeniently(sv.getValue()) + .orElseThrow(() -> literalException(input)); + } + throw literalException(input); + } + + private static CoercingParseValueException valueException(Object input) { + return new CoercingParseValueException("Cannot parse %s".formatted(input)); + } + + private static CoercingParseLiteralException literalException(Object input) { + return new CoercingParseLiteralException("Cannot parse %s".formatted(input)); } } ) .build(); - public static GraphQLScalarType geoJsonScalar = GraphQLScalarType + public static final GraphQLScalarType geoJsonScalar = GraphQLScalarType .newScalar() .name("GeoJson") .description("Geographic data structures in JSON format. See: https://geojson.org/") @@ -110,7 +133,7 @@ public Geometry parseLiteral(Object input) throws CoercingParseLiteralException ) .build(); - public static GraphQLScalarType graphQLIDScalar = GraphQLScalarType + public static final GraphQLScalarType graphQLIDScalar = GraphQLScalarType .newScalar() .name("ID") .coercing( @@ -150,7 +173,7 @@ public Relay.ResolvedGlobalId parseLiteral(Object input) ) .build(); - public static GraphQLScalarType gramsScalar = GraphQLScalarType + public static final GraphQLScalarType gramsScalar = GraphQLScalarType .newScalar() .name("Grams") .coercing( diff --git a/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java index 706adc81704..9738a277a41 100644 --- a/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java +++ b/src/main/java/org/opentripplanner/apis/transmodel/model/scalars/DateTimeScalarFactory.java @@ -10,10 +10,10 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; import java.time.temporal.TemporalAccessor; import javax.annotation.Nonnull; +import org.opentripplanner.framework.time.OffsetDateTimeParser; public final class DateTimeScalarFactory { @@ -25,22 +25,7 @@ public final class DateTimeScalarFactory { Example: `2017-04-23T18:25:43+02:00` or `2017-04-23T16:25:43Z`"""; - // We need to have two offsets, in order to parse both "+0200" and "+02:00". The first is not - // really ISO-8601 compatible with the extended date and time. We need to make parsing strict, in - // order to keep the minute mandatory, otherwise we would be left with an unparsed minute - private static final DateTimeFormatter PARSER = new DateTimeFormatterBuilder() - .parseCaseInsensitive() - .parseLenient() - .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME) - .optionalStart() - .parseStrict() - .appendOffset("+HH:MM:ss", "Z") - .parseLenient() - .optionalEnd() - .optionalStart() - .appendOffset("+HHmmss", "Z") - .optionalEnd() - .toFormatter(); + private static final DateTimeFormatter PARSER = OffsetDateTimeParser.LENIENT_PARSER; private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ISO_OFFSET_DATE_TIME; diff --git a/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java new file mode 100644 index 00000000000..11652d797a7 --- /dev/null +++ b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java @@ -0,0 +1,42 @@ +package org.opentripplanner.framework.time; + +import java.time.OffsetDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.DateTimeParseException; +import java.util.Optional; + +public class OffsetDateTimeParser { + + /** + * We need to have two offsets, in order to parse both "+0200" and "+02:00". The first is not + * really ISO-8601 compatible with the extended date and time. We need to make parsing strict, in + * order to keep the minute mandatory, otherwise we would be left with an unparsed minute + */ + public static final DateTimeFormatter LENIENT_PARSER = new DateTimeFormatterBuilder() + .parseCaseInsensitive() + .parseLenient() + .append(DateTimeFormatter.ISO_LOCAL_DATE_TIME) + .optionalStart() + .parseStrict() + .appendOffset("+HH:MM:ss", "Z") + .parseLenient() + .optionalEnd() + .optionalStart() + .appendOffset("+HHmmss", "Z") + .optionalEnd() + .toFormatter(); + + /** + * Parses a ISO-8601 string into am OffsetDateTime instance allowing the offset to be both in + * '02:00' and '0200' format. + */ + public static Optional parseLeniently(CharSequence input) { + try { + var result = OffsetDateTime.parse(input, LENIENT_PARSER); + return Optional.of(result); + } catch (DateTimeParseException e) { + return Optional.empty(); + } + } +} diff --git a/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java new file mode 100644 index 00000000000..1f164ada783 --- /dev/null +++ b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java @@ -0,0 +1,45 @@ +package org.opentripplanner.framework.time; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.time.OffsetDateTime; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +class OffsetDateTimeParserTest { + + private static final String TIME_STRING = "2023-01-27T12:59:00+01:00"; + private static final OffsetDateTime TIME = OffsetDateTime.parse(TIME_STRING); + + static List successfulCases() { + return List.of( + TIME_STRING, + "2023-01-27T12:59:00.000+01:00", + "2023-01-27T12:59:00+0100", + "2023-01-27T12:59:00+01", + "2023-01-27T11:59:00Z", + "2023-01-27T11:59Z", + "2023-01-27T06:59:00-05:00", + "2023-01-27T06:59:00-0500" + ); + } + + @ParameterizedTest + @MethodSource("successfulCases") + void parse(String input) { + var res = OffsetDateTimeParser.parseLeniently(input); + assertTrue(res.get().isEqual(TIME)); + } + + static List failedCases() { + return List.of("2023-01-27T11:59:00", "2023-01-27T11", "2023-01-27T11:00"); + } + + @ParameterizedTest + @MethodSource("failedCases") + void failed(String input) { + var res = OffsetDateTimeParser.parseLeniently(input); + assertTrue(res.isEmpty()); + } +} From 6cb475c4f701c96f4c9dc3cca13d35b9d82393f0 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 11:26:00 +0100 Subject: [PATCH 29/49] Revert to 'LegTime' --- .../impl/CombinedInterlinedTransitLeg.java | 6 +++--- .../ext/flex/FlexibleTransitLeg.java | 10 +++++----- .../apis/gtfs/datafetchers/LegImpl.java | 6 +++--- .../apis/gtfs/datafetchers/PlaceImpl.java | 6 +++--- .../gtfs/generated/GraphQLDataFetchers.java | 16 +++++++++------ .../apis/gtfs/generated/graphql-codegen.yml | 2 +- .../model/plan/FrequencyTransitLeg.java | 4 ++-- .../org/opentripplanner/model/plan/Leg.java | 4 ++-- .../plan/{LegTimeEvent.java => LegTime.java} | 15 ++++++++------ .../model/plan/ScheduledTransitLeg.java | 20 +++++++++---------- .../model/plan/StopArrival.java | 4 ++-- .../opentripplanner/model/plan/StreetLeg.java | 8 ++++---- .../model/plan/UnknownTransitPathLeg.java | 8 ++++---- .../opentripplanner/apis/gtfs/schema.graphqls | 10 +++++----- 14 files changed, 63 insertions(+), 56 deletions(-) rename src/main/java/org/opentripplanner/model/plan/{LegTimeEvent.java => LegTime.java} (52%) diff --git a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java b/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java index 27a9685b560..9d10b87bbd6 100644 --- a/src/ext/java/org/opentripplanner/ext/fares/impl/CombinedInterlinedTransitLeg.java +++ b/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.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -58,12 +58,12 @@ public Trip getTrip() { } @Override - public LegTimeEvent start() { + public LegTime start() { return first.start(); } @Override - public LegTimeEvent end() { + public LegTime end() { return second.end(); } diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index d793ad1956d..e0bdb6cc899 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -16,7 +16,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.Place; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.TransitLeg; @@ -86,13 +86,13 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimeEvent start() { - return LegTimeEvent.of(startTime, getArrivalDelay()); + public LegTime start() { + return LegTime.of(startTime, getArrivalDelay()); } @Override - public LegTimeEvent end() { - return LegTimeEvent.of(endTime, getDepartureDelay()); + public LegTime end() { + return LegTime.of(endTime, getDepartureDelay()); } @Override 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 7dc9492fbe3..f7be76481a7 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -18,7 +18,7 @@ import org.opentripplanner.model.PickDrop; import org.opentripplanner.model.fare.FareProductUse; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.ScheduledTransitLeg; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.StreetLeg; @@ -79,7 +79,7 @@ public DataFetcher duration() { } @Override - public DataFetcher end() { + public DataFetcher end() { return environment -> getSource(environment).end(); } @@ -223,7 +223,7 @@ public DataFetcher serviceDate() { } @Override - public DataFetcher start() { + public DataFetcher start() { return environment -> getSource(environment).start(); } diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index c4908b40aec..16716a393d1 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/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.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; 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(); } @@ -54,7 +54,7 @@ public DataFetcher carPark() { @Deprecated @Override - public DataFetcher departure() { + public DataFetcher departure() { return environment -> getSource(environment).departure(); } 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 e84ecfc20f4..3b4f7889cb4 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -36,7 +36,7 @@ import org.opentripplanner.model.plan.Emissions; import org.opentripplanner.model.plan.Itinerary; import org.opentripplanner.model.plan.Leg; -import org.opentripplanner.model.plan.LegTimeEvent; +import org.opentripplanner.model.plan.LegTime; import org.opentripplanner.model.plan.StopArrival; import org.opentripplanner.model.plan.WalkStep; import org.opentripplanner.routing.alertpatch.TransitAlert; @@ -445,7 +445,7 @@ public interface GraphQLLeg { public DataFetcher duration(); - public DataFetcher end(); + public DataFetcher end(); public DataFetcher endTime(); @@ -487,7 +487,7 @@ public interface GraphQLLeg { public DataFetcher serviceDate(); - public DataFetcher start(); + public DataFetcher start(); public DataFetcher startTime(); @@ -502,7 +502,11 @@ public interface GraphQLLeg { public DataFetcher walkingBike(); } - public interface GraphQLLegTimeEvent { + /** + * Time information about a passenger at a certain place. May contain real-time information if + * available. + */ + public interface GraphQLLegTime { public DataFetcher estimated(); public DataFetcher scheduled(); @@ -591,7 +595,7 @@ public interface GraphQLPattern { } public interface GraphQLPlace { - public DataFetcher arrival(); + public DataFetcher arrival(); public DataFetcher arrivalTime(); @@ -601,7 +605,7 @@ public interface GraphQLPlace { public DataFetcher carPark(); - public DataFetcher departure(); + public DataFetcher departure(); public DataFetcher departureTime(); 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 fee61cee936..55f76863cc6 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 @@ -60,7 +60,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 - LegTimeEvent: org.opentripplanner.model.plan.LegTimeEvent#LegTimeEvent + LegTime: org.opentripplanner.model.plan.LegTime#LegTime Mode: String OccupancyStatus: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLOccupancyStatus#GraphQLOccupancyStatus TransitMode: org.opentripplanner.apis.gtfs.generated.GraphQLTypes.GraphQLTransitMode#GraphQLTransitMode diff --git a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java index 0a620e6c681..48c4b1b7b87 100644 --- a/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/FrequencyTransitLeg.java @@ -55,8 +55,8 @@ public List getIntermediateStops() { StopArrival visit = new StopArrival( Place.forStop(stop), - LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), - LegTimeEvent.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), + LegTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, arrivalTime)), + LegTime.ofStatic(ServiceDateUtils.toZonedDateTime(serviceDate, zoneId, departureTime)), i, tripTimes.gtfsSequenceOfStopIndex(i) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index cfb60519572..e2d7d951556 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,8 +200,8 @@ default Accessibility getTripWheelchairAccessibility() { return null; } - LegTimeEvent start(); - LegTimeEvent end(); + LegTime start(); + LegTime end(); /** * The date and time this leg begins. diff --git a/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java similarity index 52% rename from src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java rename to src/main/java/org/opentripplanner/model/plan/LegTime.java index b5256429b1f..c0b76b7486a 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTimeEvent.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -6,18 +6,21 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; -public record LegTimeEvent(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { - public LegTimeEvent { +/** + * A scheduled time of a transit vehicle at a certain location with a optional realtime information. + */ +public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { + public LegTime { Objects.requireNonNull(scheduled); } @Nonnull - public static LegTimeEvent of(ZonedDateTime realtime, int delaySecs) { + public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTimeEvent(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); + return new LegTime(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); } @Nonnull - public static LegTimeEvent ofStatic(ZonedDateTime staticTime) { - return new LegTimeEvent(staticTime, null); + public static LegTime ofStatic(ZonedDateTime staticTime) { + return new LegTime(staticTime, null); } public ZonedDateTime time() { diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index a537e9b81f8..a4050fc3cb2 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -163,20 +163,20 @@ public Accessibility getTripWheelchairAccessibility() { } @Override - public LegTimeEvent start() { + public LegTime start() { if (getRealTime()) { - return LegTimeEvent.of(startTime, getDepartureDelay()); + return LegTime.of(startTime, getDepartureDelay()); } else { - return LegTimeEvent.ofStatic(startTime); + return LegTime.ofStatic(startTime); } } @Override - public LegTimeEvent end() { + public LegTime end() { if (getRealTime()) { - return LegTimeEvent.of(endTime, getArrivalDelay()); + return LegTime.of(endTime, getArrivalDelay()); } else { - return LegTimeEvent.ofStatic(endTime); + return LegTime.ofStatic(endTime); } } @@ -290,12 +290,12 @@ public List getIntermediateStops() { tripTimes.getDepartureTime(i) ); - var arrival = LegTimeEvent.ofStatic(arrivalTime); - var departure = LegTimeEvent.ofStatic(departureTime); + var arrival = LegTime.ofStatic(arrivalTime); + var departure = LegTime.ofStatic(departureTime); if (getRealTime()) { - arrival = LegTimeEvent.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = LegTimeEvent.of(departureTime, tripTimes.getDepartureDelay(i)); + arrival = LegTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTime.of(departureTime, tripTimes.getDepartureDelay(i)); } StopArrival visit = new StopArrival( diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index a1186fb4461..8a6b55c9346 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -15,8 +15,8 @@ */ public record StopArrival( Place place, - LegTimeEvent arrival, - LegTimeEvent departure, + LegTime arrival, + LegTime departure, Integer stopPosInPattern, Integer gtfsStopSequence ) { diff --git a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java index 372c987a5e4..6384159a4ec 100644 --- a/src/main/java/org/opentripplanner/model/plan/StreetLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/StreetLeg.java @@ -157,13 +157,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimeEvent start() { - return LegTimeEvent.ofStatic(startTime); + public LegTime start() { + return LegTime.ofStatic(startTime); } @Override - public LegTimeEvent end() { - return LegTimeEvent.ofStatic(endTime); + public LegTime end() { + return LegTime.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java index 8d1e1c134dd..df43bbcb411 100644 --- a/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/UnknownTransitPathLeg.java @@ -69,13 +69,13 @@ public boolean hasSameMode(Leg other) { } @Override - public LegTimeEvent start() { - return LegTimeEvent.ofStatic(startTime); + public LegTime start() { + return LegTime.ofStatic(startTime); } @Override - public LegTimeEvent end() { - return LegTimeEvent.ofStatic(endTime); + public LegTime end() { + return LegTime.ofStatic(endTime); } @Override diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 4b43dc091e5..1b1897c5091 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1669,7 +1669,7 @@ type RealtimeEstimate { Time information about a passenger at a certain place. May contain real-time information if available. """ -type LegTimeEvent { +type LegTime { "The scheduled time of the event." scheduled: OffsetDateTime! "The estimated time of the event, if available." @@ -1681,12 +1681,12 @@ type Leg { """ The time when the leg starts including real-time information, if available. """ - start: LegTimeEvent + start: LegTime """ The time when the leg ends including real-time information, if available. """ - end: LegTimeEvent + end: LegTime """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode @@ -2311,13 +2311,13 @@ type Place { The time the rider will arrive at the place. This also includes real-time information if available. """ - arrival: LegTimeEvent + arrival: LegTime """ The time the rider will depart the place. This also includes real-time information if available. """ - departure: LegTimeEvent + departure: LegTime """The stop related to the place.""" stop: Stop From 2130da9590ee39926ee828bb5142a012472b8046 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 11:56:51 +0100 Subject: [PATCH 30/49] Rename fields --- .../gtfs/generated/GraphQLDataFetchers.java | 4 +- .../opentripplanner/model/plan/LegTime.java | 16 ++- .../algorithm/mapping/AlertToLegMapper.java | 4 +- .../opentripplanner/apis/gtfs/schema.graphqls | 6 +- .../apis/gtfs/expectations/plan-extended.json | 128 +++++++++++++++--- .../apis/gtfs/expectations/plan.json | 104 ++++++-------- .../apis/gtfs/queries/plan-extended.graphql | 44 ++++-- .../apis/gtfs/queries/plan.graphql | 34 ++--- 8 files changed, 217 insertions(+), 123 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 3b4f7889cb4..7fab5720b9a 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/generated/GraphQLDataFetchers.java @@ -509,7 +509,7 @@ public interface GraphQLLeg { public interface GraphQLLegTime { public DataFetcher estimated(); - public DataFetcher scheduled(); + public DataFetcher scheduledTime(); } /** A span of time. */ @@ -764,7 +764,7 @@ public interface GraphQLQueryType { } public interface GraphQLRealtimeEstimate { - public DataFetcher scheduleOffset(); + public DataFetcher delay(); public DataFetcher time(); } diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index c0b76b7486a..2dc97b92a11 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -9,9 +9,9 @@ /** * A scheduled time of a transit vehicle at a certain location with a optional realtime information. */ -public record LegTime(@Nonnull ZonedDateTime scheduled, @Nullable RealtimeEstimate estimated) { +public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealtimeEstimate estimated) { public LegTime { - Objects.requireNonNull(scheduled); + Objects.requireNonNull(scheduledTime); } @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { @@ -23,13 +23,21 @@ public static LegTime ofStatic(ZonedDateTime staticTime) { return new LegTime(staticTime, null); } + /** + * The most up-to-date time available: if realtime data is available it is returned, if not then + * the scheduled one is. + */ public ZonedDateTime time() { if (estimated == null) { - return scheduled; + return scheduledTime; } else { return estimated.time; } } - record RealtimeEstimate(ZonedDateTime time, Duration scheduleOffset) {} + /** + * 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/routing/algorithm/mapping/AlertToLegMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java index 425bbf27e35..4b2b194fbe4 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java @@ -91,8 +91,8 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { ) ); - ZonedDateTime stopArrival = visit.arrival().time(); - ZonedDateTime stopDeparture = visit.departure().time(); + ZonedDateTime stopArrival = visit.arrival().scheduledTime(); + ZonedDateTime stopDeparture = visit.departure().scheduledTime(); addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture); } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 1b1897c5091..2f3e2862c01 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1656,13 +1656,13 @@ ISO-8601 allows many different formats but OTP will only return the profile spec scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") type RealtimeEstimate { - time: OffsetDateTime + time: OffsetDateTime! """ The delay or "earliness" of the vehicle at a certain place. If the vehicle is early then this is a negative duration. """ - scheduleOffset: Duration + delay: Duration! } """ @@ -1671,7 +1671,7 @@ available. """ type LegTime { "The scheduled time of the event." - scheduled: OffsetDateTime! + scheduledTime: OffsetDateTime! "The estimated time of the event, if available." estimated: RealtimeEstimate } diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index 6090cdfbf48..bfb6d969cc7 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -19,17 +19,25 @@ { "mode" : "WALK", "start" : { - "scheduled" : "2020-02-02T11:00:00Z", + "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, "end" : { - "scheduled" : "2020-02-02T11:00:20Z", + "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, "from" : { "name" : "A", "lat" : 5.0, "lon" : 8.0, + "departure" : { + "scheduledTime" : "2020-02-02T11:00:00Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:00:00Z", + "estimated" : null + }, "departureTime" : 1580641200000, "arrivalTime" : 1580641200000 }, @@ -37,6 +45,14 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, + "departure" : { + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null + }, "departureTime" : 1580641220000, "arrivalTime" : 1580641220000 }, @@ -53,23 +69,37 @@ { "mode" : "BUS", "start" : { - "scheduled" : "2020-02-02T10:51:00Z", + "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "end" : { - "scheduled" : "2020-02-02T11:05:00Z", + "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "time" : "2020-02-02T11:15:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "from" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, + "departure" : { + "scheduledTime" : "2020-02-02T10:51:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:01:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T10:51:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:01:00Z" + } + }, "departureTime" : 1580641260000, "arrivalTime" : 1580641260000 }, @@ -77,6 +107,20 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, + "departure" : { + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:15:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:15:00Z" + } + }, "departureTime" : 1580642100000, "arrivalTime" : 1580642100000 }, @@ -90,17 +134,17 @@ "intermediatePlaces" : [ { "arrival" : { - "scheduled" : "2020-02-02T11:01:00Z", + "scheduledTime" : "2020-02-02T11:01:00Z", "estimated" : { "time" : "2020-02-02T11:11:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "departure" : { - "scheduled" : "2020-02-02T11:01:00Z", + "scheduledTime" : "2020-02-02T11:01:00Z", "estimated" : { "time" : "2020-02-02T11:11:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "stop" : { @@ -115,23 +159,37 @@ { "mode" : "RAIL", "start" : { - "scheduled" : "2020-02-02T11:20:00Z", + "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "end" : { - "scheduled" : "2020-02-02T11:40:00Z", + "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "time" : "2020-02-02T11:50:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "from" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, + "departure" : { + "scheduledTime" : "2020-02-02T11:20:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:30:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:20:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:30:00Z" + } + }, "departureTime" : 1580643000000, "arrivalTime" : 1580643000000 }, @@ -139,6 +197,20 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, + "departure" : { + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:50:00Z" + } + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "delay" : "PT10M", + "time" : "2020-02-02T11:50:00Z" + } + }, "departureTime" : 1580644200000, "arrivalTime" : 1580644200000 }, @@ -152,17 +224,17 @@ "intermediatePlaces" : [ { "arrival" : { - "scheduled" : "2020-02-02T11:30:00Z", + "scheduledTime" : "2020-02-02T11:30:00Z", "estimated" : { "time" : "2020-02-02T11:40:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "departure" : { - "scheduled" : "2020-02-02T11:30:00Z", + "scheduledTime" : "2020-02-02T11:30:00Z", "estimated" : { "time" : "2020-02-02T11:40:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "stop" : { @@ -197,17 +269,25 @@ { "mode" : "CAR", "start" : { - "scheduled" : "2020-02-02T11:50:00Z", + "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, "end" : { - "scheduled" : "2020-02-02T12:00:00Z", + "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, "from" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, + "departure" : { + "scheduledTime" : "2020-02-02T11:50:00Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T11:50:00Z", + "estimated" : null + }, "departureTime" : 1580644200000, "arrivalTime" : 1580644200000 }, @@ -215,6 +295,14 @@ "name" : "E", "lat" : 9.0, "lon" : 10.0, + "departure" : { + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null + }, + "arrival" : { + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null + }, "departureTime" : 1580644800000, "arrivalTime" : 1580644800000 }, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index a150bd8bf04..72d0cc017fe 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -8,24 +8,16 @@ "legs" : [ { "mode" : "WALK", - "start" : { - "scheduled" : "2020-02-02T11:00:00Z", - "estimated" : null - }, - "end" : { - "scheduled" : "2020-02-02T11:00:20Z", - "estimated" : null - }, "from" : { "name" : "A", "lat" : 5.0, "lon" : 8.0, "departure" : { - "scheduled" : "2020-02-02T11:00:00Z", + "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T11:00:00Z", + "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null } }, @@ -34,10 +26,12 @@ "lat" : 6.0, "lon" : 8.5, "departure" : { - "scheduled" : "2020-02-02T11:00:20Z" + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T11:00:20Z" + "scheduledTime" : "2020-02-02T11:00:20Z", + "estimated" : null } }, "route" : null, @@ -45,36 +39,22 @@ }, { "mode" : "BUS", - "start" : { - "scheduled" : "2020-02-02T10:51:00Z", - "estimated" : { - "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" - } - }, - "end" : { - "scheduled" : "2020-02-02T11:05:00Z", - "estimated" : { - "time" : "2020-02-02T11:15:00Z", - "scheduleOffset" : "PT10M" - } - }, "from" : { "name" : "B", "lat" : 6.0, "lon" : 8.5, "departure" : { - "scheduled" : "2020-02-02T10:51:00Z", + "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "arrival" : { - "scheduled" : "2020-02-02T10:51:00Z", + "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } } }, @@ -83,10 +63,18 @@ "lat" : 7.0, "lon" : 9.0, "departure" : { - "scheduled" : "2020-02-02T11:05:00Z" + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "delay" : "PT10M" + } }, "arrival" : { - "scheduled" : "2020-02-02T11:05:00Z" + "scheduledTime" : "2020-02-02T11:05:00Z", + "estimated" : { + "time" : "2020-02-02T11:15:00Z", + "delay" : "PT10M" + } } }, "route" : { @@ -100,36 +88,22 @@ }, { "mode" : "RAIL", - "start" : { - "scheduled" : "2020-02-02T11:20:00Z", - "estimated" : { - "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" - } - }, - "end" : { - "scheduled" : "2020-02-02T11:40:00Z", - "estimated" : { - "time" : "2020-02-02T11:50:00Z", - "scheduleOffset" : "PT10M" - } - }, "from" : { "name" : "C", "lat" : 7.0, "lon" : 9.0, "departure" : { - "scheduled" : "2020-02-02T11:20:00Z", + "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } }, "arrival" : { - "scheduled" : "2020-02-02T11:20:00Z", + "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", - "scheduleOffset" : "PT10M" + "delay" : "PT10M" } } }, @@ -138,10 +112,18 @@ "lat" : 8.0, "lon" : 9.5, "departure" : { - "scheduled" : "2020-02-02T11:40:00Z" + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "delay" : "PT10M" + } }, "arrival" : { - "scheduled" : "2020-02-02T11:40:00Z" + "scheduledTime" : "2020-02-02T11:40:00Z", + "estimated" : { + "time" : "2020-02-02T11:50:00Z", + "delay" : "PT10M" + } } }, "route" : { @@ -155,24 +137,16 @@ }, { "mode" : "CAR", - "start" : { - "scheduled" : "2020-02-02T11:50:00Z", - "estimated" : null - }, - "end" : { - "scheduled" : "2020-02-02T12:00:00Z", - "estimated" : null - }, "from" : { "name" : "D", "lat" : 8.0, "lon" : 9.5, "departure" : { - "scheduled" : "2020-02-02T11:50:00Z", + "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T11:50:00Z", + "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null } }, @@ -181,10 +155,12 @@ "lat" : 9.0, "lon" : 10.0, "departure" : { - "scheduled" : "2020-02-02T12:00:00Z" + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null }, "arrival" : { - "scheduled" : "2020-02-02T12:00:00Z" + "scheduledTime" : "2020-02-02T12:00:00Z", + "estimated" : null } }, "route" : null, 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 e877e05ffe4..dcec1a1026c 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 @@ -32,23 +32,37 @@ legs { mode start { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } end { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } from { name lat lon + departure { + scheduledTime + estimated { + delay + time + } + } + arrival { + scheduledTime + estimated { + delay + time + } + } departureTime arrivalTime } @@ -56,6 +70,20 @@ name lat lon + departure { + scheduledTime + estimated { + delay + time + } + } + arrival { + scheduledTime + estimated { + delay + time + } + } departureTime arrivalTime } @@ -69,17 +97,17 @@ } intermediatePlaces { arrival { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } departure { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } stop { diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 4a9d7a174ba..635b9f1531a 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -21,36 +21,22 @@ end legs { mode - start { - scheduled - estimated { - time - scheduleOffset - } - } - end { - scheduled - estimated { - time - scheduleOffset - } - } from { name lat lon departure { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } arrival { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } } @@ -59,10 +45,18 @@ lat lon departure { - scheduled + scheduledTime + estimated { + time + delay + } } arrival { - scheduled + scheduledTime + estimated { + time + delay + } } } route { From 8b37735a018140d703b40f53838b44a7df0cde48 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 12:04:45 +0100 Subject: [PATCH 31/49] Improve scalars --- docs/apis/GraphQL-Tutorial.md | 34 +++++----- magidoc.mjs | 2 +- .../apis/gtfs/GraphQLScalars.java | 18 ++---- .../apis/gtfs/GraphQLScalarsTest.java | 62 +++++++++++++------ 4 files changed, 63 insertions(+), 53 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 863aa8bd57c..1a56d02b6ca 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -92,36 +92,22 @@ Most people want to get routing results out of OTP, so lets see the query for th end legs { mode - start { - scheduled - estimated { - time - scheduleOffset - } - } - end { - scheduled - estimated { - time - scheduleOffset - } - } from { name lat lon departure { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } arrival { - scheduled + scheduledTime estimated { time - scheduleOffset + delay } } } @@ -130,10 +116,18 @@ Most people want to get routing results out of OTP, so lets see the query for th lat lon departure { - scheduled + scheduledTime + estimated { + time + delay + } } arrival { - scheduled + scheduledTime + estimated { + time + delay + } } } route { diff --git a/magidoc.mjs b/magidoc.mjs index bb138f3c87d..a57b17a4308 100644 --- a/magidoc.mjs +++ b/magidoc.mjs @@ -36,7 +36,7 @@ To learn how to deactivate it, read the queryGenerationFactories: { 'Polyline': '<>', 'GeoJson': '<>', - 'OffsetDateTime': '2024-02-05T18:04:23+0100' + 'OffsetDateTime': '2024-02-05T18:04:23+01:00' }, } }, diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 82ef8090d86..e6ab9f7dd5d 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -79,9 +79,11 @@ public String serialize(@Nonnull Object dataFetcherResult) @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { if (input instanceof CharSequence cs) { - return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); + return OffsetDateTimeParser + .parseLeniently(cs) + .orElseThrow(CoercingParseValueException::new); } - throw valueException(input); + throw new CoercingParseValueException(); } @Override @@ -89,17 +91,9 @@ public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralExce if (input instanceof StringValue sv) { return OffsetDateTimeParser .parseLeniently(sv.getValue()) - .orElseThrow(() -> literalException(input)); + .orElseThrow(CoercingParseLiteralException::new); } - throw literalException(input); - } - - private static CoercingParseValueException valueException(Object input) { - return new CoercingParseValueException("Cannot parse %s".formatted(input)); - } - - private static CoercingParseLiteralException literalException(Object input) { - return new CoercingParseLiteralException("Cannot parse %s".formatted(input)); + throw new CoercingParseLiteralException(); } } ) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 079749f3ccc..652c72254d9 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -4,6 +4,7 @@ import static org.junit.jupiter.params.provider.Arguments.of; import com.fasterxml.jackson.core.JsonProcessingException; +import graphql.language.StringValue; import graphql.schema.CoercingSerializeException; import java.time.Duration; import java.time.LocalDate; @@ -12,6 +13,7 @@ import java.time.ZoneOffset; import java.util.List; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -23,7 +25,7 @@ class GraphQLScalarsTest { - private static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( + static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( LocalDate.of(2024, 2, 4), LocalTime.MIDNIGHT, ZoneOffset.UTC @@ -71,25 +73,45 @@ void geoJson() throws JsonProcessingException { assertEquals(jsonNode.toString(), geoJson.toString()); } - static List offsetDateTimeCases() { - return List.of( - of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), - of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), - "2024-02-04T01:00:00+01:00" - ), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), - "2024-02-03T19:00:00-05:00" - ) - ); - } + @Nested + class OffsetDateTimeTests { - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void duration(OffsetDateTime odt, String expected) { - var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); - assertEquals(expected, string); + static List offsetDateTimeCases() { + return List.of( + of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), + of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), + "2024-02-04T01:00:00+01:00" + ), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), + "2024-02-03T19:00:00-05:00" + ) + ); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void serializeOffsetDateTime(OffsetDateTime odt, String expected) { + var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + assertEquals(expected, string); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTime(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); + assertEquals(expected, odt); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar + .getCoercing() + .parseLiteral(new StringValue(input)); + assertEquals(expected, odt); + } } } From 4d295da420d2b7d1fb4fabcd88d5c5829a32a3c7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 19 Feb 2024 14:08:52 +0100 Subject: [PATCH 32/49] Throw exception in scalar again --- .../opentripplanner/apis/gtfs/GraphQLScalars.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index e6ab9f7dd5d..7d70f4be3b5 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -79,11 +79,9 @@ public String serialize(@Nonnull Object dataFetcherResult) @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { if (input instanceof CharSequence cs) { - return OffsetDateTimeParser - .parseLeniently(cs) - .orElseThrow(CoercingParseValueException::new); + return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); } - throw new CoercingParseValueException(); + throw valueException(input); } @Override @@ -95,6 +93,12 @@ public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralExce } throw new CoercingParseLiteralException(); } + + private static CoercingParseValueException valueException(Object input) { + return new CoercingParseValueException( + "Cannot parse %s into an OffsetDateTime.".formatted(input) + ); + } } ) .build(); From 92c7acd14e5b204c1d82d21ee35c5a2583f246a5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 07:16:51 +0100 Subject: [PATCH 33/49] Switch order of arrival, departure --- docs/apis/GraphQL-Tutorial.md | 8 ++--- .../apis/gtfs/expectations/plan-extended.json | 32 +++++++++---------- .../apis/gtfs/expectations/plan.json | 32 +++++++++---------- .../apis/gtfs/queries/plan-extended.graphql | 8 ++--- .../apis/gtfs/queries/plan.graphql | 8 ++--- 5 files changed, 44 insertions(+), 44 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 1a56d02b6ca..7e1f6b0f6db 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -96,14 +96,14 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time @@ -115,14 +115,14 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json index bfb6d969cc7..ea58480be8e 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan-extended.json @@ -30,11 +30,11 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, @@ -45,11 +45,11 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, @@ -86,14 +86,14 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:01:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "delay" : "PT10M", @@ -107,14 +107,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:15:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "delay" : "PT10M", @@ -176,14 +176,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:30:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "delay" : "PT10M", @@ -197,14 +197,14 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "delay" : "PT10M", "time" : "2020-02-02T11:50:00Z" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "delay" : "PT10M", @@ -280,11 +280,11 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, @@ -295,11 +295,11 @@ "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index 72d0cc017fe..ec971af5b3c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -12,11 +12,11 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null } @@ -25,11 +25,11 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null } @@ -43,14 +43,14 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { "time" : "2020-02-02T11:01:00Z", @@ -62,14 +62,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "time" : "2020-02-02T11:15:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:05:00Z", "estimated" : { "time" : "2020-02-02T11:15:00Z", @@ -92,14 +92,14 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { "time" : "2020-02-02T11:30:00Z", @@ -111,14 +111,14 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "time" : "2020-02-02T11:50:00Z", "delay" : "PT10M" } }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:40:00Z", "estimated" : { "time" : "2020-02-02T11:50:00Z", @@ -141,11 +141,11 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null } @@ -154,11 +154,11 @@ "name" : "E", "lat" : 9.0, "lon" : 10.0, - "departure" : { + "arrival" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null }, - "arrival" : { + "departure" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null } 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 dcec1a1026c..bcd96892e84 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 @@ -49,14 +49,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { delay time } } - arrival { + departure { scheduledTime estimated { delay @@ -70,14 +70,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { delay time } } - arrival { + departure { scheduledTime estimated { delay diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index 635b9f1531a..cc93ffb211c 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -25,14 +25,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time @@ -44,14 +44,14 @@ name lat lon - departure { + arrival { scheduledTime estimated { time delay } } - arrival { + departure { scheduledTime estimated { time From 39f06dcc5cf026317674917a30de66d53c0bb8e7 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 07:32:05 +0100 Subject: [PATCH 34/49] Add documentation --- src/main/java/org/opentripplanner/model/plan/Leg.java | 7 +++++++ .../org/opentripplanner/apis/gtfs/schema.graphqls | 7 ++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index e2d7d951556..0063ecf87c2 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -200,7 +200,14 @@ default Accessibility getTripWheelchairAccessibility() { return null; } + /** + * The time (including realtime information) when the leg starts. + */ LegTime start(); + + /** + * The time (including realtime information) when the leg ends.. + */ LegTime end(); /** diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 2f3e2862c01..93de5101451 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1655,6 +1655,7 @@ ISO-8601 allows many different formats but OTP will only return the profile spec """ scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") +"Real-time estimates for a vehicle at a certain place." type RealtimeEstimate { time: OffsetDateTime! """ @@ -1672,7 +1673,7 @@ available. type LegTime { "The scheduled time of the event." scheduledTime: OffsetDateTime! - "The estimated time of the event, if available." + "The estimated time of the event. If no real-time information is available, this is null," estimated: RealtimeEstimate } @@ -1681,12 +1682,12 @@ type Leg { """ The time when the leg starts including real-time information, if available. """ - start: LegTime + start: LegTime! """ The time when the leg ends including real-time information, if available. """ - end: LegTime + end: LegTime! """The mode (e.g. `WALK`) used when traversing this leg.""" mode: Mode From b4707ed4c635f2451b3741212e8dbdc61eeef8b8 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 09:00:33 +0100 Subject: [PATCH 35/49] Add test for leg times --- .../model/plan/ScheduledTransitLegTest.java | 65 +++++++++++++++---- 1 file changed, 54 insertions(+), 11 deletions(-) diff --git a/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java b/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java index e45beb8ebad..b41ace81e8d 100644 --- a/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java +++ b/src/test/java/org/opentripplanner/model/plan/ScheduledTransitLegTest.java @@ -1,6 +1,8 @@ package org.opentripplanner.model.plan; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.opentripplanner.transit.model._data.TransitModelForTest.id; import java.time.OffsetDateTime; @@ -9,33 +11,74 @@ import org.junit.jupiter.api.Test; import org.opentripplanner._support.time.ZoneIds; import org.opentripplanner.transit.model._data.TransitModelForTest; +import org.opentripplanner.transit.model.network.Route; +import org.opentripplanner.transit.model.network.TripPattern; +import org.opentripplanner.transit.model.timetable.RealTimeTripTimes; +import org.opentripplanner.transit.model.timetable.ScheduledTripTimes; +import org.opentripplanner.transit.model.timetable.Trip; class ScheduledTransitLegTest { static final ZonedDateTime TIME = OffsetDateTime .parse("2023-04-17T17:49:06+02:00") .toZonedDateTime(); + private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of(); + private static final Route ROUTE = TransitModelForTest.route(id("2")).build(); + private static final TripPattern PATTERN = TransitModelForTest + .tripPattern("1", ROUTE) + .withStopPattern(TEST_MODEL.stopPattern(3)) + .build(); + private static final Trip TRIP = TransitModelForTest.trip("trip1").build(); + private static final ScheduledTripTimes TRIP_TIMES = ScheduledTripTimes + .of() + .withArrivalTimes("10:00 11:00 12:00") + .withDepartureTimes("10:01 11:02 12:03") + .withTrip(TRIP) + .build(); @Test void defaultFares() { - var testModel = TransitModelForTest.of(); - var route = TransitModelForTest.route(id("2")).build(); - var pattern = TransitModelForTest - .tripPattern("1", route) - .withStopPattern(testModel.stopPattern(3)) + var leg = builder().build(); + + assertEquals(List.of(), leg.fareProducts()); + } + + @Test + void legTimesWithoutRealTime() { + var leg = builder().withTripTimes(TRIP_TIMES).build(); + + assertNull(leg.start().estimated()); + assertNull(leg.end().estimated()); + } + + @Test + void legTimesWithRealTime() { + var tt = ScheduledTripTimes + .of() + .withArrivalTimes("10:00 11:00 12:00") + .withDepartureTimes("10:01 11:02 12:03") + .withTrip(TRIP) .build(); - var leg = new ScheduledTransitLegBuilder() + + var rtt = RealTimeTripTimes.of(tt); + rtt.updateArrivalTime(0, 111); + + var leg = builder().withTripTimes(rtt).build(); + + assertNotNull(leg.start().estimated()); + assertNotNull(leg.end().estimated()); + } + + private static ScheduledTransitLegBuilder builder() { + return new ScheduledTransitLegBuilder() .withTripTimes(null) - .withTripPattern(pattern) + .withTripPattern(PATTERN) .withBoardStopIndexInPattern(0) .withAlightStopIndexInPattern(2) .withStartTime(TIME) .withEndTime(TIME.plusMinutes(10)) .withServiceDate(TIME.toLocalDate()) .withZoneId(ZoneIds.BERLIN) - .withGeneralizedCost(100) - .build(); - - assertEquals(List.of(), leg.fareProducts()); + .withGeneralizedCost(100); } } From 54c21a54a859bc2d692b439932fa67b095cc0137 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 20 Feb 2024 09:04:43 +0100 Subject: [PATCH 36/49] Fix flex leg and spelling --- .../org/opentripplanner/ext/flex/FlexibleTransitLeg.java | 4 ++-- src/main/java/org/opentripplanner/model/plan/LegTime.java | 6 +++--- .../resources/org/opentripplanner/apis/gtfs/schema.graphqls | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java index e0bdb6cc899..fac1118556f 100644 --- a/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java +++ b/src/ext/java/org/opentripplanner/ext/flex/FlexibleTransitLeg.java @@ -87,12 +87,12 @@ public Accessibility getTripWheelchairAccessibility() { @Override public LegTime start() { - return LegTime.of(startTime, getArrivalDelay()); + return LegTime.ofStatic(startTime); } @Override public LegTime end() { - return LegTime.of(endTime, getDepartureDelay()); + return LegTime.ofStatic(endTime); } @Override diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index 2dc97b92a11..4b30526ae82 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -9,14 +9,14 @@ /** * A scheduled time of a transit vehicle at a certain location with a optional realtime information. */ -public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealtimeEstimate estimated) { +public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealTimeEstimate estimated) { public LegTime { Objects.requireNonNull(scheduledTime); } @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); - return new LegTime(realtime.minus(delay), new RealtimeEstimate(realtime, delay)); + return new LegTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); } @Nonnull public static LegTime ofStatic(ZonedDateTime staticTime) { @@ -39,5 +39,5 @@ public ZonedDateTime 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) {} + record RealTimeEstimate(ZonedDateTime time, Duration delay) {} } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 93de5101451..29fcdf42a41 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1656,7 +1656,7 @@ ISO-8601 allows many different formats but OTP will only return the profile spec scalar OffsetDateTime @specifiedBy(url: "https://www.rfcreader.com/#rfc3339") "Real-time estimates for a vehicle at a certain place." -type RealtimeEstimate { +type RealTimeEstimate { time: OffsetDateTime! """ The delay or "earliness" of the vehicle at a certain place. @@ -1674,7 +1674,7 @@ type LegTime { "The scheduled time of the event." scheduledTime: OffsetDateTime! "The estimated time of the event. If no real-time information is available, this is null," - estimated: RealtimeEstimate + estimated: RealTimeEstimate } type Leg { From d99373db26b946b6c93fbc7ac875c6ba2eb52250 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 27 Feb 2024 11:40:38 +0100 Subject: [PATCH 37/49] Apply suggestions from code review Co-authored-by: Joel Lappalainen --- src/main/java/org/opentripplanner/model/plan/Leg.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index 0063ecf87c2..c70c03112d6 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -206,7 +206,7 @@ default Accessibility getTripWheelchairAccessibility() { LegTime start(); /** - * The time (including realtime information) when the leg ends.. + * The time (including realtime information) when the leg ends. */ LegTime end(); From 47d28f1c8380efddad0871e58798313434b36f77 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 27 Feb 2024 11:41:52 +0100 Subject: [PATCH 38/49] Update deprecation notices --- .../org/opentripplanner/apis/gtfs/schema.graphqls | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 29fcdf42a41..20f1f39af27 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1853,26 +1853,26 @@ type Leg { """ The date and time when this leg begins. Format: Unix timestamp in milliseconds. """ - startTime: Long @deprecated(reason: "Use `start.actual` instead which contains timezone information.") + startTime: Long @deprecated(reason: "Use `start.estimated.time` instead which contains timezone information.") """ The date and time when this leg ends. Format: Unix timestamp in milliseconds. """ - endTime: Long @deprecated(reason: "Use `end.actual` instead which contains timezone information.") + endTime: Long @deprecated(reason: "Use `end.estimated.time` instead which contains timezone information.") """ For transit leg, the offset from the scheduled departure time of the boarding stop in this leg, i.e. scheduled time of departure at boarding stop = `startTime - departureDelay` """ - departureDelay: Int @deprecated(reason: "Use `end.delay` instead.") + departureDelay: Int @deprecated(reason: "Use `end.estimated.delay` instead.") """ For transit leg, the offset from the scheduled arrival time of the alighting stop in this leg, i.e. scheduled time of arrival at alighting stop = `endTime - arrivalDelay` """ - arrivalDelay: Int @deprecated(reason: "Use `start.delay` instead.") + arrivalDelay: Int @deprecated(reason: "Use `start.estimated.delay` instead.") } From 337b10012d1a05cb3b86f6974c56c856b248aa11 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 27 Feb 2024 11:49:24 +0100 Subject: [PATCH 39/49] Add newline --- src/main/java/org/opentripplanner/model/plan/LegTime.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/opentripplanner/model/plan/LegTime.java b/src/main/java/org/opentripplanner/model/plan/LegTime.java index 4b30526ae82..354ce4f4b0b 100644 --- a/src/main/java/org/opentripplanner/model/plan/LegTime.java +++ b/src/main/java/org/opentripplanner/model/plan/LegTime.java @@ -13,11 +13,13 @@ public record LegTime(@Nonnull ZonedDateTime scheduledTime, @Nullable RealTimeEs public LegTime { Objects.requireNonNull(scheduledTime); } + @Nonnull public static LegTime of(ZonedDateTime realtime, int delaySecs) { var delay = Duration.ofSeconds(delaySecs); return new LegTime(realtime.minus(delay), new RealTimeEstimate(realtime, delay)); } + @Nonnull public static LegTime ofStatic(ZonedDateTime staticTime) { return new LegTime(staticTime, null); From df0d65b61222bf971e2d3c6daf67fa13132b91ed Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Fri, 1 Mar 2024 14:22:55 +0100 Subject: [PATCH 40/49] Always put minus as the first sign of a serialized negative duration --- .../graphql/scalar/DurationScalarFactory.java | 2 +- .../framework/time/DurationUtils.java | 18 +++++++++++++ .../opentripplanner/apis/gtfs/schema.graphqls | 4 +-- .../apis/gtfs/GraphQLScalarsTest.java | 4 ++- .../framework/time/DurationUtilsTest.java | 27 +++++++++++++++++++ 5 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java b/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java index 30dd3754198..50af0fbc759 100644 --- a/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java +++ b/src/main/java/org/opentripplanner/framework/graphql/scalar/DurationScalarFactory.java @@ -33,7 +33,7 @@ private static class DurationCoercing implements Coercing { @Nonnull public String serialize(@Nonnull Object input) throws CoercingSerializeException { if (input instanceof Duration duration) { - return duration.toString(); + return DurationUtils.formatDurationWithLeadingMinus(duration); } throw new CoercingSerializeException(input + " cannot be cast to 'Duration'"); diff --git a/src/main/java/org/opentripplanner/framework/time/DurationUtils.java b/src/main/java/org/opentripplanner/framework/time/DurationUtils.java index bf59964fbb2..9a01d308a1c 100644 --- a/src/main/java/org/opentripplanner/framework/time/DurationUtils.java +++ b/src/main/java/org/opentripplanner/framework/time/DurationUtils.java @@ -196,4 +196,22 @@ public static int toIntMilliseconds(Duration timeout, int defaultValue) { private static String msToSecondsStr(String formatSeconds, double timeMs) { return String.format(ROOT, formatSeconds, timeMs / 1000.0) + " seconds"; } + + /** + * Formats a duration and if it's a negative amount, it places the minus before the "P" rather + * than in the middle of the value. + *

+ * Background: There are multiple ways to express -1.5 hours: "PT-1H-30M" and "-PT1H30M". + *

+ * The first version is what you get when calling toString() but it's quite confusing. Therefore, + * this method makes sure that you get the second form "-PT1H30M". + */ + public static String formatDurationWithLeadingMinus(Duration duration) { + if (duration.isNegative()) { + var positive = duration.abs().toString(); + return "-" + positive; + } else { + return duration.toString(); + } + } } diff --git a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls index 20f1f39af27..655a1908a87 100644 --- a/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls +++ b/src/main/resources/org/opentripplanner/apis/gtfs/schema.graphqls @@ -1625,9 +1625,9 @@ type Money { """" An ISO-8601-formatted duration, i.e. `PT2H30M` for 2 hours and 30 minutes. -Negative durations are formatted like `PT-10M`. +Negative durations are formatted like `-PT10M`. """ -scalar Duration +scalar Duration @specifiedBy(url:"https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/time/Duration.html#parse(java.lang.CharSequence)") type RideHailingProvider { "The ID of the ride hailing provider." diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java index 652c72254d9..5183279cec7 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java @@ -35,7 +35,9 @@ static List durationCases() { return List.of( of(Duration.ofMinutes(30), "PT30M"), of(Duration.ofHours(23), "PT23H"), - of(Duration.ofMinutes(-10), "PT-10M") + of(Duration.ofMinutes(-10), "-PT10M"), + of(Duration.ofMinutes(-90), "-PT1H30M"), + of(Duration.ofMinutes(-184), "-PT3H4M") ); } diff --git a/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java b/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java index 86953760485..2457aa14b60 100644 --- a/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java +++ b/src/test/java/org/opentripplanner/framework/time/DurationUtilsTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.provider.Arguments.of; import static org.opentripplanner.framework.time.DurationUtils.requireNonNegative; import static org.opentripplanner.framework.time.DurationUtils.toIntMilliseconds; @@ -13,6 +14,9 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.parallel.ResourceLock; import org.junit.jupiter.api.parallel.Resources; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; public class DurationUtilsTest { @@ -151,6 +155,29 @@ public void msToSecondsStr() { } } + static List durationCases() { + return List.of( + of(Duration.ofSeconds(30), "PT30S"), + of(Duration.ofMinutes(30), "PT30M"), + of(Duration.ofHours(23), "PT23H"), + of(Duration.ofSeconds(-30), "-PT30S"), + of(Duration.ofMinutes(-10), "-PT10M"), + of(Duration.ofMinutes(-90), "-PT1H30M"), + of(Duration.ofMinutes(-184), "-PT3H4M") + ); + } + + @ParameterizedTest + @MethodSource("durationCases") + void formatDuration(Duration duration, String expected) { + var string = DurationUtils.formatDurationWithLeadingMinus(duration); + + assertEquals(expected, string); + + var parsed = Duration.parse(expected); + assertEquals(parsed, duration); + } + private static int durationSec(int hour, int min, int sec) { return 60 * (60 * hour + min) + sec; } From f723c25a421b00c58fb7b1e32ca29ee31583e41c Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 21:22:17 +0100 Subject: [PATCH 41/49] Revert conversion to record --- .../flex/trip/ScheduledDeviatedTripTest.java | 2 +- .../ext/restapi/mapping/PlaceMapper.java | 10 ++-- .../apis/gtfs/datafetchers/LegImpl.java | 2 +- .../apis/gtfs/datafetchers/PlaceImpl.java | 58 ++++++++++++++----- .../apis/transmodel/model/plan/LegType.java | 2 +- .../org/opentripplanner/model/plan/Leg.java | 2 +- .../model/plan/StopArrival.java | 43 +++++++++----- .../algorithm/mapping/AlertToLegMapper.java | 6 +- 8 files changed, 83 insertions(+), 42 deletions(-) diff --git a/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java b/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java index 546f8c411ac..143388cac0f 100644 --- a/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java +++ b/src/ext-test/java/org/opentripplanner/ext/flex/trip/ScheduledDeviatedTripTest.java @@ -185,7 +185,7 @@ void flexTripInTransitMode() { var intermediateStops = leg.getIntermediateStops(); assertEquals(1, intermediateStops.size()); - assertEquals("zone_1", intermediateStops.get(0).place().stop.getId().getId()); + assertEquals("zone_1", intermediateStops.get(0).place.stop.getId().getId()); EncodedPolyline legGeometry = EncodedPolyline.encode(leg.getLegGeometry()); assertThatPolylinesAreEqual( diff --git a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java index 95669d4b7ca..28ceb0b84e3 100644 --- a/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java +++ b/src/ext/java/org/opentripplanner/ext/restapi/mapping/PlaceMapper.java @@ -38,11 +38,11 @@ public List mapStopArrivals(Collection domain) { public ApiPlace mapStopArrival(StopArrival domain) { return mapPlace( - domain.place(), - domain.arrival().time(), - domain.departure().time(), - domain.stopPosInPattern(), - domain.gtfsStopSequence() + domain.place, + domain.arrival.time(), + domain.departure.time(), + domain.stopPosInPattern, + domain.gtfsStopSequence ); } 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 f7be76481a7..975d8d56831 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/LegImpl.java @@ -144,7 +144,7 @@ public DataFetcher> intermediateStops() { } return intermediateStops .stream() - .map(intermediateStop -> intermediateStop.place().stop) + .map(intermediateStop -> intermediateStop.place.stop) .filter(Objects::nonNull) .collect(Collectors.toList()); }; diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 16716a393d1..9ce80bcaf7f 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -20,13 +20,16 @@ public class PlaceImpl implements GraphQLDataFetchers.GraphQLPlace { @Override public DataFetcher arrival() { - return environment -> getSource(environment).arrival(); + return environment -> getSource(environment).arrival; } @Deprecated @Override public DataFetcher arrivalTime() { - return environment -> getSource(environment).arrival().time().toInstant().toEpochMilli(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.arrival.time().toInstant().toEpochMilli(); + }; } @Override @@ -37,7 +40,8 @@ public DataFetcher bikePark() { @Override public DataFetcher bikeRentalStation() { return environment -> { - Place place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + Place place = stopArrival.place; if (!place.vertexType.equals(VertexType.VEHICLERENTAL)) { return null; @@ -55,34 +59,47 @@ public DataFetcher carPark() { @Deprecated @Override public DataFetcher departure() { - return environment -> getSource(environment).departure(); + return environment -> getSource(environment).departure; } @Override public DataFetcher departureTime() { - return environment -> getSource(environment).departure().time().toInstant().toEpochMilli(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.departure.time().toInstant().toEpochMilli(); + }; } @Override public DataFetcher lat() { - return environment -> getSource(environment).place().coordinate.latitude(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.place.coordinate.latitude(); + }; } @Override public DataFetcher lon() { - return environment -> getSource(environment).place().coordinate.longitude(); + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.place.coordinate.longitude(); + }; } @Override public DataFetcher name() { return environment -> - GraphQLUtils.getTranslation(getSource(environment).place().name, environment); + { + StopArrival stopArrival = getSource(environment); + return GraphQLUtils.getTranslation(stopArrival.place.name, environment); + }; } @Override public DataFetcher rentalVehicle() { return environment -> { - Place place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + Place place = stopArrival.place; if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -97,13 +114,17 @@ public DataFetcher rentalVehicle() { @Override public DataFetcher stop() { - return environment -> getSource(environment).place().stop; + return environment -> { + StopArrival stopArrival = getSource(environment); + return stopArrival.place.stop; + }; } @Override public DataFetcher stopPosition() { return environment -> { - var seq = getSource(environment).gtfsStopSequence(); + StopArrival stopArrival = getSource(environment); + var seq = stopArrival.gtfsStopSequence; if (seq != null) { return new PositionAtStop(seq); } else { @@ -120,7 +141,8 @@ public DataFetcher vehicleParking() { @Override public DataFetcher vehicleRentalStation() { return environment -> { - Place place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + Place place = stopArrival.place; if ( !place.vertexType.equals(VertexType.VEHICLERENTAL) || @@ -136,7 +158,8 @@ public DataFetcher vehicleRentalStation() { @Override public DataFetcher vertexType() { return environment -> { - var place = getSource(environment).place(); + StopArrival stopArrival = getSource(environment); + var place = stopArrival.place; return switch (place.vertexType) { case NORMAL -> GraphQLVertexType.NORMAL.name(); case TRANSIT -> GraphQLVertexType.TRANSIT.name(); @@ -147,7 +170,8 @@ public DataFetcher vertexType() { } private VehicleParking getBikePark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; + StopArrival stopArrival = getSource(environment); + var vehicleParkingWithEntrance = stopArrival.place.vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasBicyclePlaces() @@ -159,7 +183,8 @@ private VehicleParking getBikePark(DataFetchingEnvironment environment) { } private VehicleParking getCarPark(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; + StopArrival stopArrival = getSource(environment); + var vehicleParkingWithEntrance = stopArrival.place.vehicleParkingWithEntrance; if ( vehicleParkingWithEntrance == null || !vehicleParkingWithEntrance.getVehicleParking().hasAnyCarPlaces() @@ -171,7 +196,8 @@ private VehicleParking getCarPark(DataFetchingEnvironment environment) { } private VehicleParking getVehicleParking(DataFetchingEnvironment environment) { - var vehicleParkingWithEntrance = getSource(environment).place().vehicleParkingWithEntrance; + StopArrival stopArrival = getSource(environment); + var vehicleParkingWithEntrance = stopArrival.place.vehicleParkingWithEntrance; if (vehicleParkingWithEntrance == null) { return null; } 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 99ead9fd8c0..be05d00e16d 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 @@ -340,7 +340,7 @@ public static GraphQLObjectType create( return ( stops .stream() - .map(stop -> stop.place().stop) + .map(stop -> stop.place.stop) .filter(Objects::nonNull) .collect(Collectors.toList()) ); diff --git a/src/main/java/org/opentripplanner/model/plan/Leg.java b/src/main/java/org/opentripplanner/model/plan/Leg.java index c70c03112d6..5a032def979 100644 --- a/src/main/java/org/opentripplanner/model/plan/Leg.java +++ b/src/main/java/org/opentripplanner/model/plan/Leg.java @@ -462,7 +462,7 @@ default Leg withTimeShift(Duration duration) { default Set getFareZones() { var intermediate = getIntermediateStops() .stream() - .flatMap(stopArrival -> stopArrival.place().stop.getFareZones().stream()); + .flatMap(stopArrival -> stopArrival.place.stop.getFareZones().stream()); var start = getFareZones(this.getFrom()); var end = getFareZones(this.getTo()); diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 8a6b55c9346..8435013cfb5 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -5,21 +5,36 @@ /** * This class is used to represent a stop arrival event mostly for intermediate visits to a stops * along a route. - * - * @param arrival The time the rider will arrive at the place. - * @param departure The time the rider will depart the place. - * @param stopPosInPattern For transit trips, the stop index (numbered from zero from the start of - * the trip). - * @param gtfsStopSequence For transit trips, the sequence number of the stop. Per GTFS, these - * numbers are increasing. */ -public record StopArrival( - Place place, - LegTime arrival, - LegTime departure, - Integer stopPosInPattern, - Integer gtfsStopSequence -) { +public final class StopArrival { + public final Place place; + public final LegTime arrival; + public final LegTime departure; + public final Integer stopPosInPattern; + public final Integer gtfsStopSequence; + + /** + * @param arrival The time the rider will arrive at the place. + * @param departure The time the rider will depart the place. + * @param stopPosInPattern For transit trips, the stop index (numbered from zero from the start of + * the trip). + * @param gtfsStopSequence For transit trips, the sequence number of the stop. Per GTFS, these + * numbers are increasing. + */ + public StopArrival( + Place place, + LegTime arrival, + LegTime departure, + Integer stopPosInPattern, + Integer gtfsStopSequence + ) { + this.place = place; + this.arrival = arrival; + this.departure = departure; + this.stopPosInPattern = stopPosInPattern; + this.gtfsStopSequence = gtfsStopSequence; + } + @Override public String toString() { return ToStringBuilder diff --git a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java index 4b2b194fbe4..94630be7600 100644 --- a/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java +++ b/src/main/java/org/opentripplanner/routing/algorithm/mapping/AlertToLegMapper.java @@ -81,7 +81,7 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { if (leg.getIntermediateStops() != null) { Set stopConditions = StopCondition.PASSING; for (StopArrival visit : leg.getIntermediateStops()) { - if (visit.place().stop instanceof RegularStop stop) { + if (visit.place.stop instanceof RegularStop stop) { Collection alerts = getAlertsForStopAndRoute(stop, routeId, stopConditions); alerts.addAll(getAlertsForStopAndTrip(stop, tripId, serviceDate, stopConditions)); alerts.addAll( @@ -91,8 +91,8 @@ public void addTransitAlertsToLeg(Leg leg, boolean isFirstLeg) { ) ); - ZonedDateTime stopArrival = visit.arrival().scheduledTime(); - ZonedDateTime stopDeparture = visit.departure().scheduledTime(); + ZonedDateTime stopArrival = visit.arrival.scheduledTime(); + ZonedDateTime stopDeparture = visit.departure.scheduledTime(); addTransitAlertsToLeg(leg, alerts, stopArrival, stopDeparture); } From 91989e297ee37707302f09ede6b7ab4c18032c78 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 21:32:41 +0100 Subject: [PATCH 42/49] Extract mapper for StopArrivals --- .../apis/gtfs/datafetchers/PlaceImpl.java | 3 +- .../model/plan/ScheduledTransitLeg.java | 29 +---------- .../model/plan/StopArrival.java | 1 + .../model/plan/StopArrivalMapper.java | 52 +++++++++++++++++++ 4 files changed, 56 insertions(+), 29 deletions(-) create mode 100644 src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java diff --git a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java index 9ce80bcaf7f..145321f809c 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/datafetchers/PlaceImpl.java @@ -88,8 +88,7 @@ public DataFetcher lon() { @Override public DataFetcher name() { - return environment -> - { + return environment -> { StopArrival stopArrival = getSource(environment); return GraphQLUtils.getTranslation(stopArrival.place.name, environment); }; diff --git a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java index a4050fc3cb2..6bf39d5aa4c 100644 --- a/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java +++ b/src/main/java/org/opentripplanner/model/plan/ScheduledTransitLeg.java @@ -275,36 +275,11 @@ public Place getTo() { @Override public List getIntermediateStops() { List visits = new ArrayList<>(); + var mapper = new StopArrivalMapper(zoneId, serviceDate, tripTimes); for (int i = boardStopPosInPattern + 1; i < alightStopPosInPattern; i++) { StopLocation stop = tripPattern.getStop(i); - - final var arrivalTime = ServiceDateUtils.toZonedDateTime( - serviceDate, - zoneId, - tripTimes.getArrivalTime(i) - ); - final var departureTime = ServiceDateUtils.toZonedDateTime( - serviceDate, - zoneId, - tripTimes.getDepartureTime(i) - ); - - var arrival = LegTime.ofStatic(arrivalTime); - var departure = LegTime.ofStatic(departureTime); - - if (getRealTime()) { - arrival = LegTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); - departure = LegTime.of(departureTime, tripTimes.getDepartureDelay(i)); - } - - StopArrival visit = new StopArrival( - Place.forStop(stop), - arrival, - departure, - i, - tripTimes.gtfsSequenceOfStopIndex(i) - ); + final StopArrival visit = mapper.map(i, stop, getRealTime()); visits.add(visit); } return visits; diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrival.java b/src/main/java/org/opentripplanner/model/plan/StopArrival.java index 8435013cfb5..489b122da09 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrival.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrival.java @@ -7,6 +7,7 @@ * along a route. */ public final class StopArrival { + public final Place place; public final LegTime arrival; public final LegTime departure; diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java new file mode 100644 index 00000000000..3a907e8cffb --- /dev/null +++ b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -0,0 +1,52 @@ +package org.opentripplanner.model.plan; + +import java.time.LocalDate; +import java.time.ZoneId; +import org.opentripplanner.framework.time.ServiceDateUtils; +import org.opentripplanner.transit.model.site.StopLocation; +import org.opentripplanner.transit.model.timetable.TripTimes; + +/** + * Maps leg-related information to an instance of {@link StopArrival}. + */ +class StopArrivalMapper { + + private final ZoneId zoneId; + private final LocalDate serviceDate; + private final TripTimes tripTimes; + + public StopArrivalMapper(ZoneId zoneId, LocalDate serviceDate, TripTimes tripTimes) { + this.zoneId = zoneId; + this.serviceDate = serviceDate; + this.tripTimes = tripTimes; + } + + StopArrival map(int i, StopLocation stop, boolean realTime) { + final var arrivalTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getArrivalTime(i) + ); + final var departureTime = ServiceDateUtils.toZonedDateTime( + serviceDate, + zoneId, + tripTimes.getDepartureTime(i) + ); + + var arrival = LegTime.ofStatic(arrivalTime); + var departure = LegTime.ofStatic(departureTime); + + if (realTime) { + arrival = LegTime.of(arrivalTime, tripTimes.getArrivalDelay(i)); + departure = LegTime.of(departureTime, tripTimes.getDepartureDelay(i)); + } + + return new StopArrival( + Place.forStop(stop), + arrival, + departure, + i, + tripTimes.gtfsSequenceOfStopIndex(i) + ); + } +} From 84083b6476ad1afd52d48405e024838751ecfef9 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 21:36:29 +0100 Subject: [PATCH 43/49] Separate tests several classes --- .../apis/gtfs/DurationScalarTest.java | 41 ++++++ .../apis/gtfs/GeoJsonScalarTest.java | 31 +++++ .../apis/gtfs/GraphQLScalarsTest.java | 119 ------------------ .../apis/gtfs/OffsetDateTimeScalarTest.java | 62 +++++++++ 4 files changed, 134 insertions(+), 119 deletions(-) create mode 100644 src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java create mode 100644 src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java delete mode 100644 src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java create mode 100644 src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java diff --git a/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java new file mode 100644 index 00000000000..ca87311ac3a --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java @@ -0,0 +1,41 @@ +package org.opentripplanner.apis.gtfs; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.of; + +import graphql.schema.CoercingSerializeException; +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +public class DurationScalarTest { + + static List durationCases() { + return List.of( + of(Duration.ofMinutes(30), "PT30M"), + of(Duration.ofHours(23), "PT23H"), + of(Duration.ofMinutes(-10), "-PT10M"), + of(Duration.ofMinutes(-90), "-PT1H30M"), + of(Duration.ofMinutes(-184), "-PT3H4M") + ); + } + + @ParameterizedTest + @MethodSource("durationCases") + void duration(Duration duration, String expected) { + var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); + assertEquals(expected, string); + } + + @Test + void nonDuration() { + Assertions.assertThrows( + CoercingSerializeException.class, + () -> GraphQLScalars.durationScalar.getCoercing().serialize(new Object()) + ); + } +} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java new file mode 100644 index 00000000000..92188e603c4 --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java @@ -0,0 +1,31 @@ +package org.opentripplanner.apis.gtfs; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.fasterxml.jackson.core.JsonProcessingException; +import org.junit.jupiter.api.Test; +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.GeometryFactory; +import org.opentripplanner.framework.json.ObjectMappers; + +class GeoJsonScalarTest { + + @Test + void geoJson() throws JsonProcessingException { + var gm = new GeometryFactory(); + var polygon = gm.createPolygon( + new Coordinate[] { + new Coordinate(0, 0), + new Coordinate(1, 1), + new Coordinate(2, 2), + new Coordinate(0, 0), + } + ); + var geoJson = GraphQLScalars.geoJsonScalar.getCoercing().serialize(polygon); + + var jsonNode = ObjectMappers + .ignoringExtraFields() + .readTree("{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[1,1],[2,2],[0,0]]]}"); + assertEquals(jsonNode.toString(), geoJson.toString()); + } +} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java deleted file mode 100644 index 5183279cec7..00000000000 --- a/src/test/java/org/opentripplanner/apis/gtfs/GraphQLScalarsTest.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.opentripplanner.apis.gtfs; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.params.provider.Arguments.of; - -import com.fasterxml.jackson.core.JsonProcessingException; -import graphql.language.StringValue; -import graphql.schema.CoercingSerializeException; -import java.time.Duration; -import java.time.LocalDate; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.GeometryFactory; -import org.opentripplanner._support.time.ZoneIds; -import org.opentripplanner.framework.json.ObjectMappers; - -class GraphQLScalarsTest { - - static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( - LocalDate.of(2024, 2, 4), - LocalTime.MIDNIGHT, - ZoneOffset.UTC - ); - - static List durationCases() { - return List.of( - of(Duration.ofMinutes(30), "PT30M"), - of(Duration.ofHours(23), "PT23H"), - of(Duration.ofMinutes(-10), "-PT10M"), - of(Duration.ofMinutes(-90), "-PT1H30M"), - of(Duration.ofMinutes(-184), "-PT3H4M") - ); - } - - @ParameterizedTest - @MethodSource("durationCases") - void duration(Duration duration, String expected) { - var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); - assertEquals(expected, string); - } - - @Test - void nonDuration() { - Assertions.assertThrows( - CoercingSerializeException.class, - () -> GraphQLScalars.durationScalar.getCoercing().serialize(new Object()) - ); - } - - @Test - void geoJson() throws JsonProcessingException { - var gm = new GeometryFactory(); - var polygon = gm.createPolygon( - new Coordinate[] { - new Coordinate(0, 0), - new Coordinate(1, 1), - new Coordinate(2, 2), - new Coordinate(0, 0), - } - ); - var geoJson = GraphQLScalars.geoJsonScalar.getCoercing().serialize(polygon); - - var jsonNode = ObjectMappers - .ignoringExtraFields() - .readTree("{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[1,1],[2,2],[0,0]]]}"); - assertEquals(jsonNode.toString(), geoJson.toString()); - } - - @Nested - class OffsetDateTimeTests { - - static List offsetDateTimeCases() { - return List.of( - of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), - of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), - "2024-02-04T01:00:00+01:00" - ), - of( - OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), - "2024-02-03T19:00:00-05:00" - ) - ); - } - - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void serializeOffsetDateTime(OffsetDateTime odt, String expected) { - var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); - assertEquals(expected, string); - } - - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void parseOffsetDateTime(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); - assertEquals(expected, odt); - } - - @ParameterizedTest - @MethodSource("offsetDateTimeCases") - void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar - .getCoercing() - .parseLiteral(new StringValue(input)); - assertEquals(expected, odt); - } - } -} diff --git a/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java new file mode 100644 index 00000000000..890bf1eeed1 --- /dev/null +++ b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java @@ -0,0 +1,62 @@ +package org.opentripplanner.apis.gtfs; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.params.provider.Arguments.of; + +import graphql.language.StringValue; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.ZoneOffset; +import java.util.List; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.opentripplanner._support.time.ZoneIds; + +public class OffsetDateTimeScalarTest { + + static final OffsetDateTime OFFSET_DATE_TIME = OffsetDateTime.of( + LocalDate.of(2024, 2, 4), + LocalTime.MIDNIGHT, + ZoneOffset.UTC + ); + + static List offsetDateTimeCases() { + return List.of( + of(OFFSET_DATE_TIME, "2024-02-04T00:00:00Z"), + of(OFFSET_DATE_TIME.plusHours(12).plusMinutes(8).plusSeconds(22), "2024-02-04T12:08:22Z"), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.BERLIN).toOffsetDateTime(), + "2024-02-04T01:00:00+01:00" + ), + of( + OFFSET_DATE_TIME.atZoneSameInstant(ZoneIds.NEW_YORK).toOffsetDateTime(), + "2024-02-03T19:00:00-05:00" + ) + ); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void serializeOffsetDateTime(OffsetDateTime odt, String expected) { + var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + assertEquals(expected, string); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTime(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); + assertEquals(expected, odt); + } + + @ParameterizedTest + @MethodSource("offsetDateTimeCases") + void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { + var odt = GraphQLScalars.offsetDateTimeScalar + .getCoercing() + .parseLiteral(new StringValue(input)); + assertEquals(expected, odt); + } +} From 10fac09bdd9c3481256fd8be7f5682b1dc12ab04 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Sun, 3 Mar 2024 22:32:33 +0100 Subject: [PATCH 44/49] Make parser return throw an exception --- .../apis/gtfs/GraphQLScalars.java | 31 ++++++++++++------- .../framework/time/OffsetDateTimeParser.java | 10 +++--- .../time/OffsetDateTimeParserTest.java | 14 ++++++--- 3 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 7d70f4be3b5..f0e4f295055 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -10,6 +10,7 @@ import graphql.schema.CoercingParseValueException; import graphql.schema.CoercingSerializeException; import graphql.schema.GraphQLScalarType; +import java.text.ParseException; import java.time.OffsetDateTime; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; @@ -79,26 +80,34 @@ public String serialize(@Nonnull Object dataFetcherResult) @Override public OffsetDateTime parseValue(Object input) throws CoercingParseValueException { if (input instanceof CharSequence cs) { - return OffsetDateTimeParser.parseLeniently(cs).orElseThrow(() -> valueException(input)); + try { + return OffsetDateTimeParser.parseLeniently(cs); + } catch (ParseException e) { + int errorOffset = e.getErrorOffset(); + throw new CoercingParseValueException( + "Cannot parse %s into an OffsetDateTime. Error at character index %s".formatted( + input, + errorOffset + ) + ); + } } - throw valueException(input); + throw new CoercingParseValueException( + "Cannot parse %s into an OffsetDateTime. Must be a string." + ); } @Override public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralException { if (input instanceof StringValue sv) { - return OffsetDateTimeParser - .parseLeniently(sv.getValue()) - .orElseThrow(CoercingParseLiteralException::new); + try { + return OffsetDateTimeParser.parseLeniently(sv.getValue()); + } catch (ParseException e) { + throw new CoercingSerializeException(); + } } throw new CoercingParseLiteralException(); } - - private static CoercingParseValueException valueException(Object input) { - return new CoercingParseValueException( - "Cannot parse %s into an OffsetDateTime.".formatted(input) - ); - } } ) .build(); diff --git a/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java index 11652d797a7..8b40697977a 100644 --- a/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java +++ b/src/main/java/org/opentripplanner/framework/time/OffsetDateTimeParser.java @@ -1,10 +1,10 @@ package org.opentripplanner.framework.time; +import java.text.ParseException; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.format.DateTimeParseException; -import java.util.Optional; public class OffsetDateTimeParser { @@ -30,13 +30,13 @@ public class OffsetDateTimeParser { /** * Parses a ISO-8601 string into am OffsetDateTime instance allowing the offset to be both in * '02:00' and '0200' format. + * @throws ParseException if the string cannot be parsed */ - public static Optional parseLeniently(CharSequence input) { + public static OffsetDateTime parseLeniently(CharSequence input) throws ParseException { try { - var result = OffsetDateTime.parse(input, LENIENT_PARSER); - return Optional.of(result); + return OffsetDateTime.parse(input, LENIENT_PARSER); } catch (DateTimeParseException e) { - return Optional.empty(); + throw new ParseException(e.getParsedString(), e.getErrorIndex()); } } } diff --git a/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java index 1f164ada783..d8944b9a5f0 100644 --- a/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java +++ b/src/test/java/org/opentripplanner/framework/time/OffsetDateTimeParserTest.java @@ -2,8 +2,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; +import java.text.ParseException; import java.time.OffsetDateTime; import java.util.List; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -27,9 +29,9 @@ static List successfulCases() { @ParameterizedTest @MethodSource("successfulCases") - void parse(String input) { + void parse(String input) throws ParseException { var res = OffsetDateTimeParser.parseLeniently(input); - assertTrue(res.get().isEqual(TIME)); + assertTrue(res.isEqual(TIME)); } static List failedCases() { @@ -39,7 +41,11 @@ static List failedCases() { @ParameterizedTest @MethodSource("failedCases") void failed(String input) { - var res = OffsetDateTimeParser.parseLeniently(input); - assertTrue(res.isEmpty()); + Assertions.assertThrows( + ParseException.class, + () -> { + OffsetDateTimeParser.parseLeniently(input); + } + ); } } From 009eb99f6b8796702ac5112983dbfd4f3dd28a59 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 10:02:44 +0100 Subject: [PATCH 45/49] Remove arrival/departure in example --- docs/apis/GraphQL-Tutorial.md | 14 ------ .../apis/gtfs/expectations/plan.json | 44 ------------------- .../apis/gtfs/queries/plan.graphql | 14 ------ 3 files changed, 72 deletions(-) diff --git a/docs/apis/GraphQL-Tutorial.md b/docs/apis/GraphQL-Tutorial.md index 7e1f6b0f6db..92645f9b245 100644 --- a/docs/apis/GraphQL-Tutorial.md +++ b/docs/apis/GraphQL-Tutorial.md @@ -96,13 +96,6 @@ Most people want to get routing results out of OTP, so lets see the query for th name lat lon - arrival { - scheduledTime - estimated { - time - delay - } - } departure { scheduledTime estimated { @@ -122,13 +115,6 @@ Most people want to get routing results out of OTP, so lets see the query for th delay } } - departure { - scheduledTime - estimated { - time - delay - } - } } route { gtfsId diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json index ec971af5b3c..d213443f7cd 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json +++ b/src/test/resources/org/opentripplanner/apis/gtfs/expectations/plan.json @@ -12,10 +12,6 @@ "name" : "A", "lat" : 5.0, "lon" : 8.0, - "arrival" : { - "scheduledTime" : "2020-02-02T11:00:00Z", - "estimated" : null - }, "departure" : { "scheduledTime" : "2020-02-02T11:00:00Z", "estimated" : null @@ -28,10 +24,6 @@ "arrival" : { "scheduledTime" : "2020-02-02T11:00:20Z", "estimated" : null - }, - "departure" : { - "scheduledTime" : "2020-02-02T11:00:20Z", - "estimated" : null } }, "route" : null, @@ -43,13 +35,6 @@ "name" : "B", "lat" : 6.0, "lon" : 8.5, - "arrival" : { - "scheduledTime" : "2020-02-02T10:51:00Z", - "estimated" : { - "time" : "2020-02-02T11:01:00Z", - "delay" : "PT10M" - } - }, "departure" : { "scheduledTime" : "2020-02-02T10:51:00Z", "estimated" : { @@ -68,13 +53,6 @@ "time" : "2020-02-02T11:15:00Z", "delay" : "PT10M" } - }, - "departure" : { - "scheduledTime" : "2020-02-02T11:05:00Z", - "estimated" : { - "time" : "2020-02-02T11:15:00Z", - "delay" : "PT10M" - } } }, "route" : { @@ -92,13 +70,6 @@ "name" : "C", "lat" : 7.0, "lon" : 9.0, - "arrival" : { - "scheduledTime" : "2020-02-02T11:20:00Z", - "estimated" : { - "time" : "2020-02-02T11:30:00Z", - "delay" : "PT10M" - } - }, "departure" : { "scheduledTime" : "2020-02-02T11:20:00Z", "estimated" : { @@ -117,13 +88,6 @@ "time" : "2020-02-02T11:50:00Z", "delay" : "PT10M" } - }, - "departure" : { - "scheduledTime" : "2020-02-02T11:40:00Z", - "estimated" : { - "time" : "2020-02-02T11:50:00Z", - "delay" : "PT10M" - } } }, "route" : { @@ -141,10 +105,6 @@ "name" : "D", "lat" : 8.0, "lon" : 9.5, - "arrival" : { - "scheduledTime" : "2020-02-02T11:50:00Z", - "estimated" : null - }, "departure" : { "scheduledTime" : "2020-02-02T11:50:00Z", "estimated" : null @@ -157,10 +117,6 @@ "arrival" : { "scheduledTime" : "2020-02-02T12:00:00Z", "estimated" : null - }, - "departure" : { - "scheduledTime" : "2020-02-02T12:00:00Z", - "estimated" : null } }, "route" : null, diff --git a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql index cc93ffb211c..39877eef0b7 100644 --- a/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql +++ b/src/test/resources/org/opentripplanner/apis/gtfs/queries/plan.graphql @@ -25,13 +25,6 @@ name lat lon - arrival { - scheduledTime - estimated { - time - delay - } - } departure { scheduledTime estimated { @@ -51,13 +44,6 @@ delay } } - departure { - scheduledTime - estimated { - time - delay - } - } } route { gtfsId From 2bd2026116177d6bc0c55f1f5da1eb5bd9fef403 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 14:50:27 +0100 Subject: [PATCH 46/49] Add validation Co-authored-by: Thomas Gran --- .../org/opentripplanner/model/plan/StopArrivalMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java index 3a907e8cffb..9f8e4f7045a 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -16,9 +16,9 @@ class StopArrivalMapper { private final TripTimes tripTimes; public StopArrivalMapper(ZoneId zoneId, LocalDate serviceDate, TripTimes tripTimes) { - this.zoneId = zoneId; - this.serviceDate = serviceDate; - this.tripTimes = tripTimes; + this.zoneId = Objects.requireNonNull(zoneId); + this.serviceDate = Objects.requireNonNull(serviceDate); + this.tripTimes = Objects.requireNonNull(tripTimes); } StopArrival map(int i, StopLocation stop, boolean realTime) { From a9406dc1baf835eb69b3539fbbe8b9e5db485ed5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 14:57:31 +0100 Subject: [PATCH 47/49] Add import --- .../java/org/opentripplanner/model/plan/StopArrivalMapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java index 9f8e4f7045a..25bab2a7c3f 100644 --- a/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java +++ b/src/main/java/org/opentripplanner/model/plan/StopArrivalMapper.java @@ -2,6 +2,7 @@ import java.time.LocalDate; import java.time.ZoneId; +import java.util.Objects; import org.opentripplanner.framework.time.ServiceDateUtils; import org.opentripplanner.transit.model.site.StopLocation; import org.opentripplanner.transit.model.timetable.TripTimes; From 964a3f767d6196524126102fbd46006427a3a7e5 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Mon, 4 Mar 2024 15:04:40 +0100 Subject: [PATCH 48/49] Use uppercase for constants --- .../opentripplanner/apis/gtfs/GraphQLScalars.java | 12 ++++++------ .../opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 12 ++++++------ .../apis/gtfs/DurationScalarTest.java | 4 ++-- .../opentripplanner/apis/gtfs/GeoJsonScalarTest.java | 2 +- .../apis/gtfs/OffsetDateTimeScalarTest.java | 6 +++--- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index f0e4f295055..9a9d704afdb 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -25,9 +25,9 @@ public class GraphQLScalars { private static final ObjectMapper geoJsonMapper = new ObjectMapper() .registerModule(new JtsModule(GeometryUtils.getGeometryFactory())); - public static GraphQLScalarType durationScalar = DurationScalarFactory.createDurationScalar(); + public static GraphQLScalarType DURATION_SCALAR = DurationScalarFactory.createDurationScalar(); - public static final GraphQLScalarType polylineScalar = GraphQLScalarType + public static final GraphQLScalarType POLYLINE_SCALAR = GraphQLScalarType .newScalar() .name("Polyline") .description( @@ -56,7 +56,7 @@ public String parseLiteral(Object input) { ) .build(); - public static final GraphQLScalarType offsetDateTimeScalar = GraphQLScalarType + public static final GraphQLScalarType OFFSET_DATETIME_SCALAR = GraphQLScalarType .newScalar() .name("OffsetDateTime") .coercing( @@ -112,7 +112,7 @@ public OffsetDateTime parseLiteral(Object input) throws CoercingParseLiteralExce ) .build(); - public static final GraphQLScalarType geoJsonScalar = GraphQLScalarType + public static final GraphQLScalarType GEOJSON_SCALAR = GraphQLScalarType .newScalar() .name("GeoJson") .description("Geographic data structures in JSON format. See: https://geojson.org/") @@ -140,7 +140,7 @@ public Geometry parseLiteral(Object input) throws CoercingParseLiteralException ) .build(); - public static final GraphQLScalarType graphQLIDScalar = GraphQLScalarType + public static final GraphQLScalarType GRAPHQLID_SCALAR = GraphQLScalarType .newScalar() .name("ID") .coercing( @@ -180,7 +180,7 @@ public Relay.ResolvedGlobalId parseLiteral(Object input) ) .build(); - public static final GraphQLScalarType gramsScalar = GraphQLScalarType + public static final GraphQLScalarType GRAMS_SCALAR = GraphQLScalarType .newScalar() .name("Grams") .coercing( diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 0d76de16dc1..6adadaa40ff 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -106,12 +106,12 @@ protected static GraphQLSchema buildSchema() { IntrospectionTypeWiring typeWiring = new IntrospectionTypeWiring(typeRegistry); RuntimeWiring runtimeWiring = RuntimeWiring .newRuntimeWiring() - .scalar(GraphQLScalars.durationScalar) - .scalar(GraphQLScalars.polylineScalar) - .scalar(GraphQLScalars.geoJsonScalar) - .scalar(GraphQLScalars.graphQLIDScalar) - .scalar(GraphQLScalars.gramsScalar) - .scalar(GraphQLScalars.offsetDateTimeScalar) + .scalar(GraphQLScalars.DURATION_SCALAR) + .scalar(GraphQLScalars.POLYLINE_SCALAR) + .scalar(GraphQLScalars.GEOJSON_SCALAR) + .scalar(GraphQLScalars.GRAPHQLID_SCALAR) + .scalar(GraphQLScalars.GRAMS_SCALAR) + .scalar(GraphQLScalars.OFFSET_DATETIME_SCALAR) .scalar(ExtendedScalars.GraphQLLong) .type("Node", type -> type.typeResolver(new NodeTypeResolver())) .type("PlaceInterface", type -> type.typeResolver(new PlaceInterfaceTypeResolver())) diff --git a/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java index ca87311ac3a..28d1ad08376 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/DurationScalarTest.java @@ -27,7 +27,7 @@ static List durationCases() { @ParameterizedTest @MethodSource("durationCases") void duration(Duration duration, String expected) { - var string = GraphQLScalars.durationScalar.getCoercing().serialize(duration); + var string = GraphQLScalars.DURATION_SCALAR.getCoercing().serialize(duration); assertEquals(expected, string); } @@ -35,7 +35,7 @@ void duration(Duration duration, String expected) { void nonDuration() { Assertions.assertThrows( CoercingSerializeException.class, - () -> GraphQLScalars.durationScalar.getCoercing().serialize(new Object()) + () -> GraphQLScalars.DURATION_SCALAR.getCoercing().serialize(new Object()) ); } } diff --git a/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java index 92188e603c4..cc88e22d074 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/GeoJsonScalarTest.java @@ -21,7 +21,7 @@ void geoJson() throws JsonProcessingException { new Coordinate(0, 0), } ); - var geoJson = GraphQLScalars.geoJsonScalar.getCoercing().serialize(polygon); + var geoJson = GraphQLScalars.GEOJSON_SCALAR.getCoercing().serialize(polygon); var jsonNode = ObjectMappers .ignoringExtraFields() diff --git a/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java index 890bf1eeed1..45c8e9de837 100644 --- a/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java +++ b/src/test/java/org/opentripplanner/apis/gtfs/OffsetDateTimeScalarTest.java @@ -40,21 +40,21 @@ static List offsetDateTimeCases() { @ParameterizedTest @MethodSource("offsetDateTimeCases") void serializeOffsetDateTime(OffsetDateTime odt, String expected) { - var string = GraphQLScalars.offsetDateTimeScalar.getCoercing().serialize(odt); + var string = GraphQLScalars.OFFSET_DATETIME_SCALAR.getCoercing().serialize(odt); assertEquals(expected, string); } @ParameterizedTest @MethodSource("offsetDateTimeCases") void parseOffsetDateTime(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar.getCoercing().parseValue(input); + var odt = GraphQLScalars.OFFSET_DATETIME_SCALAR.getCoercing().parseValue(input); assertEquals(expected, odt); } @ParameterizedTest @MethodSource("offsetDateTimeCases") void parseOffsetDateTimeLiteral(OffsetDateTime expected, String input) { - var odt = GraphQLScalars.offsetDateTimeScalar + var odt = GraphQLScalars.OFFSET_DATETIME_SCALAR .getCoercing() .parseLiteral(new StringValue(input)); assertEquals(expected, odt); From 2f763e9626a89164f09d73030bdccb09590650d1 Mon Sep 17 00:00:00 2001 From: Leonard Ehrenfried Date: Tue, 5 Mar 2024 12:30:19 +0100 Subject: [PATCH 49/49] Rename constant --- src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java | 2 +- .../java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java index 9a9d704afdb..42ffe992539 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GraphQLScalars.java @@ -140,7 +140,7 @@ public Geometry parseLiteral(Object input) throws CoercingParseLiteralException ) .build(); - public static final GraphQLScalarType GRAPHQLID_SCALAR = GraphQLScalarType + public static final GraphQLScalarType GRAPHQL_ID_SCALAR = GraphQLScalarType .newScalar() .name("ID") .coercing( diff --git a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java index 6adadaa40ff..1fd78765a07 100644 --- a/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java +++ b/src/main/java/org/opentripplanner/apis/gtfs/GtfsGraphQLIndex.java @@ -109,7 +109,7 @@ protected static GraphQLSchema buildSchema() { .scalar(GraphQLScalars.DURATION_SCALAR) .scalar(GraphQLScalars.POLYLINE_SCALAR) .scalar(GraphQLScalars.GEOJSON_SCALAR) - .scalar(GraphQLScalars.GRAPHQLID_SCALAR) + .scalar(GraphQLScalars.GRAPHQL_ID_SCALAR) .scalar(GraphQLScalars.GRAMS_SCALAR) .scalar(GraphQLScalars.OFFSET_DATETIME_SCALAR) .scalar(ExtendedScalars.GraphQLLong)