Skip to content

Commit

Permalink
feat: 1776 add flex features to list (#1780)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>

* 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 <[email protected]>
  • Loading branch information
qcdyx and cka-y authored Sep 9, 2024
1 parent 37ed5e7 commit 014bac0
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -104,3 +104,5 @@ app/pkg/bin/
processor/notices/bin/
processor/notices/tests/bin/
web/service/bin/

RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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() {}

Expand Down Expand Up @@ -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<GtfsTableContainer<?>> 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<GtfsTableContainer<?>> 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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
@@ -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 {}
Original file line number Diff line number Diff line change
@@ -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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 014bac0

Please sign in to comment.