invalid_category

This rule checks if the rows of a categorical column in a table have the right values. A right value is one in the set of allowable values for the categorical column. For example, the coll column in the samples table is a categorical column whose set of allowable values or categories are comp3h, comp8h, flowPr etc. The following samples table row would fail validation,

                                                  Invalid Dataset                                                  
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ coll                                                                                                            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ flow                                                                                                            │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

The following samples table row would pass validation,

                                                   Valid Dataset                                                   
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ coll                                                                                                            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ flowPr                                                                                                          │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

For non-mandatory categorical columns, values representing missing are also allowed. Assuming that coll is not mandatory, the following table should pass validation,

                                                   Valid Dataset                                                   
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ coll                                                                                                            ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ NA                                                                                                              │
│                                                                                                                 │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘

The second row contains an empty string.

Error report

The error report will have the following fields

  • errorType: invalid_category

  • tableName: The name of the table whose row has the invalid category

  • columnName The name of the column with the invalid category

  • rowNumber: The index of the table row with the error

  • row The row in the data that failed this validation rule

  • invalidValue: The invalid category value

  • validationRuleFields: The ODM data dictionary rule fields violated by this row

  • message: Invalid category <invalidValue> found in row <rowIndex> for column <columnName> in table <tableName>

Example

{
'errors': [
│   │   {
│   │   │   'errorType': 'invalid_category',
│   │   │   'tableName': 'samples',
│   │   │   'columnName': 'coll',
│   │   │   'rowNumber': 1,
│   │   │   'row': {
│   │   │   │   'coll': 'flow'
│   │   │   },
│   │   │   'invalidValue': 'flow',
│   │   │   'validationRuleFields': [
│   │   │   │   {
│   │   │   │   │   'partID': 'coll',
│   │   │   │   │   'samples': 'header',
│   │   │   │   │   'dataType': 'categorical',
│   │   │   │   │   'mmaSet': 'collectCat'
│   │   │   │   },
│   │   │   │   {
│   │   │   │   │   'partID': 'comp3h',
│   │   │   │   │   'setID': 'collectCat'
│   │   │   │   },
│   │   │   │   {
│   │   │   │   │   'partID': 'comp8h',
│   │   │   │   │   'setID': 'collectCat'
│   │   │   │   },
│   │   │   │   {
│   │   │   │   │   'partID': 'flowPr',
│   │   │   │   │   'setID': 'collectCat'
│   │   │   │   }
│   │   │   ],
│   │   │   'message': 'invalid_category rule violated in table samples, column coll, row(s) 1: Invalid category "flow"'
│   │   }
],
'warnings': []
}

Rule metadata

The metadata for this rule is contained in two sheets:

  1. The parts sheet which has information on whether a column is categorical and if it is, information on how to find the categories that are part of it

  2. The sets sheet which contains information on the categories

The steps to use this meatdata are:

  1. Get all the columns that are part of the table

  2. Filter the columns to only include those that are categorical. Categorical columns have a dataType value of categorical.

  3. For each categorical column, identify the name of the set that has the categories for that column. The set name is stored in the mmaSet column.

  4. Use the sets sheet and the value of the mmaSet column to identify the categories. For each categorical column, filter the sets sheet to only include those rows whose setID column value is the same as the mmaSet value.

  5. In the filtered rows, the partID column contains the category values.

Example

                                                     Parts v2                                                      
┏━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━━━━━┓
┃ partID     partType   samples  sites  measures  dataType   mmaSet     status     firstRele…  lastUpda… ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━━━━━┩
│ samples   │ tables    │ NA      │ NA    │ NA       │ NA        │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ sites     │ tables    │ NA      │ NA    │ NA       │ NA        │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ measures  │ tables    │ NA      │ NA    │ NA       │ NA        │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ coll      │ attribut… │ header  │ NA    │ NA       │ categori… │ collectC… │ active    │ 1.0.0      │ 2.0.0     │
│ comp3h    │ categori… │ input   │ NA    │ NA       │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ comp8h    │ categori… │ input   │ NA    │ NA       │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ flowPr    │ categori… │ input   │ NA    │ NA       │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ siteType… │ attribut… │ NA      │ fK    │ NA       │ categori… │ siteType… │ active    │ 1.0.0      │ 2.0.0     │
│ wwtpMuC   │ categori… │ NA      │ input │ NA       │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ wwtpMuS   │ categori… │ NA      │ input │ NA       │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ someOldC… │ categori… │ NA      │ input │ NA       │ varchar   │ NA        │ deprecia… │ 1.0.0      │ 2.0.0     │
│ tp24s     │ categori… │ NA      │ NA    │ NA       │ NA        │ NA        │ deprecia… │ 1.0.0      │ 2.0.0     │
│ measureID │ attribut… │ NA      │ NA    │ fK       │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ cod       │ categori… │ NA      │ NA    │ input    │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
│ NA        │ missingn… │ NA      │ NA    │ NA       │ varchar   │ NA        │ active    │ 1.0.0      │ 2.0.0     │
└───────────┴───────────┴─────────┴───────┴──────────┴───────────┴───────────┴───────────┴────────────┴───────────┘
                                                       Sets                                                        
