invalid_type¶
This rule checks that the type of a value matches with a defined type or can be coerced into the defined type. There are a number of types in the ODM that this validation rule will need to handle, we’ll go over each of them in the following sections.
integer¶
An integer is defined as a number without a decimal point. Imagine a
column geoLat
in the sites table which is defined to be an integer.
The following ODM data snippet would fail validation,
# This is a YAML file since in a CSV file all the numbers would be included as
# a string
pprint_yaml_file(asset("integer-invalid-dataset-1.yml"))
[ │ { │ │ 'siteID': 1, │ │ 'geoLat': 1.23 │ } ]
whereas the following would pass validation
# This is a YAML file since in a CSV file all the numbers would be included as
# a string
pprint_yaml_file(asset("integer-valid-dataset-1.yml"))
[ │ { │ │ 'siteID': 1, │ │ 'geoLat': 1 │ } ]
Values that are not explicitly integers but can be coerced into integers should pass validation. For example, the following should pass validation,
Valid integer dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ siteID ┃ geoLat ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ 1 │ │ 2 │ 1.00 │ └────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────┘
A floating point number can be coerced into an integer if the coercion does not result in a value change. In above example, coercing 1.00 to its integer value of 1 does not change its value.
The snippet below should fail validation since they cannot be coerced to integers.
Invalid integer dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ siteID ┃ geoLat ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ a │ │ 2 │ 1.01 │ └────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────┘
float¶
A float is a decimal number. Imagine the same geoLat
column but its
defined type is now a float. The following dataset snippet would fail
validation,
Invalid float dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ siteID ┃ geoLat ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ a │ └────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────┘
whereas the following would pass validation
[ │ { │ │ 'siteID': 1, │ │ 'geoLat': 1.23 │ } ]
Once again, values that can be coerced into floats should pass validation. All integers and certain strings can be coerced into floats. For example, the following snippet below should pass validation,
Valid float dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ siteID ┃ geoLat ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ 1.0 │ └────────────────────────────────────────────────────────┴────────────────────────────────────────────────────────┘
boolean¶
A column that can have one of two values, representing Yes/No. The
category values representing Yes/No are encoded in the dictionary. For
example, consider the reportable
column in the measures
table whose
data type is boolean. Also, assume that true
and false
are the
allowed boolean category values. The following dataset snippet would
fail validation,
Invalid bool dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ measureID ┃ reportable ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ Yes │ └──────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────┘
whereas the following the would pass validation,
Valid bool dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ measureID ┃ reportable ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ true │ └──────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────┘
The category values are case-sensitive i.e. the boolean column value case should match the one in the category values. For example, the following would fail validation,
Invalid bool dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ measureID ┃ reportable ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ True │ └──────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────┘
datetime¶
A type that allows columns to have a string that holds a date and time value. The date component is mandatory whereas the time component is optional. Regardless of what’s included in the column value, the string should be formatted using the ISO 8601 standard. Although the standard specifies a number of ways to represent datetime, for the purposes of the ODM only the following formats will be supported.
date
datetime and
datetime with timezone
For example, consider the reportDate
column in the measures
table
whose type is datetime
. The following dataset snippet should pass
validation,
pprint_csv_file(asset("datetime-valid-dataset-1.csv"),
"Valid datetime dataset")
Valid datetime dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ measureID ┃ reportDate ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ 2022-01-01 │ │ 2 │ 2022-01-01T06:11:54 │ │ 3 │ 2022-01-01T06:11:54+13:30 │ └─────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────┘
whereas the following dataset should fail validation,
pprint_csv_file(asset("datetime-invalid-dataset-1.csv"),
"Invalid datetime dataset")
Invalid datetime dataset ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ measureID ┃ reportDate ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ 1 │ a │ │ 2 │ 2022 │ └──────────────────────────────────────────────────────┴──────────────────────────────────────────────────────────┘
categorical¶
This type is handled by the invalid_category rule
varchar¶
No validation is currently needed for this type since all the previously mentioned types can be coerced into a varchar.
see measure¶
Can be ignored for now.
Error report¶
The error report should have the following fields,
errorType: invalid_type
tableName: The name of the table with the invalid value
columnName: The name of the column with the invalid value
rowNumber: The 1-based index of the row with the invalid value
row: The dictionary containing the invalid row
invalidValue: The invalid value
validationRuleFields: The ODM data dictionary rows used to generate this rule
message: Value <invalid_value> in row <row_number> in column <column_name> in table <table_name> has type <invalid_value_type> but should be of type <valid_type> or coercable into a <valid_type>.
For a boolean data type, the message is shown below,
message: Row <row_number> in column <column_name> in table <table_name> is a boolean but has value <invalid_value>. Allowed values are <boolean_categories>.
For a datetime data type, the message is shown belowm,
message: Row <row_number> in column <column_name> in table <table_name> is a datetime with value <invalid_value> that has an unsupported datetime format. Allowed values are ISO 8601 standard full dates, full dates and times, or full dates and times with timezone.
The error report objects for the invalid examples above can be seen below,
integer
{ │ 'errors': [ │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'sites', │ │ │ 'columnName': 'geoLat', │ │ │ 'rowNumber': 1, │ │ │ 'row': { │ │ │ │ 'siteID': 1, │ │ │ │ 'geoLat': 1.23 │ │ │ }, │ │ │ 'invalidValue': 1.23, │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ 'dataType': 'integer', │ │ │ │ │ 'sites': 'header' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table sites, column geoLat, row(s) 1: Value "1.23" has type float which is incompatible with integer' │ │ } │ ], │ 'warnings': [] }
integer
{ │ 'errors': [ │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'sites', │ │ │ 'columnName': 'geoLat', │ │ │ 'rowNumber': 1, │ │ │ 'row': { │ │ │ │ 'siteID': '1', │ │ │ │ 'geoLat': 'a' │ │ │ }, │ │ │ 'invalidValue': 'a', │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ 'dataType': 'integer', │ │ │ │ │ 'sites': 'header' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table sites, column geoLat, row(s) 1: Value "a" has type string which is incompatible with integer' │ │ }, │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'sites', │ │ │ 'columnName': 'geoLat', │ │ │ 'rowNumber': 2, │ │ │ 'row': { │ │ │ │ 'siteID': '2', │ │ │ │ 'geoLat': '1.01' │ │ │ }, │ │ │ 'invalidValue': '1.01', │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ 'dataType': 'integer', │ │ │ │ │ 'sites': 'header' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table sites, column geoLat, row(s) 2: Value "1.01" has type string which is incompatible with integer' │ │ } │ ], │ 'warnings': [] }
float
{ │ 'errors': [ │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'sites', │ │ │ 'columnName': 'geoLat', │ │ │ 'rowNumber': 1, │ │ │ 'row': { │ │ │ │ 'siteID': '1', │ │ │ │ 'geoLat': 'a' │ │ │ }, │ │ │ 'invalidValue': 'a', │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ 'dataType': 'float', │ │ │ │ │ 'sites': 'header' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table sites, column geoLat, row(s) 1: Value "a" has type string which is incompatible with float' │ │ } │ ], │ 'warnings': [] }
boolean 1
{ │ 'errors': [ │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'measures', │ │ │ 'columnName': 'reportable', │ │ │ 'rowNumber': 1, │ │ │ 'row': { │ │ │ │ 'measureID': '1', │ │ │ │ 'reportable': 'Yes' │ │ │ }, │ │ │ 'invalidValue': 'Yes', │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'reportable', │ │ │ │ │ 'dataType': 'boolean', │ │ │ │ │ 'measures': 'header' │ │ │ │ }, │ │ │ │ { │ │ │ │ │ 'partID': 'false', │ │ │ │ │ 'setID': 'booleanSet' │ │ │ │ }, │ │ │ │ { │ │ │ │ │ 'partID': 'true', │ │ │ │ │ 'setID': 'booleanSet' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table measures, column reportable, row(s) 1: Column reportable is a boolean but has value "Yes". Allowed values are false/true.' │ │ } │ ], │ 'warnings': [] }
boolean 2
{ │ 'errors': [ │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'measures', │ │ │ 'columnName': 'reportable', │ │ │ 'rowNumber': 1, │ │ │ 'row': { │ │ │ │ 'measureID': '1', │ │ │ │ 'reportable': 'True' │ │ │ }, │ │ │ 'invalidValue': 'True', │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'reportable', │ │ │ │ │ 'dataType': 'boolean', │ │ │ │ │ 'measures': 'header' │ │ │ │ }, │ │ │ │ { │ │ │ │ │ 'partID': 'false', │ │ │ │ │ 'setID': 'booleanSet' │ │ │ │ }, │ │ │ │ { │ │ │ │ │ 'partID': 'true', │ │ │ │ │ 'setID': 'booleanSet' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table measures, column reportable, row(s) 1: Column reportable is a boolean but has value "True". Allowed values are false/true.' │ │ } │ ], │ 'warnings': [] }
datetime
pprint_json_file(asset("datetime-error-report-1.json"))
{ │ 'errors': [ │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'measures', │ │ │ 'columnName': 'reportDate', │ │ │ 'row': { │ │ │ │ 'measureID': '1', │ │ │ │ 'reportDate': 'a' │ │ │ }, │ │ │ 'rowNumber': 1, │ │ │ 'invalidValue': 'a', │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'reportDate', │ │ │ │ │ 'dataType': 'datetime', │ │ │ │ │ 'measures': 'header' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table measures, column reportDate, row(s) 1: Column reportDate is a datetime but has value "a". Allowed values are ISO 8601 standard full dates, full dates and times, or full dates and times with timezone.' │ │ }, │ │ { │ │ │ 'errorType': 'invalid_type', │ │ │ 'tableName': 'measures', │ │ │ 'columnName': 'reportDate', │ │ │ 'row': { │ │ │ │ 'measureID': '2', │ │ │ │ 'reportDate': '2022' │ │ │ }, │ │ │ 'rowNumber': 2, │ │ │ 'invalidValue': '2022', │ │ │ 'validationRuleFields': [ │ │ │ │ { │ │ │ │ │ 'partID': 'reportDate', │ │ │ │ │ 'dataType': 'datetime', │ │ │ │ │ 'measures': 'header' │ │ │ │ } │ │ │ ], │ │ │ 'message': 'invalid_type rule violated in table measures, column reportDate, row(s) 2: Column reportDate is a datetime but has value "2022". Allowed values are ISO 8601 standard full dates, full dates and times, or full dates and times with timezone.' │ │ } │ ], │ 'warnings': [] }
Rule metadata¶
All the metadata for this rule is contained in the parts sheet in the ODM dictionary. The steps to retreive the metadata are:
Get the defined data type for each column. If the data type is a boolean then retreive the category values by using the sets sheet: 1. Filter out all rows except for the ones whose
setID
isbooleanSet
2. ThepartID
columns in the filtered rows contains the category valuesAdd this validation rule if the data type is supported by this validation rule. Currently, only the
blob
is not supported and we don’t need to add a rule for thevarchar
column.
For example, the parts sheet snippets for the examples above can be seen below,
For an integer geoLat
column in a sites table
Integer parts v2 ┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ sites ┃ dataType ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ │ sites │ tables │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ geoLat │ attributes │ header │ integer │ active │ 1.0.0 │ 2.0.0 │ └────────────┴──────────────────┴────────────┴───────────────┴────────────┴─────────────────────┴─────────────────┘
For a float geoLat
column in a sites table
Float parts v2 ┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ sites ┃ dataType ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ │ sites │ tables │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ geoLat │ attributes │ header │ float │ active │ 1.0.0 │ 2.0.0 │ └────────────┴──────────────────┴────────────┴───────────────┴────────────┴─────────────────────┴─────────────────┘
For the boolean reportable
column in the measures
table,
the part sheet is below,
Bool parts v2 ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ measures ┃ dataType ┃ mmaSet ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩ │ measures │ tables │ NA │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ reportable │ attributes │ header │ boolean │ booleanSet │ active │ 1.0.0 │ 2.0.0 │ │ true │ categories │ NA │ varchar │ NA │ active │ 1.0.0 │ 2.0.0 │ │ false │ categories │ NA │ varchar │ NA │ active │ 1.0.0 │ 2.0.0 │ └──────────────┴──────────────┴────────────┴────────────┴──────────────┴─────────┴─────────────────┴──────────────┘
and the sets sheet is,
Bool set v2 ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ setID ┃ partID ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩ │ booleanSet │ true │ 1.0.0 │ 2.0.0 │ │ booleanSet │ false │ 1.0.0 │ 2.0.0 │ └────────────────────────────┴───────────────────┴──────────────────────────────────┴─────────────────────────────┘
For the datetime reportDate
column in the measures
table,
pprint_csv_file(asset("datetime-parts.csv"), "Datetime parts v2",
ignore_prefix="version1")
Datetime parts v2 ┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ measures ┃ dataType ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩ │ measures │ tables │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ reportDate │ attributes │ header │ datetime │ active │ 1.0.0 │ 2.0.0 │ └─────────────────┴────────────────┴──────────────┴──────────────┴───────────┴───────────────────┴────────────────┘
Cerberus schema¶
We can use the type rule in cerberus to perform this validation. Cerberus by default does not coerce the data before validating, we will need to explicitly tell it to do so by using the coerce field.
For a boolean
type we will need to use the
allowed
rule in cerberus.
For a datetime
type we will need to
extend
cerberus and add a new datetime type.
The generated cerberus objects for the examples above are shown below,
integer
{ │ 'schemaVersion': '2.0.0', │ 'schema': { │ │ 'sites': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'geoLat': { │ │ │ │ │ │ 'type': 'integer', │ │ │ │ │ │ 'coerce': 'integer', │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ │ │ │ │ │ 'dataType': 'integer', │ │ │ │ │ │ │ │ │ │ 'sites': 'header' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'sites', │ │ │ │ │ │ 'partType': 'tables' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
float
{ │ 'schemaVersion': '2.0.0', │ 'schema': { │ │ 'sites': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'geoLat': { │ │ │ │ │ │ 'type': 'float', │ │ │ │ │ │ 'coerce': 'float', │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ │ │ │ │ │ 'dataType': 'float', │ │ │ │ │ │ │ │ │ │ 'sites': 'header' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'sites', │ │ │ │ │ │ 'partType': 'tables' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
boolean
{ │ 'schemaVersion': '2.0.0', │ 'schema': { │ │ 'measures': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'reportable': { │ │ │ │ │ │ 'type': 'string', │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ 'false', │ │ │ │ │ │ │ 'true' │ │ │ │ │ │ ], │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'reportable', │ │ │ │ │ │ │ │ │ │ 'dataType': 'boolean', │ │ │ │ │ │ │ │ │ │ 'measures': 'header' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'false', │ │ │ │ │ │ │ │ │ │ 'setID': 'booleanSet' │ │ │ │ │ │ │ │ │ }, │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'true', │ │ │ │ │ │ │ │ │ │ 'setID': 'booleanSet' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'measures', │ │ │ │ │ │ 'partType': 'tables' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
datetime
pprint_yaml_file(asset("datetime-schema-v2.yml"))
{ │ 'schemaVersion': '2.0.0', │ 'schema': { │ │ 'measures': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'reportDate': { │ │ │ │ │ │ 'type': 'datetime', │ │ │ │ │ │ 'coerce': 'datetime', │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'reportDate', │ │ │ │ │ │ │ │ │ │ 'dataType': 'datetime', │ │ │ │ │ │ │ │ │ │ 'measures': 'header' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'measures', │ │ │ │ │ │ 'partType': 'tables' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
The meta for this rule should include the partID
, <table_name>
, and
dataType
.
For a boolean data type, it should also include the rows that contain
the category values. The partID
and setID
from each row should be
included in the category value rows.
ODM Version 1¶
When generating the schema for version 1, we check whether the column has an equivalent part in version 1. If it does, then we add this validaton rule to it. For example, the v1 parts snippets for each of examples above are shown below,
integer
Integer parts v1 ┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ sites ┃ dataType ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ │ sites │ tables │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ geoLat │ attributes │ header │ integer │ active │ 1.0.0 │ 2.0.0 │ └────────────┴──────────────────┴────────────┴───────────────┴────────────┴─────────────────────┴─────────────────┘
float
Float parts v1 ┏━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ sites ┃ dataType ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━┩ │ sites │ tables │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ geoLat │ attributes │ header │ float │ active │ 1.0.0 │ 2.0.0 │ └────────────┴──────────────────┴────────────┴───────────────┴────────────┴─────────────────────┴─────────────────┘
boolean
Bool parts v1 ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ measures ┃ dataType ┃ mmaSet ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━┩ │ measures │ tables │ NA │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ reportable │ attributes │ header │ boolean │ booleanSet │ active │ 1.0.0 │ 2.0.0 │ │ true │ categories │ NA │ varchar │ NA │ active │ 1.0.0 │ 2.0.0 │ │ false │ categories │ NA │ varchar │ NA │ active │ 1.0.0 │ 2.0.0 │ └──────────────┴──────────────┴────────────┴────────────┴──────────────┴─────────┴─────────────────┴──────────────┘
datetime
pprint_csv_file(asset("datetime-parts.csv"), "Datetime parts v1",
ignore_prefix="version1")
Datetime parts v1 ┏━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┓ ┃ partID ┃ partType ┃ measures ┃ dataType ┃ status ┃ firstReleased ┃ lastUpdated ┃ ┡━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━┩ │ measures │ tables │ NA │ NA │ active │ 1.0.0 │ 2.0.0 │ │ reportDate │ attributes │ header │ datetime │ active │ 1.0.0 │ 2.0.0 │ └─────────────────┴────────────────┴──────────────┴──────────────┴───────────┴───────────────────┴────────────────┘
The corresponding v1 cerberus schemas are shown below,
integer
{ │ 'schemaVersion': '1.0.0', │ 'schema': { │ │ 'Site': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'Latitude': { │ │ │ │ │ │ 'type': 'integer', │ │ │ │ │ │ 'coerce': 'integer', │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ │ │ │ │ │ 'dataType': 'integer', │ │ │ │ │ │ │ │ │ │ 'sites': 'header', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Site', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'Latitude' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'sites', │ │ │ │ │ │ 'partType': 'tables', │ │ │ │ │ │ 'version1Location': 'tables', │ │ │ │ │ │ 'version1Table': 'Site' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
float
{ │ 'schemaVersion': '1.0.0', │ 'schema': { │ │ 'Site': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'Latitude': { │ │ │ │ │ │ 'type': 'float', │ │ │ │ │ │ 'coerce': 'float', │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'geoLat', │ │ │ │ │ │ │ │ │ │ 'dataType': 'float', │ │ │ │ │ │ │ │ │ │ 'sites': 'header', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Site', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'Latitude' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'sites', │ │ │ │ │ │ 'partType': 'tables', │ │ │ │ │ │ 'version1Location': 'tables', │ │ │ │ │ │ 'version1Table': 'Site' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
boolean
{ │ 'schemaVersion': '1.1.0', │ 'schema': { │ │ 'Measure': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'reported': { │ │ │ │ │ │ 'type': 'string', │ │ │ │ │ │ 'allowed': [ │ │ │ │ │ │ │ 'FALSE', │ │ │ │ │ │ │ 'TRUE' │ │ │ │ │ │ ], │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'reportable', │ │ │ │ │ │ │ │ │ │ 'dataType': 'boolean', │ │ │ │ │ │ │ │ │ │ 'measures': 'header', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Measure', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'reported' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'measures', │ │ │ │ │ │ 'partType': 'tables', │ │ │ │ │ │ 'version1Location': 'tables', │ │ │ │ │ │ 'version1Table': 'Measure' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
datetime
pprint_yaml_file(asset("datetime-schema-v1.yml"))
{ │ 'schemaVersion': '1.0.0', │ 'schema': { │ │ 'Measure': { │ │ │ 'type': 'list', │ │ │ 'schema': { │ │ │ │ 'type': 'dict', │ │ │ │ 'schema': { │ │ │ │ │ 'DateReport': { │ │ │ │ │ │ 'type': 'datetime', │ │ │ │ │ │ 'coerce': 'datetime', │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ 'ruleID': 'invalid_type', │ │ │ │ │ │ │ │ 'meta': [ │ │ │ │ │ │ │ │ │ { │ │ │ │ │ │ │ │ │ │ 'partID': 'reportDate', │ │ │ │ │ │ │ │ │ │ 'dataType': 'datetime', │ │ │ │ │ │ │ │ │ │ 'measures': 'header', │ │ │ │ │ │ │ │ │ │ 'version1Location': 'variables', │ │ │ │ │ │ │ │ │ │ 'version1Table': 'Measure', │ │ │ │ │ │ │ │ │ │ 'version1Variable': 'DateReport' │ │ │ │ │ │ │ │ │ } │ │ │ │ │ │ │ │ ] │ │ │ │ │ │ │ } │ │ │ │ │ │ ] │ │ │ │ │ } │ │ │ │ }, │ │ │ │ 'meta': [ │ │ │ │ │ { │ │ │ │ │ │ 'partID': 'measures', │ │ │ │ │ │ 'partType': 'tables', │ │ │ │ │ │ 'version1Location': 'tables', │ │ │ │ │ │ 'version1Table': 'Measure' │ │ │ │ │ } │ │ │ │ ] │ │ │ } │ │ } │ } }
The metadata should include the meta columns for version 2 as well as
the version1Location
, version1Table
, and the version1Variable
columns.
For a boolean data type, only the version1Category
column should be
added on for the boolean category values.