Skip to content

Commit 85dbd83

Browse files
Merge pull request opentripplanner#6525 from entur/better_trip_api
Change the TripRequest and builder to work with include lists instead of just the FilterValues
2 parents 698df74 + a80c70b commit 85dbd83

File tree

9 files changed

+141
-86
lines changed

9 files changed

+141
-86
lines changed

application/src/main/java/org/opentripplanner/apis/transmodel/TransmodelGraphQLSchema.java

Lines changed: 6 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
import static java.util.Collections.emptyList;
55
import static org.opentripplanner.apis.transmodel.mapping.SeverityMapper.getTransmodelSeverity;
66
import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDToDomain;
7+
import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomain;
78
import static org.opentripplanner.apis.transmodel.mapping.TransitIdMapper.mapIDsToDomainNullSafe;
89
import static org.opentripplanner.apis.transmodel.model.EnumTypes.FILTER_PLACE_TYPE_ENUM;
910
import static org.opentripplanner.apis.transmodel.model.EnumTypes.MULTI_MODAL_MODE;
1011
import static org.opentripplanner.apis.transmodel.model.EnumTypes.TRANSPORT_MODE;
1112
import static org.opentripplanner.apis.transmodel.model.scalars.DateTimeScalarFactory.createMillisecondsSinceEpochAsDateTimeStringScalar;
12-
import static org.opentripplanner.apis.transmodel.support.GqlUtil.toListNullSafe;
1313
import static org.opentripplanner.model.projectinfo.OtpProjectInfo.projectInfo;
1414