┏━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ setID                   partID          firstReleased                lastUpdated              status        ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ collectCat             │ comp3h         │ 1.0.0                       │ 2.0.0                   │ active        │
│ collectCat             │ comp8h         │ 1.0.0                       │ 2.0.0                   │ active        │
│ collectCat             │ flowPr         │ 1.0.0                       │ 2.0.0                   │ active        │
└────────────────────────┴────────────────┴─────────────────────────────┴─────────────────────────┴───────────────┘

Here, the name of the categorical column is coll and its a column in the samples table. The set name is collectCat which is used to identify the category values in the sets sheet which are comp3h, comp8h, and flowPr.

Cerberus Schema

The generated cerberus object for the example above is shown below,

{
'schemaVersion': '2.0.0',
'schema': {
│   │   'samples': {
│   │   │   'type': 'list',
│   │   │   'schema': {
│   │   │   │   'type': 'dict',
│   │   │   │   'schema': {
│   │   │   │   │   'coll': {
│   │   │   │   │   │   'allowed': [
│   │   │   │   │   │   │   'comp3h',
│   │   │   │   │   │   │   'comp8h',
│   │   │   │   │   │   │   'flowPr'
│   │   │   │   │   │   ],
│   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   'ruleID': 'invalid_category',
│   │   │   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'coll',
│   │   │   │   │   │   │   │   │   │   'samples': 'header',
│   │   │   │   │   │   │   │   │   │   'dataType': 'categorical',
│   │   │   │   │   │   │   │   │   │   'mmaSet': 'collectCat'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'comp3h',
│   │   │   │   │   │   │   │   │   │   'setID': 'collectCat'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'comp8h',
│   │   │   │   │   │   │   │   │   │   'setID': 'collectCat'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'flowPr',
│   │   │   │   │   │   │   │   │   │   'setID': 'collectCat'
│   │   │   │   │   │   │   │   │   }
│   │   │   │   │   │   │   │   ]
│   │   │   │   │   │   │   }
│   │   │   │   │   │   ]
│   │   │   │   │   }
│   │   │   │   },
│   │   │   │   'meta': [
│   │   │   │   │   {
│   │   │   │   │   │   'partID': 'samples',
│   │   │   │   │   │   'partType': 'tables'
│   │   │   │   │   }
│   │   │   │   ]
│   │   │   }
│   │   }
}
}

The metadata for this rule should include the following rows from the ODM dictionary:

  • The part definition for the column in the table

  • The sets definition for each category that forms the category set for the categorical column

Version 1

Generating the cerberus schema for version 1 requires the following information:

  1. The columns that are part of the version 1 table

  2. Whether the column is categorical and

  3. If it is, the list of allowed categories

Information on point 1 can be found here.

To check whether a version 1 column is categorical, we can use the version1Location column. If the column has a value of variableCategories then the part was a category in version 1. We can then look at the value of the version1Category column to see the what the category value was in version 1. For example, in the ODM parts snippet below,

                                                     Parts v1                                                      
