Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Initial support for Fares v2 validation. #1228

Merged
merged 21 commits into from
Oct 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
6e90eaa
Initial support for Fares v2 validation.
bdferris-v2 Aug 5, 2022
fe7052c
Add validation for currency amount.
bdferris-v2 Aug 5, 2022
2e72a0d
Add workaround for the very large values present in the areas.txt 'wk…
bdferris-v2 Aug 5, 2022
cd58e3a
Bump areas.txt max-chars-per-column to unlimited.
bdferris-v2 Aug 5, 2022
59862fe
Remove debug statement.
bdferris-v2 Aug 9, 2022
dfdf243
Merge branch 'master' into issue/1201/fares
bdferris-v2 Aug 17, 2022
9495243
Merge branch 'master' into issue/1201/fares
bdferris-v2 Sep 14, 2022
89d1554
Update to use @CurrencyAmount annotation.
bdferris-v2 Sep 14, 2022
9285ea3
Add documentation for new fares notices.
bdferris-v2 Sep 14, 2022
82107ed
Fix typo.
bdferris-v2 Sep 14, 2022
4026388
Add documentation for invalid currency amount.
bdferris-v2 Sep 14, 2022
da9cf96
Fix typo.
bdferris-v2 Sep 14, 2022
0691570
Merge branch 'master' into issue/1201/fares
maximearmstrong Sep 21, 2022
4c3f66e
Merge branch 'issue/1201/fares' of https://github.com/bdferris-v2/gtf…
bdferris-v2 Sep 29, 2022
594b913
Add documentation for FareTransferRuleDurationLimitWithoutTypeNotice.
bdferris-v2 Sep 29, 2022
a0f69f2
Fix variable name.
bdferris-v2 Sep 29, 2022
a965192
Add fare_transfer_rule_duration_limit_type_without_duration_limit val…
bdferris-v2 Sep 29, 2022
e8fae01
Remove blank lines.
bdferris-v2 Sep 29, 2022
5f12a8c
Rename InvalidFareTransferRuleTransferCountNotice to better match nam…
bdferris-v2 Oct 3, 2022
aa0b7a1
Merge branch 'master' into issue/1201/fares
bdferris-v2 Oct 3, 2022
aa6e4f8
Add missing field to documentation.
bdferris-v2 Oct 3, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions RULES.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,16 @@ Each Notice is associated with a severity: `INFO`, `WARNING`, `ERROR`.
| [`empty_column_name`](#empty_column_name) | A column name is empty. |
| [`empty_file`](#empty_file) | A CSV file is empty. |
| [`equal_shape_distance_diff_coordinates`](#equal_shape_distance_diff_coordinates) | Two consecutive points have equal `shape_dist_traveled` and different lat/lon coordinates in `shapes.txt`. |
| [`fare_transfer_rule_duration_limit_type_without_duration_limit`](#fare_transfer_rule_duration_limit_type_without_duration_limit) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit_type` field but no `duration_limit` specified. |
| [`fare_transfer_rule_duration_limit_without_type`](#fare_transfer_rule_duration_limit_without_type) | A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit` field but no `duration_limit_type` specified. |
| [`fare_transfer_rule_invalid_transfer_count`](#fare_transfer_rule_invalid_transfer_count) | A row from GTFS file `fare_transfer_rules.txt` has a defined `transfer_count` with an invalid value. |
| [`fare_transfer_rule_missing_transfer_count`](#fare_transfer_rule_missing_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` equal to `to_leg_group_id`, but has no `transfer_count` specified. |
| [`fare_transfer_rule_with_forbidden_transfer_count`](#fare_transfer_rule_with_forbidden_transfer_count) | A row from `fare_transfer_rules.txt` has `from_leg_group_id` not equal to `to_leg_group_id`, but has `transfer_count` specified. |
| [`foreign_key_violation`](#foreign_key_violation) | Wrong foreign key. |
| [`inconsistent_agency_timezone`](#inconsistent_agency_timezone) | Inconsistent Timezone among agencies. |
| [`invalid_color`](#invalid_color) | A field contains an invalid color value. |
| [`invalid_currency`](#invalid_currency) | A field contains a wrong currency code. |
| [`invalid_currency_amount`](#invalid_currency_amount) | A currency amount field has a value that does not match the format of its corresponding currency code field. |
| [`invalid_date`](#invalid_date) | A field cannot be parsed as date. |
| [`invalid_email`](#invalid_email) | A field contains a malformed email address. |
| [`invalid_float`](#invalid_float) | A field cannot be parsed as a floating point number. |
Expand Down Expand Up @@ -403,6 +409,112 @@ When sorted by `shape.shape_pt_sequence`, the values for `shape_dist_traveled` m

</details>

<a name="FareTransferRuleDurationLimitTypeWithoutDurationLimitNotice"/>

### fare_transfer_rule_duration_limit_type_without_duration_limit

A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit_type` field but no `duration_limit` specified.

#### References
* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

<details>

#### Notice fields description
| Field name | Description | Type |
|----------------- |---------------------------------------------------- |-------- |
| `csvRowNumber` | The row of the faulty record. | Long |

#### Affected files
* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

</details>

<a name="FareTransferRuleDurationLimitWithoutTypeNotice"/>

### fare_transfer_rule_duration_limit_without_type

A row from GTFS file `fare_transfer_rules.txt` has a defined `duration_limit` field but no `duration_limit_type` specified.

#### References
* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

<details>

#### Notice fields description
| Field name | Description | Type |
|----------------- |---------------------------------------------------- |-------- |
| `csvRowNumber` | The row of the faulty record. | Long |

#### Affected files
* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

</details>

<a name="FareTransferRuleInvalidTransferCountNotice"/>

### fare_transfer_rule_invalid_transfer_count

A row from GTFS file `fare_transfer_rules.txt` has a defined `transfer_count` with an invalid value.

#### References
* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

<details>

#### Notice fields description
| Field name | Description | Type |
|----------------- |---------------------------------------------------- |-------- |
| `csvRowNumber` | The row of the faulty record. | Long |
| `transferCount` | The transfer count value of the faulty record. | Integer |

#### Affected files
* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

</details>

<a name="FareTransferRuleMissingTransferCountNotice"/>

### fare_transfer_rule_missing_transfer_count

A row from GTFS file `fare_transfer_rules.txt` has `from_leg_group_id` equal to `to_leg_group_id`, but has no `transfer_count` specified. Per the spec, `transfer_count` is required if the two leg group ids are equal.

#### References
* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

<details>

#### Notice fields description
| Field name | Description | Type |
|----------------- |---------------------------------------------------- |-------- |
| `csvRowNumber` | The row of the faulty record. | Long |

#### Affected files
* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

</details>

<a name="FareTransferRuleWithForbiddenTransferCountNotice"/>

### fare_transfer_rule_with_forbidden_transfer_count

A row from GTFS file `fare_transfer_rules.txt` has `from_leg_group_id` not equal to `to_leg_group_id`, but has `transfer_count` specified. Per the spec, `transfer_count` is forbidden if the two leg group ids are not equal.

#### References
* [GTFS fare_transfer_rules.txt](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

<details>

#### Notice fields description
| Field name | Description | Type |
|----------------- |---------------------------------------------------- |-------- |
| `csvRowNumber` | The row of the faulty record. | Long |

#### Affected files
* [`fare_transfer_rules.txt`](https://gtfs.org/schedule/reference/#fare_transfer_rulestxt)

</details>

<a name="ForeignKeyViolationNotice"/>

### foreign_key_violation
Expand Down Expand Up @@ -507,6 +619,29 @@ Value of field with type `currency` is not valid. Currency code must follow <a h

</details>

<a name="InvalidCurrencyAmountNotice"/>

### invalid_currency_amount

A currency amount field has a value that does not match the format (e.g. expected number of decimal places) of its corresponding currency code field. The number of decimal places is specified by <a href="https://en.wikipedia.org/wiki/ISO_4217#Active_codes">ISO 4217</a>.

#### References
* [Field Types Description](http://gtfs.org/reference/static/#field-types)
<details>

#### Notice fields description
| Field name | Description | Type |
|-------------- |------------------------------- |-------- |
| `filename` | The row of the faulty record. | String |
| `csvRowNumber`| The row of the faulty record. | Long |
| `fieldName` | Faulty record's field name. | String |
| `amount` | Faulty currency amount value. | String |

#### Affected files
* [`fare_products.txt`](http://gtfs.org/reference/static#fare_productstxt)

</details>

<a name="InvalidDateNotice"/>

### invalid_date
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@
String value();

boolean singleRow() default false;

/**
* If a non-zero integer is specified, this will override the default max-chars-per-column setting
* for the CSV Parser.
*/
int maxCharsPerColumn() default 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,22 @@ public class CsvFile implements Iterable<CsvRow> {
private final CsvHeader headers;
private final String filename;

public static CsvParserSettings createDefaultParserSettings() {
CsvParserSettings settings = new CsvParserSettings();
settings.getFormat().setLineSeparator("\n");
settings.getFormat().setDelimiter(',');
settings.setHeaderExtractionEnabled(true);
// Explicitly disable trimming of whitespaces because we will emit notices for them.
settings.setIgnoreLeadingWhitespacesInQuotes(false);
settings.setIgnoreTrailingWhitespacesInQuotes(false);
return settings;
}

public CsvFile(InputStream inputStream, String filename) {
this(inputStream, filename, createDefaultParserSettings());
}

public CsvFile(InputStream inputStream, String filename, CsvParserSettings settings) {
this.filename = filename;

// Only UTF-8 is supported according to GTFS reference. We may add optional support for other
Expand All @@ -54,13 +69,6 @@ public CsvFile(InputStream inputStream, String filename) {
final BufferedReader reader =
new BufferedReader(new InputStreamReader(bomInputStream, decoder));

CsvParserSettings settings = new CsvParserSettings();
settings.getFormat().setLineSeparator("\n");
settings.getFormat().setDelimiter(',');
settings.setHeaderExtractionEnabled(true);
// Explicitly disable trimming of whitespaces because we will emit notices for them.
settings.setIgnoreLeadingWhitespacesInQuotes(false);
settings.setIgnoreTrailingWhitespacesInQuotes(false);
parser = new CsvParser(settings);
parser.beginParsing(reader);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Copyright 2022 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.FieldType;
import org.mobilitydata.gtfsvalidator.annotation.FieldTypeEnum;
import org.mobilitydata.gtfsvalidator.annotation.GtfsTable;
import org.mobilitydata.gtfsvalidator.annotation.PrimaryKey;
import org.mobilitydata.gtfsvalidator.annotation.Required;

@GtfsTable(
value = "areas.txt",
// We specify no limit (-1) here to support the experimental 'wkt' column, which encodes
// an area polygon as a WKT string, which can grow quite large. While this column has not yet
// been added to the spec, it is present in many feeds (e.g. those produced by Trillium), which
// can cause issues for the CSV parser.
maxCharsPerColumn = -1)
public interface GtfsAreaSchema extends GtfsEntity {
@FieldType(FieldTypeEnum.ID)
@Required
@PrimaryKey
String areaId();

String areaName();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright 2022 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 = "DEPARTURE_TO_ARRIVAL", value = 0)
@GtfsEnumValue(name = "DEPARTURE_TO_DEPARTURE", value = 1)
@GtfsEnumValue(name = "ARRIVAL_TO_DEPARTURE", value = 2)
@GtfsEnumValue(name = "ARRIVAL_TO_ARRIVAL", value = 3)
public interface GtfsDurationLimitTypeEnum {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Copyright 2022 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 static org.mobilitydata.gtfsvalidator.annotation.TranslationRecordIdType.UNSUPPORTED;

import org.mobilitydata.gtfsvalidator.annotation.FieldType;
import org.mobilitydata.gtfsvalidator.annotation.FieldTypeEnum;
import org.mobilitydata.gtfsvalidator.annotation.ForeignKey;
import org.mobilitydata.gtfsvalidator.annotation.GtfsTable;
import org.mobilitydata.gtfsvalidator.annotation.Index;
import org.mobilitydata.gtfsvalidator.annotation.PrimaryKey;
import org.mobilitydata.gtfsvalidator.annotation.Required;

@GtfsTable("fare_leg_rules.txt")
public interface GtfsFareLegRuleSchema extends GtfsEntity {
@FieldType(FieldTypeEnum.ID)
@Index
String legGroupId();

@FieldType(FieldTypeEnum.ID)
@PrimaryKey(translationRecordIdType = UNSUPPORTED)
@ForeignKey(table = "routes.txt", field = "network_id")
String networkId();

@FieldType(FieldTypeEnum.ID)
@PrimaryKey(translationRecordIdType = UNSUPPORTED)
@ForeignKey(table = "areas.txt", field = "area_id")
String fromAreaId();

@FieldType(FieldTypeEnum.ID)
@PrimaryKey(translationRecordIdType = UNSUPPORTED)
@ForeignKey(table = "areas.txt", field = "area_id")
String toAreaId();

@FieldType(FieldTypeEnum.ID)
@Required
@PrimaryKey(translationRecordIdType = UNSUPPORTED)
@ForeignKey(table = "fare_products.txt", field = "fare_product_id")
String fareProductId();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Copyright 2022 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 java.math.BigDecimal;
import java.util.Currency;
import org.mobilitydata.gtfsvalidator.annotation.CurrencyAmount;
import org.mobilitydata.gtfsvalidator.annotation.FieldType;
import org.mobilitydata.gtfsvalidator.annotation.FieldTypeEnum;
import org.mobilitydata.gtfsvalidator.annotation.GtfsTable;
import org.mobilitydata.gtfsvalidator.annotation.NonNegative;
import org.mobilitydata.gtfsvalidator.annotation.PrimaryKey;
import org.mobilitydata.gtfsvalidator.annotation.Required;

@GtfsTable("fare_products.txt")
public interface GtfsFareProductSchema extends GtfsEntity {
@FieldType(FieldTypeEnum.ID)
@Required
@PrimaryKey
String fareProductId();

String fareProductName();

@Required
@NonNegative
@CurrencyAmount(currencyField = "currency")
BigDecimal amount();

@Required
Currency currency();
}
Loading