From 014bac028f3b128d71d799d5782de21dcd178a4e Mon Sep 17 00:00:00 2001 From: Jingsi Lu Date: Mon, 9 Sep 2024 14:00:24 -0400 Subject: [PATCH] feat: 1776 add flex features to list (#1780) * GtfsBookingRulesSchema and GtfsBookingTypeEnum * added Flex features - Booking Rules: At least one record in booking_rules.txt * added flex rule: Fixed-Stops Demand Responsive Transit: At least one record in location_groups.txt * added Flex rules: Zone-based Demand Responsive Transit and Deviated Fixed Route * updated Zone-based Demand Responsive Transit * no message * updated GtfsBookingRulesSchema * updated Deviated Fixed Route features * updated Zone-Based Demand Responsive Transit * modified Zone-Based Demand Responsive Transit logic * updated logic * Update main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/FeedMetadata.java Co-authored-by: cka-y <60586858+cka-y@users.noreply.github.com> * updated .gitignore * fix Java syntax error * Delete web/client/static/RULES.md * removed the @required for stopId, since stop_times.txt without stopid is unparsable * added back @Required * addressed PR comments --------- Co-authored-by: cka-y <60586858+cka-y@users.noreply.github.com> --- .gitignore | 2 + .../report/model/FeedMetadata.java | 58 +++++++++++++++++- .../table/GtfsBookingRulesSchema.java | 60 +++++++++++++++++++ .../table/GtfsBookingTypeEnum.java | 23 +++++++ .../table/GtfsLocationGroupsSchema.java | 19 ++++++ .../table/GtfsStopTimeSchema.java | 3 + 6 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingRulesSchema.java create mode 100644 main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingTypeEnum.java create mode 100644 main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsLocationGroupsSchema.java diff --git a/.gitignore b/.gitignore index af4b5e8a58..e4b3a4c077 100644 --- a/.gitignore +++ b/.gitignore @@ -104,3 +104,5 @@ app/pkg/bin/ processor/notices/bin/ processor/notices/tests/bin/ web/service/bin/ + +RULES.md \ No newline at end of file diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/FeedMetadata.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/FeedMetadata.java index 832daea602..4aba98a51b 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/FeedMetadata.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/report/model/FeedMetadata.java @@ -60,7 +60,9 @@ public class FeedMetadata { new Pair<>("Zone-Based Fares", GtfsArea.FILENAME), new Pair<>("Transfer Fares", GtfsFareTransferRule.FILENAME), new Pair<>("Time-Based Fares", GtfsTimeframe.FILENAME), - new Pair<>("Levels", GtfsLevel.FILENAME)); + new Pair<>("Levels", GtfsLevel.FILENAME), + new Pair<>("Booking Rules", GtfsBookingRules.FILENAME), + new Pair<>("Fixed-Stops Demand Responsive Transit", GtfsLocationGroups.FILENAME)); protected FeedMetadata() {} @@ -156,6 +158,60 @@ private void loadSpecFeaturesBasedOnFieldPresence(GtfsFeedContainer feedContaine loadPathwayExtraFeature(feedContainer); loadRouteBasedFaresFeature(feedContainer); loadContinuousStopsFeature(feedContainer); + loadZoneBasedDemandResponsiveTransitFeature(feedContainer); + loadDeviatedFixedRouteFeature(feedContainer); + } + + private void loadDeviatedFixedRouteFeature(GtfsFeedContainer feedContainer) { + specFeatures.put("Deviated Fixed Route", hasAtLeastOneTripWithAllFields(feedContainer)); + } + + private boolean hasAtLeastOneTripWithAllFields(GtfsFeedContainer feedContainer) { + Optional> optionalStopTimeTable = + feedContainer.getTableForFilename(GtfsStopTime.FILENAME); + if (optionalStopTimeTable.isPresent()) { + for (GtfsEntity entity : optionalStopTimeTable.get().getEntities()) { + if (entity instanceof GtfsStopTime) { + GtfsStopTime stopTime = (GtfsStopTime) entity; + return stopTime.hasTripId() + && stopTime.tripId() != null + && stopTime.hasLocationId() + && stopTime.locationId() != null + && stopTime.hasStopId() + && stopTime.stopId() != null + && stopTime.hasArrivalTime() + && stopTime.arrivalTime() != null + && stopTime.hasDepartureTime() + && stopTime.departureTime() != null; + } + } + } + return false; + } + + private void loadZoneBasedDemandResponsiveTransitFeature(GtfsFeedContainer feedContainer) { + specFeatures.put( + "Zone-Based Demand Responsive Transit", hasAtLeastOneTripWithOnlyLocationId(feedContainer)); + } + + private boolean hasAtLeastOneTripWithOnlyLocationId(GtfsFeedContainer feedContainer) { + Optional> optionalStopTimeTable = + feedContainer.getTableForFilename(GtfsStopTime.FILENAME); + if (optionalStopTimeTable.isPresent()) { + for (GtfsEntity entity : optionalStopTimeTable.get().getEntities()) { + if (entity instanceof GtfsStopTime) { + GtfsStopTime stopTime = (GtfsStopTime) entity; + if (stopTime.hasTripId() + && stopTime.tripId() != null + && stopTime.hasLocationId() + && stopTime.locationId() != null + && (!stopTime.hasStopId() || stopTime.stopId() == null)) { + return true; + } + } + } + } + return false; } private void loadContinuousStopsFeature(GtfsFeedContainer feedContainer) { diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingRulesSchema.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingRulesSchema.java new file mode 100644 index 0000000000..44973c2647 --- /dev/null +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingRulesSchema.java @@ -0,0 +1,60 @@ +package org.mobilitydata.gtfsvalidator.table; + +import org.mobilitydata.gtfsvalidator.annotation.ConditionallyRequired; +import org.mobilitydata.gtfsvalidator.annotation.FieldType; +import org.mobilitydata.gtfsvalidator.annotation.FieldTypeEnum; +import org.mobilitydata.gtfsvalidator.annotation.GtfsTable; +import org.mobilitydata.gtfsvalidator.annotation.MixedCase; +import org.mobilitydata.gtfsvalidator.annotation.PrimaryKey; +import org.mobilitydata.gtfsvalidator.annotation.Required; +import org.mobilitydata.gtfsvalidator.type.GtfsTime; + +@GtfsTable("booking_rules.txt") +public interface GtfsBookingRulesSchema extends GtfsEntity { + @FieldType(FieldTypeEnum.ID) + @PrimaryKey + @Required + String bookingRuleId(); + + @Required + GtfsBookingType bookingType(); + + @ConditionallyRequired + int priorNoticeDurationMin(); + + @ConditionallyRequired + int priorNoticeDurationMax(); + + @ConditionallyRequired + int priorNoticeStartDay(); + + @ConditionallyRequired + GtfsTime priorNoticeStartTime(); + + @ConditionallyRequired + int priorNoticeLastDay(); + + @ConditionallyRequired + GtfsTime priorNoticeLastTime(); + + @ConditionallyRequired + String priorNoticeServiceId(); + + @MixedCase + String message(); + + @MixedCase + String pickupMessage(); + + @MixedCase + String dropOffMessage(); + + @FieldType(FieldTypeEnum.PHONE_NUMBER) + String phoneNumber(); + + @FieldType(FieldTypeEnum.URL) + String infoUrl(); + + @FieldType(FieldTypeEnum.URL) + String bookingUrl(); +} diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingTypeEnum.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingTypeEnum.java new file mode 100644 index 0000000000..7c5cbcd161 --- /dev/null +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsBookingTypeEnum.java @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.mobilitydata.gtfsvalidator.table; + +import org.mobilitydata.gtfsvalidator.annotation.GtfsEnumValue; + +@GtfsEnumValue(name = "REALTIME", value = 0) +@GtfsEnumValue(name = "SAMEDAY", value = 1) +@GtfsEnumValue(name = "PRIORDAY", value = 2) +public interface GtfsBookingTypeEnum {} diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsLocationGroupsSchema.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsLocationGroupsSchema.java new file mode 100644 index 0000000000..e3f035037f --- /dev/null +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsLocationGroupsSchema.java @@ -0,0 +1,19 @@ +package org.mobilitydata.gtfsvalidator.table; + +import org.mobilitydata.gtfsvalidator.annotation.FieldType; +import org.mobilitydata.gtfsvalidator.annotation.FieldTypeEnum; +import org.mobilitydata.gtfsvalidator.annotation.GtfsTable; +import org.mobilitydata.gtfsvalidator.annotation.MixedCase; +import org.mobilitydata.gtfsvalidator.annotation.PrimaryKey; +import org.mobilitydata.gtfsvalidator.annotation.Required; + +@GtfsTable("location_groups.txt") +public interface GtfsLocationGroupsSchema extends GtfsEntity { + @FieldType(FieldTypeEnum.ID) + @PrimaryKey + @Required + String locationGroupId(); + + @MixedCase + String locationGroupName(); +} diff --git a/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java index f35ce24ff9..7f6a05589c 100644 --- a/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java +++ b/main/src/main/java/org/mobilitydata/gtfsvalidator/table/GtfsStopTimeSchema.java @@ -56,6 +56,9 @@ public interface GtfsStopTimeSchema extends GtfsEntity { @ForeignKey(table = "stops.txt", field = "stop_id") String stopId(); + @FieldType(FieldTypeEnum.ID) + String locationId(); + @PrimaryKey(isSequenceUsedForSorting = true, translationRecordIdType = RECORD_SUB_ID) @Required @NonNegative