┏━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━━┳━━━━━━━┳━━━━━━━━┓
┃ part…  part…  samp…  sites  meas…  data…  mmaS…  vers…  vers…  vers…  vers…  status  firs…  lastU… ┃
┡━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━━╇━━━━━━━╇━━━━━━━━┩
│ samp… │ tabl… │ NA    │ NA    │ NA    │ NA    │ NA    │ tabl… │ Samp… │ NA    │ NA    │ active │ 1.0.0 │ 2.0.0  │
│ sites │ tabl… │ NA    │ NA    │ NA    │ NA    │ NA    │ tabl… │ Site  │ NA    │ NA    │ active │ 1.0.0 │ 2.0.0  │
│ meas… │ tabl… │ NA    │ NA    │ NA    │ NA    │ NA    │ tabl… │ WWMe… │ NA    │ NA    │ active │ 1.0.0 │ 2.0.0  │
│ coll  │ attr… │ head… │ NA    │ NA    │ cate… │ coll… │ vari… │ Samp… │ Coll… │ NA    │ active │ 1.0.0 │ 2.0.0  │
│ comp… │ cate… │ input │ NA    │ NA    │ varc… │ NA    │ vari… │ Samp… │ Coll… │ Comp… │ active │ 1.0.0 │ 2.0.0  │
│ comp… │ cate… │ input │ NA    │ NA    │ varc… │ NA    │ vari… │ Samp… │ Coll… │ Comp… │ active │ 1.0.0 │ 2.0.0  │
│ flow… │ cate… │ input │ NA    │ NA    │ varc… │ NA    │ vari… │ Samp… │ Coll… │ Flow… │ active │ 1.0.0 │ 2.0.0  │
│ site… │ attr… │ NA    │ fK    │ NA    │ cate… │ site… │ vari… │ Site  │ type  │ NA    │ active │ 1.0.0 │ 2.0.0  │
│ wwtp… │ cate… │ NA    │ input │ NA    │ varc… │ NA    │ vari… │ Site  │ type  │ wwtp… │ active │ 1.0.0 │ 2.0.0  │
│ wwtp… │ cate… │ NA    │ input │ NA    │ varc… │ NA    │ vari… │ Site  │ type  │ wwtp… │ active │ 1.0.0 │ 2.0.0  │
│ some… │ cate… │ NA    │ input │ NA    │ varc… │ NA    │ vari… │ Site  │ type  │ some… │ depre… │ 1.0.0 │ 2.0.0  │
│ tp24s │ cate… │ NA    │ NA    │ NA    │ NA    │ NA    │ vari… │ Site  │ Samp… │ cpTP… │ depre… │ 1.0.0 │ 2.0.0  │
│ meas… │ attr… │ NA    │ NA    │ fK    │ varc… │ NA    │ vari… │ WWMe… │ type  │ NA    │ active │ 1.0.0 │ 2.0.0  │
│ cod   │ cate… │ NA    │ NA    │ input │ varc… │ NA    │ vari… │ WWMe… │ type  │ wqCO… │ active │ 1.0.0 │ 2.0.0  │
│       │       │       │       │       │       │       │       │ Site… │       │ wwCOD │        │       │        │
│ NA    │ miss… │ NA    │ NA    │ NA    │ varc… │ NA    │ NA    │ NA    │ NA    │ NA    │ active │ 1.0.0 │ 2.0.0  │
└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴────────┴───────┴────────┘

In the snippet above, for a version 1 variable, we check whether the version1Category column has a value. If it does then it is categorical. We can then retreive the categories by looking at all the unique version1Category values for that variable. Keep in mind, that there can be multiple categories encoded in a cell, with each value seperated by a semi-colon.

The version 1 variable Collection column has four categories, Comp3h, Comp8h, FlowPR, FlowRatePr.

The corresponding cerberus schema for version 1 would be,