1515
import graphql.Scalars;
@@ -30,7 +30,6 @@
3030
import graphql.schema.GraphQLScalarType;
3131
import graphql.schema.GraphQLSchema;
3232
import graphql.schema.SchemaTransformer;
33-
import java.time.LocalDate;
3433
import java.time.ZoneId;
3534
import java.util.ArrayList;
3635
import java.util.Arrays;
@@ -1216,28 +1215,11 @@ private GraphQLSchema create() {
12161215
.build()
12171216
)
12181217
.dataFetcher(environment -> {
1219-
var authorities = FilterValues.ofEmptyIsEverything(
1220-
"authorities",
1221-
mapIDsToDomainNullSafe(environment.getArgument("authorities"))
1222-
);
1223-
var lineIds = FilterValues.ofEmptyIsEverything(
1224-
"lines",
1225-
mapIDsToDomainNullSafe(environment.getArgument("lines"))
1226-
);
1227-
var privateCodes = FilterValues.ofEmptyIsEverything(
1228-
"privateCodes",
1229-
toListNullSafe(environment.<List<String>>getArgument("privateCodes"))
1230-
);
1231-
var activeServiceDates = FilterValues.ofEmptyIsEverything(
1232-
"activeDates",
1233-
toListNullSafe(environment.<List<LocalDate>>getArgument("activeDates"))
1234-
);
1235-
1236-
TripRequest tripRequest = TripRequest.of()
1237-
.withAgencies(authorities)
1238-
.withRoutes(lineIds)
1239-
.withNetexInternalPlanningCodes(privateCodes)
1240-
.withServiceDates(activeServiceDates)
1218+
var tripRequest = TripRequest.of()
1219+
.withIncludeAgencies(mapIDsToDomain(environment.getArgument("authorities")))
1220+
.withIncludeRoutes(mapIDsToDomain(environment.getArgument("lines")))
1221+
.withIncludeNetexInternalPlanningCodes(environment.getArgument("privateCodes"))
1222+
.withIncludeServiceDates(environment.getArgument("activeDates"))
12411223
.build();
12421224

12431225
return GqlUtil.getTransitService(environment).getTrips(tripRequest);

application/src/main/java/org/opentripplanner/apis/transmodel/mapping/TransitIdMapper.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ public static List<FeedScopedId> mapIDsToDomainNullSafe(@Nullable Collection<Str
4545
return ids.stream().filter(StringUtils::hasValue).map(TransitIdMapper::mapIDToDomain).toList();
4646
}
4747

48+
/**
49+
* Maps ids to feed-scoped ids.
50+
* Return null if the collection of ids is null.
51+
* If the collection of ids contains null or blank elements, they are ignored.
52+
*/
53+
public static List<FeedScopedId> mapIDsToDomain(@Nullable Collection<String> ids) {
54+
if (ids == null) {
55+
return null;
56+
}
57+
return ids.stream().filter(StringUtils::hasValue).map(TransitIdMapper::mapIDToDomain).toList();
58+
}
59+
4860
public static FeedScopedId mapIDToDomain(String id) {
4961
if (id == null || id.isBlank()) {
5062
return null;

application/src/main/java/org/opentripplanner/apis/transmodel/support/GqlUtil.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,12 @@ public static Locale getLocale(DataFetchingEnvironment environment) {
9999
}
100100

101101
/**
102-
* Null-safe handling of a collection of type T. Returns an empty list if the collection is null.
102+
* Null-safe handling of a collection of type T. Returns null if the incoming collection is null.
103103
* Null elements are filtered out.
104104
*/
105-
public static <T> List<T> toListNullSafe(@Nullable Collection<T> args) {
105+
public static <T> List<T> toList(@Nullable Collection<T> args) {
106106
if (args == null) {
107-
return List.of();
107+
return null;
108108
}
109109
return args.stream().filter(Objects::nonNull).toList();
110110
}

application/src/main/java/org/opentripplanner/transit/api/model/FilterValues.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,21 @@ public static <E> FilterValues<E> ofEmptyIsEverything(
4242
return new FilterValuesEmptyIsEverything<>(name, values);
4343
}
4444

45+
/**
46+
* Returns a {@link FilterValues} that matches everything if the filter values are null.
47+
* </p>
48+
* @param name - The name of the filter.
49+
* @param <E> - The type of the filter values. Typically, String or {@link FeedScopedId}.
50+
* @param values - The {@link Collection} of filter values.
51+
* @return FilterValues
52+
*/
53+
public static <E> FilterValues<E> ofNullIsEverything(
54+
String name,
55+
@Nullable Collection<E> values
56+
) {
57+
return new FilterValuesNullIsEverything<>(name, values);
58+
}
59+
4560
/**
4661
* Returns a {@link RequiredFilterValues} that throws an exception at creation time if the filter
4762
* values is null or empty.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package org.opentripplanner.transit.api.model;
2+
3+
import java.util.Collection;
4+
5+
/**
6+
* {@link FilterValuesNullIsEverything} is a subclass of {@link FilterValues} that
7+
* includes everything only if the values collection is null.
8+
*/
9+
public class FilterValuesNullIsEverything<E> extends FilterValues<E> {
10+
11+
FilterValuesNullIsEverything(String name, Collection<E> values) {
12+
super(name, values);
13+
}
14+
15+
@Override
16+
public boolean includeEverything() {
17+
return values == null;
18+
}
19+
}

application/src/main/java/org/opentripplanner/transit/api/request/TripRequest.java

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,40 @@
1212
*/
1313
public class TripRequest {
1414

15-
private final FilterValues<FeedScopedId> agencies;
16-
private final FilterValues<FeedScopedId> routes;
17-
private final FilterValues<String> netexInternalPlanningCodes;
18-
private final FilterValues<LocalDate> serviceDates;
15+
private final FilterValues<FeedScopedId> includeAgencies;
16+
private final FilterValues<FeedScopedId> includeRoutes;
17+
private final FilterValues<String> includeNetexInternalPlanningCodes;
18+
private final FilterValues<LocalDate> includeServiceDates;
1919

2020
TripRequest(
21-
FilterValues<FeedScopedId> agencies,
22-
FilterValues<FeedScopedId> routes,
23-
FilterValues<String> netexInternalPlanningCodes,
24-
FilterValues<LocalDate> serviceDates
21+
FilterValues<FeedScopedId> includeAgencies,
22+
FilterValues<FeedScopedId> includeRoutes,
23+
FilterValues<String> includeNetexInternalPlanningCodes,
24+
FilterValues<LocalDate> includeServiceDates
2525
) {
26-
this.agencies = agencies;
27-
this.routes = routes;
28-
this.netexInternalPlanningCodes = netexInternalPlanningCodes;
29-
this.serviceDates = serviceDates;
26+
this.includeAgencies = includeAgencies;
27+
this.includeRoutes = includeRoutes;
28+
this.includeNetexInternalPlanningCodes = includeNetexInternalPlanningCodes;
29+
this.includeServiceDates = includeServiceDates;
3030
}
3131

3232
public static TripRequestBuilder of() {
3333
return new TripRequestBuilder();
3434
}
3535

36-
public FilterValues<FeedScopedId> agencies() {
37-
return agencies;
36+
public FilterValues<FeedScopedId> includeAgencies() {
37+
return includeAgencies;
3838
}
3939

40-
public FilterValues<FeedScopedId> routes() {
41-
return routes;
40+
public FilterValues<FeedScopedId> includeRoutes() {
41+
return includeRoutes;
4242
}
4343

44-
public FilterValues<String> netexInternalPlanningCodes() {
45-
return netexInternalPlanningCodes;
44+
public FilterValues<String> includeNetexInternalPlanningCodes() {
45+
return includeNetexInternalPlanningCodes;
4646
}
4747

48-
public FilterValues<LocalDate> serviceDates() {
49-
return serviceDates;
48+
public FilterValues<LocalDate> includeServiceDates() {
49+
return includeServiceDates;
5050
}
5151
}

application/src/main/java/org/opentripplanner/transit/api/request/TripRequestBuilder.java

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,65 @@
22

33
import java.time.LocalDate;
44
import java.util.List;
5+
import javax.annotation.Nullable;
56
import org.opentripplanner.transit.api.model.FilterValues;
67
import org.opentripplanner.transit.model.framework.FeedScopedId;
78

89
public class TripRequestBuilder {
910

10-
private FilterValues<FeedScopedId> agencies = FilterValues.ofEmptyIsEverything(
11-
"agencies",
12-
List.of()
11+
private FilterValues<FeedScopedId> includeAgencies = FilterValues.ofNullIsEverything(
12+
"includeAgencies",
13+
null
1314
);
14-
private FilterValues<FeedScopedId> routes = FilterValues.ofEmptyIsEverything("routes", List.of());
15-
private FilterValues<String> netexInternalPlanningCodes = FilterValues.ofEmptyIsEverything(
16-
"netexInternalPlanningCodes",
17-
List.of()
15+
private FilterValues<FeedScopedId> includeRoutes = FilterValues.ofNullIsEverything(
16+
"includeRoutes",
17+
null
1818
);
19-
private FilterValues<LocalDate> serviceDates = FilterValues.ofEmptyIsEverything(
20-
"serviceDates",
21-
List.of()
19+
private FilterValues<String> includeNetexInternalPlanningCodes = FilterValues.ofNullIsEverything(
20+
"includeNetexInternalPlanningCodes",
21+
null
22+
);
23+
private FilterValues<LocalDate> includeServiceDates = FilterValues.ofNullIsEverything(
24+
"includeServiceDates",
25+
null
2226
);
2327

2428
TripRequestBuilder() {}
2529

26-
public TripRequestBuilder withAgencies(FilterValues<FeedScopedId> agencies) {
27-
this.agencies = agencies;
30+
public TripRequestBuilder withIncludeAgencies(@Nullable List<FeedScopedId> includeAgencies) {
31+
this.includeAgencies = FilterValues.ofNullIsEverything("includeAgencies", includeAgencies);
2832
return this;
2933
}
3034

31-
public TripRequestBuilder withRoutes(FilterValues<FeedScopedId> routes) {
32-
this.routes = routes;
35+
public TripRequestBuilder withIncludeRoutes(@Nullable List<FeedScopedId> includeRoutes) {
36+
this.includeRoutes = FilterValues.ofNullIsEverything("includeRoutes", includeRoutes);
3337
return this;
3438
}
3539

36-
public TripRequestBuilder withNetexInternalPlanningCodes(
37-
FilterValues<String> netexInternalPlanningCodes
40+
public TripRequestBuilder withIncludeNetexInternalPlanningCodes(
41+
@Nullable List<String> includeNetexInternalPlanningCodes
3842
) {
39-
this.netexInternalPlanningCodes = netexInternalPlanningCodes;
43+
this.includeNetexInternalPlanningCodes = FilterValues.ofNullIsEverything(
44+
"includeNetexInternalPlanningCodes",
45+
includeNetexInternalPlanningCodes
46+
);
4047
return this;
4148
}
4249

43-
public TripRequestBuilder withServiceDates(FilterValues<LocalDate> serviceDates) {
44-
this.serviceDates = serviceDates;
50+
public TripRequestBuilder withIncludeServiceDates(@Nullable List<LocalDate> includeServiceDates) {
51+
this.includeServiceDates = FilterValues.ofNullIsEverything(
52+
"includeServiceDates",
53+
includeServiceDates
54+
);
4555
return this;
4656
}
4757

4858
public TripRequest build() {
49-
return new TripRequest(agencies, routes, netexInternalPlanningCodes, serviceDates);
59+
return new TripRequest(
60+
includeAgencies,
61+
includeRoutes,
62+
includeNetexInternalPlanningCodes,
63+
includeServiceDates
64+
);
5065
}
5166
}

application/src/main/java/org/opentripplanner/transit/model/filter/transit/TripMatcherFactory.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,14 @@ public static Matcher<Trip> of(
3636
) {
3737
ExpressionBuilder<Trip> expr = ExpressionBuilder.of();
3838

39-
expr.atLeastOneMatch(request.agencies(), TripMatcherFactory::agencyId);
40-
expr.atLeastOneMatch(request.routes(), TripMatcherFactory::routeId);
39+
expr.atLeastOneMatch(request.includeAgencies(), TripMatcherFactory::agencyId);
40+
expr.atLeastOneMatch(request.includeRoutes(), TripMatcherFactory::routeId);
4141
expr.atLeastOneMatch(
42-
request.netexInternalPlanningCodes(),
42+
request.includeNetexInternalPlanningCodes(),
4343
TripMatcherFactory::netexInternalPlanningCode
4444
);
4545
expr.atLeastOneMatch(
46-
request.serviceDates(),
46+
request.includeServiceDates(),
4747
TripMatcherFactory.serviceDate(serviceDateProvider)
4848
);
4949

application/src/test/java/org/opentripplanner/transit/model/filter/transit/TripMatcherFactoryTest.java

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
package org.opentripplanner.transit.model.filter.transit;
22

3-
import static org.junit.Assert.assertFalse;
4-
import static org.junit.Assert.assertTrue;
3+
import static org.junit.jupiter.api.Assertions.assertFalse;
4+
import static org.junit.jupiter.api.Assertions.assertTrue;
55

66
import java.time.LocalDate;
77
import java.util.List;
88
import java.util.Set;
99
import org.junit.jupiter.api.BeforeEach;
1010
import org.junit.jupiter.api.Test;
11-
import org.opentripplanner.transit.api.model.FilterValues;
1211
import org.opentripplanner.transit.api.request.TripRequest;
1312
import org.opentripplanner.transit.model.basic.TransitMode;
1413
import org.opentripplanner.transit.model.filter.expr.Matcher;
@@ -75,9 +74,7 @@ void setup() {
7574
@Test
7675
void testMatchRouteId() {
7776
TripRequest request = TripRequest.of()
78-
.withRoutes(
79-
FilterValues.ofEmptyIsEverything("routes", List.of(new FeedScopedId("F", "RUT:route:1")))
80-
)
77+
.withIncludeRoutes(List.of(new FeedScopedId("F", "RUT:route:1")))
8178
.build();
8279

8380
Matcher<Trip> matcher = TripMatcherFactory.of(request, feedScopedId -> Set.of());
@@ -98,12 +95,32 @@ void testMatchDefaultAll() {
9895
assertTrue(matcher.match(tripAkt));
9996
}
10097

98+
@Test
99+
void testNullListMatchesAll() {
100+
TripRequest request = TripRequest.of().withIncludeAgencies(null).build();
101+
102+
Matcher<Trip> matcher = TripMatcherFactory.of(request, feedScopedId -> Set.of());
103+
104+
assertTrue(matcher.match(tripRut));
105+
assertTrue(matcher.match(tripRut2));
106+
assertTrue(matcher.match(tripAkt));
107+
}
108+
109+
@Test
110+
void testEmptyListMatchesNone() {
111+
TripRequest request = TripRequest.of().withIncludeAgencies(List.of()).build();
112+
113+
Matcher<Trip> matcher = TripMatcherFactory.of(request, feedScopedId -> Set.of());
114+
115+
assertFalse(matcher.match(tripRut));
116+
assertFalse(matcher.match(tripRut2));
117+
assertFalse(matcher.match(tripAkt));
118+
}
119+
101120
@Test
102121
void testMatchAgencyId() {
103122
TripRequest request = TripRequest.of()
104-
.withAgencies(
105-
FilterValues.ofEmptyIsEverything("agencies", List.of(new FeedScopedId("F", "RUT:1")))
106-
)
123+
.withIncludeAgencies(List.of(new FeedScopedId("F", "RUT:1")))
107124
.build();
108125

109126
Matcher<Trip> matcher = TripMatcherFactory.of(request, feedScopedId -> Set.of());
@@ -116,12 +133,7 @@ void testMatchAgencyId() {
116133
@Test
117134
void testMatchServiceDates() {
118135
TripRequest request = TripRequest.of()
119-
.withServiceDates(
120-
FilterValues.ofEmptyIsEverything(
121-
"operatingDays",
122-
List.of(LocalDate.of(2024, 2, 22), LocalDate.of(2024, 2, 23))
123-
)
124-
)
136+
.withIncludeServiceDates(List.of(LocalDate.of(2024, 2, 22), LocalDate.of(2024, 2, 23)))
125137
.build();
126138

127139
Matcher<Trip> matcher = TripMatcherFactory.of(request, this::dummyServiceDateProvider);

0 commit comments

Comments
 (0)