-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
251 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripPatternTimePenaltyType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
package org.opentripplanner.apis.transmodel.model.plan; | ||
|
||
import graphql.Scalars; | ||
import graphql.schema.DataFetchingEnvironment; | ||
import graphql.schema.GraphQLFieldDefinition; | ||
import graphql.schema.GraphQLObjectType; | ||
import org.opentripplanner.framework.time.DurationUtils; | ||
|
||
public class TripPatternTimePenaltyType { | ||
|
||
public static GraphQLObjectType create() { | ||
return GraphQLObjectType | ||
.newObject() | ||
.name("TimePenalty") | ||
.description( | ||
""" | ||
The time-penalty is applied to either the access-legs and/or egress-legs. Both access and | ||
egress may contain more than one leg; Hence, the penalty is not a field on leg. | ||
Note! This is for debugging only. This type can change without notice. | ||
""" | ||
) | ||
.field( | ||
GraphQLFieldDefinition | ||
.newFieldDefinition() | ||
.name("appliedTo") | ||
.description( | ||
""" | ||
The time-penalty is applied to either the access-legs and/or egress-legs. Both access | ||
and egress may contain more than one leg; Hence, the penalty is not a field on leg. The | ||
`appliedTo` describe witch part of the itinerary that this instance applies to. | ||
""" | ||
) | ||
.type(Scalars.GraphQLString) | ||
.dataFetcher(environment -> penalty(environment).appliesTo()) | ||
.build() | ||
) | ||
.field( | ||
GraphQLFieldDefinition | ||
.newFieldDefinition() | ||
.name("timePenalty") | ||
.description( | ||
""" | ||
The time-penalty added to the actual time/duration when comparing the itinerary with | ||
other itineraries. This is used to decide witch is the best option, but is not visible | ||
- the actual departure and arrival-times are not modified. | ||
""" | ||
) | ||
.type(Scalars.GraphQLString) | ||
.dataFetcher(environment -> | ||
DurationUtils.durationToStr(penalty(environment).penalty().time()) | ||
) | ||
.build() | ||
) | ||
.field( | ||
GraphQLFieldDefinition | ||
.newFieldDefinition() | ||
.name("generalizedCostPenalty") | ||
.description( | ||
""" | ||
The time-penalty does also propagate to the `generalizedCost` But, while the | ||
arrival-/departure-times listed is not affected, the generalized-cost is. In some cases | ||
the time-penalty-cost is excluded when comparing itineraries - that happens if one of | ||
the itineraries is a "direct/street-only" itinerary. Time-penalty can not be set for | ||
direct searches, so it needs to be excluded from such comparison to be fair. The unit | ||
is transit-seconds. | ||
""" | ||
) | ||
.type(Scalars.GraphQLInt) | ||
.dataFetcher(environment -> penalty(environment).penalty().cost().toSeconds()) | ||
.build() | ||
) | ||
.build(); | ||
} | ||
|
||
static TripPlanTimePenaltyDto penalty(DataFetchingEnvironment environment) { | ||
return environment.getSource(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
src/main/java/org/opentripplanner/apis/transmodel/model/plan/TripPlanTimePenaltyDto.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package org.opentripplanner.apis.transmodel.model.plan; | ||
|
||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.stream.Stream; | ||
import org.opentripplanner.framework.model.TimeAndCost; | ||
import org.opentripplanner.model.plan.Itinerary; | ||
|
||
/** | ||
* A simple data-transfer-object used to map from an itinerary to the API specific | ||
* type. It is needed because we need to pass in the "appliedTo" field, which does not | ||
* exist in the domain model. | ||
*/ | ||
public record TripPlanTimePenaltyDto(String appliesTo, TimeAndCost penalty) { | ||
static List<TripPlanTimePenaltyDto> map(Itinerary itinerary) { | ||
// This check for null to be robust - in case of a mistake in the future. | ||
// The check is redundant on purpose. | ||
if (itinerary == null) { | ||
return List.of(); | ||
} | ||
return Stream | ||
.of(map("access", itinerary.getAccessPenalty()), map("egress", itinerary.getEgressPenalty())) | ||
.filter(Objects::nonNull) | ||
.toList(); | ||
} | ||
|
||
static TripPlanTimePenaltyDto map(String appliedTo, TimeAndCost penalty) { | ||
return penalty == null || penalty.isZero() | ||
? null | ||
: new TripPlanTimePenaltyDto(appliedTo, penalty); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
src/test/java/org/opentripplanner/apis/transmodel/model/plan/TripPlanTimePenaltyDtoTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package org.opentripplanner.apis.transmodel.model.plan; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNull; | ||
|
||
import java.util.List; | ||
import org.junit.jupiter.api.Test; | ||
import org.opentripplanner.framework.model.Cost; | ||
import org.opentripplanner.framework.model.TimeAndCost; | ||
import org.opentripplanner.framework.time.DurationUtils; | ||
import org.opentripplanner.model.plan.Itinerary; | ||
import org.opentripplanner.model.plan.Place; | ||
import org.opentripplanner.model.plan.TestItineraryBuilder; | ||
import org.opentripplanner.transit.model._data.TransitModelForTest; | ||
|
||
class TripPlanTimePenaltyDtoTest { | ||
|
||
private static final TimeAndCost PENALTY = new TimeAndCost( | ||
DurationUtils.duration("20m30s"), | ||
Cost.costOfSeconds(21) | ||
); | ||
|
||
private final TransitModelForTest testModel = TransitModelForTest.of(); | ||
private final Place placeA = Place.forStop(testModel.stop("A").build()); | ||
private final Place placeB = Place.forStop(testModel.stop("B").build()); | ||
|
||
@Test | ||
void mapSingeEntry() { | ||
assertNull(TripPlanTimePenaltyDto.map("access", null)); | ||
assertNull(TripPlanTimePenaltyDto.map("access", TimeAndCost.ZERO)); | ||
assertEquals( | ||
new TripPlanTimePenaltyDto("access", PENALTY), | ||
TripPlanTimePenaltyDto.map("access", PENALTY) | ||
); | ||
} | ||
|
||
@Test | ||
void mapItineraryWithNoPenalty() { | ||
var i = itinerary(); | ||
assertEquals(List.of(), TripPlanTimePenaltyDto.map(null)); | ||
assertEquals(List.of(), TripPlanTimePenaltyDto.map(i)); | ||
} | ||
|
||
@Test | ||
void mapItineraryWithAccess() { | ||
var i = itinerary(); | ||
i.setAccessPenalty(PENALTY); | ||
assertEquals( | ||
List.of(new TripPlanTimePenaltyDto("access", PENALTY)), | ||
TripPlanTimePenaltyDto.map(i) | ||
); | ||
} | ||
|
||
@Test | ||
void mapItineraryWithEgress() { | ||
var i = itinerary(); | ||
i.setEgressPenalty(PENALTY); | ||
assertEquals( | ||
List.of(new TripPlanTimePenaltyDto("egress", PENALTY)), | ||
TripPlanTimePenaltyDto.map(i) | ||
); | ||
} | ||
|
||
private Itinerary itinerary() { | ||
return TestItineraryBuilder.newItinerary(placeA).drive(100, 200, placeB).build(); | ||
} | ||
} |