{
'schemaVersion': '1.0.0',
'schema': {
│   │   'Sample': {
│   │   │   'type': 'list',
│   │   │   'schema': {
│   │   │   │   'type': 'dict',
│   │   │   │   'schema': {
│   │   │   │   │   'Collection': {
│   │   │   │   │   │   'allowed': [
│   │   │   │   │   │   │   'Comp3h',
│   │   │   │   │   │   │   'Comp8h',
│   │   │   │   │   │   │   'FlowPr',
│   │   │   │   │   │   │   'FlowRatePr',
│   │   │   │   │   │   │   'other'
│   │   │   │   │   │   ],
│   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   'ruleID': 'invalid_category',
│   │   │   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'coll',
│   │   │   │   │   │   │   │   │   │   'dataType': 'categorical',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variables',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Sample',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'Collection'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'comp3h',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variableCategories',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Sample',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'Collection',
│   │   │   │   │   │   │   │   │   │   'version1Category': 'Comp3h'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'comp8h',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variableCategories',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Sample',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'Collection',
│   │   │   │   │   │   │   │   │   │   'version1Category': 'Comp8h'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'flowPr',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variableCategories',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Sample',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'Collection',
│   │   │   │   │   │   │   │   │   │   'version1Category': 'FlowPr;FlowRatePr'
│   │   │   │   │   │   │   │   │   }
│   │   │   │   │   │   │   │   ]
│   │   │   │   │   │   │   }
│   │   │   │   │   │   ]
│   │   │   │   │   }
│   │   │   │   },
│   │   │   │   'meta': [
│   │   │   │   │   {
│   │   │   │   │   │   'partID': 'samples',
│   │   │   │   │   │   'partType': 'tables',
│   │   │   │   │   │   'version1Location': 'tables',
│   │   │   │   │   │   'version1Table': 'Sample'
│   │   │   │   │   }
│   │   │   │   ]
│   │   │   }
│   │   },
│   │   'Site': {
│   │   │   'type': 'list',
│   │   │   'schema': {
│   │   │   │   'type': 'dict',
│   │   │   │   'schema': {
│   │   │   │   │   'type': {
│   │   │   │   │   │   'allowed': [
│   │   │   │   │   │   │   'other',
│   │   │   │   │   │   │   'someOldCat1',
│   │   │   │   │   │   │   'wwtpMuC',
│   │   │   │   │   │   │   'wwtpMuS'
│   │   │   │   │   │   ],
│   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   'ruleID': 'invalid_category',
│   │   │   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'siteTypeID',
│   │   │   │   │   │   │   │   │   │   'dataType': 'categorical',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variables',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Site',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'type'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'wwtpMuC',
│   │   │   │   │   │   │   │   │   │   'version1Category': 'wwtpMuC',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variableCategories',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Site',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'type'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'wwtpMuS',
│   │   │   │   │   │   │   │   │   │   'version1Category': 'wwtpMuS',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variableCategories',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Site',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'type'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'someOldCat',
│   │   │   │   │   │   │   │   │   │   'version1Category': 'someOldCat1',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variableCategories',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'Site',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'type'
│   │   │   │   │   │   │   │   │   }
│   │   │   │   │   │   │   │   ]
│   │   │   │   │   │   │   }
│   │   │   │   │   │   ]
│   │   │   │   │   }
│   │   │   │   },
│   │   │   │   'meta': [
│   │   │   │   │   {
│   │   │   │   │   │   'partID': 'sites',
│   │   │   │   │   │   'partType': 'tables',
│   │   │   │   │   │   'version1Location': 'tables',
│   │   │   │   │   │   'version1Table': 'Site'
│   │   │   │   │   }
│   │   │   │   ]
│   │   │   }
│   │   },
│   │   'WWMeasure': {
│   │   │   'type': 'list',
│   │   │   'schema': {
│   │   │   │   'type': 'dict',
│   │   │   │   'schema': {
│   │   │   │   │   'type': {
│   │   │   │   │   │   'allowed': [
│   │   │   │   │   │   │   'other',
│   │   │   │   │   │   │   'wqCOD',
│   │   │   │   │   │   │   'wwCOD'
│   │   │   │   │   │   ],
│   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   'ruleID': 'invalid_category',
│   │   │   │   │   │   │   │   'meta': [
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'dataType': 'varchar',
│   │   │   │   │   │   │   │   │   │   'partID': 'measureID',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variables',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'WWMeasure',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'type'
│   │   │   │   │   │   │   │   │   },
│   │   │   │   │   │   │   │   │   {
│   │   │   │   │   │   │   │   │   │   'partID': 'cod',
│   │   │   │   │   │   │   │   │   │   'version1Category': 'wqCOD; wwCOD',
│   │   │   │   │   │   │   │   │   │   'version1Location': 'variableCategories',
│   │   │   │   │   │   │   │   │   │   'version1Table': 'WWMeasure; SiteMeasure',
│   │   │   │   │   │   │   │   │   │   'version1Variable': 'type'
│   │   │   │   │   │   │   │   │   }
│   │   │   │   │   │   │   │   ]
│   │   │   │   │   │   │   }
│   │   │   │   │   │   ]
│   │   │   │   │   }
│   │   │   │   },
│   │   │   │   'meta': [
│   │   │   │   │   {
│   │   │   │   │   │   'partID': 'measures',
│   │   │   │   │   │   'partType': 'tables',
│   │   │   │   │   │   'version1Location': 'tables',
│   │   │   │   │   │   'version1Table': 'WWMeasure'
│   │   │   │   │   }
│   │   │   │   ]
│   │   │   }
│   │   }
}
}

The meta field for the rule should include the same part rows and fields as version 2 with the following additions,

  • The version1Location, version1Table, and version1Variable` columns added to all the rows

  • The version1Category column added to the category parts