diff --git a/synapseclient/extensions/curator/schema_generation.py b/synapseclient/extensions/curator/schema_generation.py index 172bd8c1c..b6328c35e 100644 --- a/synapseclient/extensions/curator/schema_generation.py +++ b/synapseclient/extensions/curator/schema_generation.py @@ -659,6 +659,7 @@ def gather_csv_attributes_relationships( # Check for presence of optional columns model_includes_column_type = "columnType" in model_df.columns model_includes_format = "Format" in model_df.columns + model_includes_pattern = "Pattern" in model_df.columns # Build attribute/relationship dictionary relationship_types = self.required_headers @@ -697,6 +698,12 @@ def gather_csv_attributes_relationships( attr_rel_dictionary[attribute_name]["Relationships"].update( maximum_dict ) + + if model_includes_pattern: + pattern_dict = self.parse_pattern(attr) + attr_rel_dictionary[attribute_name]["Relationships"].update( + pattern_dict + ) return attr_rel_dictionary def parse_column_type(self, attr: dict) -> dict: @@ -798,6 +805,26 @@ def parse_format(self, attribute_dict: dict) -> dict[str, str]: return {"Format": format_string} + def parse_pattern(self, attribute_dict: dict) -> dict[str, str]: + """Finds the pattern value if it exists and returns it as a dictionary. + + Args: + attribute_dict: The attribute dictionary. + Returns: + A dictionary containing the pattern value if it exists + else an empty dict + """ + from pandas import isna + + pattern_value = attribute_dict.get("Pattern") + + if isna(pattern_value): + return {} + + pattern_string = str(pattern_value).strip() + + return {"Pattern": pattern_string} + def parse_csv_model( self, path_to_data_model: str, @@ -1815,6 +1842,27 @@ def get_node_column_type( raise ValueError(msg) return column_type + def get_node_column_pattern( + self, node_label: Optional[str] = None, node_display_name: Optional[str] = None + ) -> Optional[str]: + """Gets the regex pattern of the node + + Args: + node_label: The label of the node to get the type from + node_display_name: The display name of the node to get the type from + + Raises: + ValueError: If the value from the node is not allowed + + Returns: + The column pattern of the node if it has one, otherwise None + """ + node_label = self._get_node_label(node_label, node_display_name) + rel_node_label = self.dmr.get_relationship_value("pattern", "node_label") + pattern = self.graph.nodes[node_label][rel_node_label] + + return pattern + def get_node_format( self, node_label: Optional[str] = None, node_display_name: Optional[str] = None ) -> Optional[JSONSchemaFormat]: @@ -1942,6 +1990,9 @@ class PropertyTemplate: magic_validationRules: list = field( default_factory=list, metadata=config(field_name="sms:validationRules") ) + magic_pattern: list = field( + default_factory=list, metadata=config(field_name="sms:pattern") + ) @dataclass_json @@ -2841,6 +2892,7 @@ def define_data_model_relationships(self) -> dict: allowed_values: A list of values the entry must be one of edge_dir: str, 'in'/'out' is the edge an in or out edge. Define for edge relationships jsonld_dir: str, 'in'/out is the direction in or out in the JSONLD. + pattern: regex pattern that the entry must match """ map_data_model_relationships = { "displayName": { @@ -3016,6 +3068,15 @@ def define_data_model_relationships(self) -> dict: "edge_rel": False, "node_attr_dict": {"default": None}, }, + "pattern": { + "jsonld_key": "sms:pattern", + "csv_header": "Pattern", + "node_label": "pattern", + "type": str, + "required_header": False, + "edge_rel": False, + "node_attr_dict": {"default": None}, + }, } return map_data_model_relationships @@ -4741,6 +4802,9 @@ def __post_init__(self) -> None: relationship_value="minimum", node_display_name=self.display_name ) + column_pattern = self.dmge.get_node_column_pattern( + node_display_name=self.display_name + ) # list validation rule is been deprecated for use in deciding type # TODO: set self.is_array here instead of return from _get_validation_rule_based_fields # https://sagebionetworks.jira.com/browse/SYNPY-1692 @@ -4748,7 +4812,9 @@ def __post_init__(self) -> None: # Validate column type compatibility with min/max constraints self._validate_column_type_compatibility( - explicit_maximum=explicit_maximum, explicit_minimum=explicit_minimum + explicit_maximum=explicit_maximum, + explicit_minimum=explicit_minimum, + column_pattern=column_pattern, ) # url and date rules are deprecated for adding format keyword @@ -4771,7 +4837,7 @@ def __post_init__(self) -> None: self.format, implicit_minimum, implicit_maximum, - self.pattern, + rule_pattern, ) = _get_validation_rule_based_fields( validation_rules=validation_rules, explicit_is_array=explicit_is_array, @@ -4790,6 +4856,25 @@ def __post_init__(self) -> None: explicit_maximum if explicit_maximum is not None else implicit_maximum ) + self.pattern = column_pattern if column_pattern else rule_pattern + + if rule_pattern and not column_pattern: + msg = ( + f"A regex validation rule is set for property: {self.name}, but the pattern is not set in the data model. " + f"The regex pattern will be set to {self.pattern}, but the regex rule is deprecated and validation " + "rules will no longer be used in the future. " + "Please explicitly set the regex pattern in the 'Pattern' column in the data model." + ) + self.logger.warning(msg) + + if self.pattern: + try: + re.compile(self.pattern) + except re.error as e: + raise SyntaxError( + f"The regex pattern '{self.pattern}' for property '{self.name}' is invalid." + ) from e + def _determine_type_and_array( self, column_type: Optional[ColumnType] ) -> tuple[Optional[AtomicColumnType], Optional[bool]]: @@ -4812,6 +4897,7 @@ def _validate_column_type_compatibility( self, explicit_maximum: Union[int, float, None], explicit_minimum: Union[int, float, None], + column_pattern: Optional[str] = None, ) -> None: """Validate that columnType is compatible with Maximum/Minimum constraints. @@ -4834,7 +4920,7 @@ def _validate_column_type_compatibility( None: This method performs validation only and doesn't return a value. It raises ValueError if validation fails. """ - if not explicit_maximum and not explicit_minimum: + if not explicit_maximum and not explicit_minimum and not column_pattern: return if not self.type: raise ValueError( @@ -4842,8 +4928,14 @@ def _validate_column_type_compatibility( f"(min: {explicit_minimum}, max: {explicit_maximum}) are specified, " f"but columnType is not set. Please set columnType to 'number', 'integer' or 'integer_list'." ) + + if column_pattern and self.type and self.type.value != "string": + raise ValueError( + "Column type must be set to 'string' to use column pattern specification for regex validation." + ) + # If type is specified but not numeric, raise error - if self.type not in ( + if (explicit_maximum or explicit_minimum) and self.type not in ( AtomicColumnType.NUMBER, AtomicColumnType.INTEGER, ListColumnType.INTEGER_LIST, @@ -5412,6 +5504,9 @@ def _set_property( else: prop = _create_simple_property(node) + if node.pattern: + prop["pattern"] = node.pattern + prop["description"] = node.description prop["title"] = node.display_name schema_property = {node_name: prop} diff --git a/tests/unit/synapseclient/extensions/schema_files/data_models/example.model.csv b/tests/unit/synapseclient/extensions/schema_files/data_models/example.model.csv index f5aee46fb..36c1bfec7 100644 --- a/tests/unit/synapseclient/extensions/schema_files/data_models/example.model.csv +++ b/tests/unit/synapseclient/extensions/schema_files/data_models/example.model.csv @@ -1,92 +1,92 @@ -Attribute,Description,Valid Values,DependsOn,Properties,Required,Parent,DependsOn Component,Source,Validation Rules,columnType,Format,Maximum,Minimum -Component,,,,,TRUE,,,,,,,, -Patient,,,"Patient ID, Sex, Year of Birth, Diagnosis, Component",,FALSE,DataType,,,,,,, -Patient ID,,,,,TRUE,DataProperty,,,#Patient unique warning^^#Biospecimen unique error,,,, -Sex,,"Female, Male, Other",,,TRUE,DataProperty,,,,,,, -Year of Birth,,,,,FALSE,DataProperty,,,,,,, -Diagnosis,,"Healthy, Cancer",,,TRUE,DataProperty,,,,,,, -Cancer,,,"Cancer Type, Family History",,FALSE,ValidValue,,,,,,, -Cancer Type,,"Breast, Colorectal, Lung, Prostate, Skin",,,TRUE,DataProperty,,,,,,, -Family History,,"Breast, Colorectal, Lung, Prostate, Skin",,,TRUE,DataProperty,,,list strict,,,, -Biospecimen,,,"Sample ID, Patient ID, Tissue Status, Component",,FALSE,DataType,Patient,,,,,, -Sample ID,,,,,TRUE,DataProperty,,,,,,, -Tissue Status,,"Healthy, Malignant, None",,,TRUE,DataProperty,,,,,,, -Bulk RNA-seq Assay,,,"Filename, Sample ID, File Format, Component",,FALSE,DataType,Biospecimen,,,,,, -Filename,,,,,TRUE,DataProperty,,,#MockFilename filenameExists^^,,,, -File Format,,"FASTQ, BAM, CRAM, CSV/TSV",,,TRUE,DataProperty,,,,,,, -BAM,,,Genome Build,,FALSE,ValidValue,,,,,,, -CRAM,,,"Genome Build, Genome FASTA",,FALSE,ValidValue,,,,,,, -CSV/TSV,,,Genome Build,,FALSE,ValidValue,,,,,,, -Genome Build,,"GRCh37, GRCh38, GRCm38, GRCm39",,,TRUE,DataProperty,,,,,,, -Genome FASTA,,,,,TRUE,DataProperty,,,,,,, -MockComponent,Component to hold mock attributes for testing all validation rules,,"Component, Check List, Check List Enum, Check List Like, Check List Like Enum, Check List Strict, Check List Enum Strict, Check Regex List, Check Regex List Like, Check Regex List Strict, Check Regex Single, Check Regex Format, Check Regex Integer, Check Num, Check Float, Check Int, Check String, Check URL,Check Match at Least, Check Match at Least values, Check Match Exactly, Check Match Exactly values, Check Match None, Check Match None values, Check Recommended, Check Ages, Check Unique, Check Range, Check Date, Check NA",,FALSE,DataType,,,,,,, -Check List,,,,,TRUE,DataProperty,,,list,,,, -Check List Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list,,,, -Check List Like,,,,,TRUE,DataProperty,,,list like,,,, -Check List Like Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list like,,,, -Check List Strict,,,,,TRUE,DataProperty,,,list strict,,,, -Check List Enum Strict,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list strict,,,, -Check Regex List,,,,,TRUE,DataProperty,,,list::regex match [a-f],,,, -Check Regex List Strict,,,,,TRUE,DataProperty,,,list strict::regex match [a-f],,,, -Check Regex List Like,,,,,TRUE,DataProperty,,,list like::regex match [a-f],,,, -Check Regex Single,,,,,TRUE,DataProperty,,,regex search [a-f],,,, -Check Regex Format,,,,,TRUE,DataProperty,,,regex match [a-f],,,, -Check Regex Integer,,,,,TRUE,DataProperty,,,regex search ^\d+$,,,, -Check Num,,,,,TRUE,DataProperty,,,num error,,,, -Check Float,,,,,TRUE,DataProperty,,,float error,number,,, -Check Int,,,,,TRUE,DataProperty,,,int error,,,, -Check String,,,,,TRUE,DataProperty,,,str error,,,, -Check URL,,,,,TRUE,DataProperty,,,url,string,uri,, -Check Match at Least,,,,,TRUE,DataProperty,,,matchAtLeastOne Patient.PatientID set,,,, -Check Match Exactly,,,,,TRUE,DataProperty,,,matchExactlyOne MockComponent.checkMatchExactly set,,,, -Check Match None,,,,,TRUE,DataProperty,,,matchNone MockComponent.checkMatchNone set error,,,, -Check Match at Least values,,,,,TRUE,DataProperty,,,matchAtLeastOne MockComponent.checkMatchatLeastvalues value,,,, -Check Match Exactly values,,,,,TRUE,DataProperty,,,matchExactlyOne MockComponent.checkMatchExactlyvalues value,,,, -Check Match None values,,,,,TRUE,DataProperty,,,matchNone MockComponent.checkMatchNonevalues value error,,,, -Check Recommended,,,,,FALSE,DataProperty,,,recommended,,,, -Check Ages,,,,,TRUE,DataProperty,,,protectAges,,,, -Check Unique,,,,,TRUE,DataProperty,,,unique error,,,, -Check Range,,,,,TRUE,DataProperty,,,inRange 50 100 error,,,, -Check Date,,,,,TRUE,DataProperty,,,date,string,date,, -Check NA,,,,,TRUE,DataProperty,,,int::IsNA,,,, -MockRDB,,,"Component, MockRDB_id, SourceManifest",,FALSE,DataType,,,,,,, -MockRDB_id,,,,,TRUE,DataProperty,,,int,,,, -SourceManifest,,,,,TRUE,DataProperty,,,,,,, -MockFilename,,,"Component, Filename",,FALSE,DataType,,,,,,, -JSONSchemaComponent,Component to hold attributes for testing JSON Schemas,,"Component, No Rules, No Rules Not Required, String, String Not Required, Enum, Enum Not Required, Date, URL, InRange, Regex, List, List Not Required, List Enum, List Enum Not Required, List Boolean, List, Integer, List InRange",,FALSE,DataType,,,,,,, -No Rules,,,,,TRUE,DataProperty,,,,,,, -No Rules Not Required,,,,,FALSE,DataProperty,,,,,,, -String,,,,,TRUE,DataProperty,,,,string,,, -String Not Required,,,,,FALSE,DataProperty,,,,string,,, -Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,,string,,, -Enum Not Required,,"ab, cd, ef, gh",,,FALSE,DataProperty,,,,string,,, -Date,,,,,TRUE,DataProperty,,,date,string,date,, -URL,,,,,TRUE,DataProperty,,,url,string,uri,, -InRange,,,,,TRUE,DataProperty,,,inRange 50 100,number,,, -Regex,,,,,TRUE,DataProperty,,,regex search [a-f],string,,, -List,,,,,TRUE,DataProperty,,,,string_list,,, -List Not Required,,,,,FALSE,DataProperty,,,,string_list,,, -List Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,,string_list,,, -List Enum Not Required,,"ab, cd, ef, gh",,,FALSE,DataProperty,,,,string_list,,, -List Boolean,,,,,TRUE,DataProperty,,,,boolean_list,,, -List Integer,,,,,TRUE,DataProperty,,,,integer_list,,, -List InRange,,,,,TRUE,DataProperty,,,inRange 50 100,integer_list,,, -TypeDefinitionComponent,Component to check type specification,,"Component, String type, String type caps, Int type, Int type caps, Num type, Num type caps, Nan type, Missing type, Boolean type, Boolean type caps",,FALSE,DataType,,,,,,, -String type,,,,,TRUE,DataProperty,,,,string,,, -String type caps,,,,,TRUE,DataProperty,,,,STRING,,, -Int type,,,,,TRUE,DataProperty,,,,integer,,, -Int type caps,,,,,TRUE,DataProperty,,,,INTEGER,,, -Num type,,,,,TRUE,DataProperty,,,,number,,, -Num type caps,,,,,TRUE,DataProperty,,,,NUMBER,,, -Nan type,,,,,TRUE,DataProperty,,,,nan,,, -Missing type,,,,,TRUE,DataProperty,,,,,,, -Boolean type,,,,,TRUE,DataProperty,,,,boolean,,, -Boolean type caps,,,,,TRUE,DataProperty,,,,BOOLEAN,,, -RangeComponent,Component to ensure maximum and minimum can be set correctly,,"Component, Maximum Integer, Minimum Integer, Maximum Float, Minimum Float, Maximum Minimum, Maximum Minimum Integer List, Maximum Minimum Validation Rule",,FALSE,DataType,,,,,,, -Maximum Integer,,,,,TRUE,DataProperty,,,,integer,,100, -Minimum Integer,,,,,TRUE,DataProperty,,,,integer,,,10 -Maximum Float,,,,,TRUE,DataProperty,,,,number,,100.5, -Minimum Float,,,,,TRUE,DataProperty,,,,number,,,10.8 -Maximum Minimum,,,,,TRUE,DataProperty,,,,integer,,100,10 -Maximum Minimum Integer List,,,,,TRUE,DataProperty,,,,integer_list,,100,10 -Maximum Minimum Validation Rule,,,,,TRUE,DataProperty,,,inRange 50 100,integer,,200,10 +Attribute,Description,Valid Values,DependsOn,Properties,Required,Parent,DependsOn Component,Source,Validation Rules,columnType,Format,Maximum,Minimum,Pattern +Component,,,,,TRUE,,,,,,,,, +Patient,,,"Patient ID, Sex, Year of Birth, Diagnosis, Component",,FALSE,DataType,,,,,,,, +Patient ID,,,,,TRUE,DataProperty,,,#Patient unique warning^^#Biospecimen unique error,,,,, +Sex,,"Female, Male, Other",,,TRUE,DataProperty,,,,,,,, +Year of Birth,,,,,FALSE,DataProperty,,,,,,,, +Diagnosis,,"Healthy, Cancer",,,TRUE,DataProperty,,,,,,,, +Cancer,,,"Cancer Type, Family History",,FALSE,ValidValue,,,,,,,, +Cancer Type,,"Breast, Colorectal, Lung, Prostate, Skin",,,TRUE,DataProperty,,,,,,,, +Family History,,"Breast, Colorectal, Lung, Prostate, Skin",,,TRUE,DataProperty,,,list strict,,,,, +Biospecimen,,,"Sample ID, Patient ID, Tissue Status, Component",,FALSE,DataType,Patient,,,,,,, +Sample ID,,,,,TRUE,DataProperty,,,,,,,, +Tissue Status,,"Healthy, Malignant, None",,,TRUE,DataProperty,,,,,,,, +Bulk RNA-seq Assay,,,"Filename, Sample ID, File Format, Component",,FALSE,DataType,Biospecimen,,,,,,, +Filename,,,,,TRUE,DataProperty,,,#MockFilename filenameExists^^,,,,, +File Format,,"FASTQ, BAM, CRAM, CSV/TSV",,,TRUE,DataProperty,,,,,,,, +BAM,,,Genome Build,,FALSE,ValidValue,,,,,,,, +CRAM,,,"Genome Build, Genome FASTA",,FALSE,ValidValue,,,,,,,, +CSV/TSV,,,Genome Build,,FALSE,ValidValue,,,,,,,, +Genome Build,,"GRCh37, GRCh38, GRCm38, GRCm39",,,TRUE,DataProperty,,,,,,,, +Genome FASTA,,,,,TRUE,DataProperty,,,,,,,, +MockComponent,Component to hold mock attributes for testing all validation rules,,"Component, Check List, Check List Enum, Check List Like, Check List Like Enum, Check List Strict, Check List Enum Strict, Check Regex List, Check Regex List Like, Check Regex List Strict, Check Regex Single, Check Regex Format, Check Regex Integer, Check Num, Check Float, Check Int, Check String, Check URL,Check Match at Least, Check Match at Least values, Check Match Exactly, Check Match Exactly values, Check Match None, Check Match None values, Check Recommended, Check Ages, Check Unique, Check Range, Check Date, Check NA",,FALSE,DataType,,,,,,,, +Check List,,,,,TRUE,DataProperty,,,list,,,,, +Check List Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list,,,,, +Check List Like,,,,,TRUE,DataProperty,,,list like,,,,, +Check List Like Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list like,,,,, +Check List Strict,,,,,TRUE,DataProperty,,,list strict,,,,, +Check List Enum Strict,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list strict,,,,, +Check Regex List,,,,,TRUE,DataProperty,,,list::regex match [a-f],,,,, +Check Regex List Strict,,,,,TRUE,DataProperty,,,list strict::regex match [a-f],,,,, +Check Regex List Like,,,,,TRUE,DataProperty,,,list like::regex match [a-f],,,,, +Check Regex Single,,,,,TRUE,DataProperty,,,,string,,,,[a-b] +Check Regex Format,,,,,TRUE,DataProperty,,,regex match [a-f],string,,,,^[a-b] +Check Regex Integer,,,,,TRUE,DataProperty,,,regex search ^\d+$,,,,, +Check Num,,,,,TRUE,DataProperty,,,num error,,,,, +Check Float,,,,,TRUE,DataProperty,,,float error,number,,,, +Check Int,,,,,TRUE,DataProperty,,,int error,,,,, +Check String,,,,,TRUE,DataProperty,,,str error,,,,, +Check URL,,,,,TRUE,DataProperty,,,url,string,uri,,, +Check Match at Least,,,,,TRUE,DataProperty,,,matchAtLeastOne Patient.PatientID set,,,,, +Check Match Exactly,,,,,TRUE,DataProperty,,,matchExactlyOne MockComponent.checkMatchExactly set,,,,, +Check Match None,,,,,TRUE,DataProperty,,,matchNone MockComponent.checkMatchNone set error,,,,, +Check Match at Least values,,,,,TRUE,DataProperty,,,matchAtLeastOne MockComponent.checkMatchatLeastvalues value,,,,, +Check Match Exactly values,,,,,TRUE,DataProperty,,,matchExactlyOne MockComponent.checkMatchExactlyvalues value,,,,, +Check Match None values,,,,,TRUE,DataProperty,,,matchNone MockComponent.checkMatchNonevalues value error,,,,, +Check Recommended,,,,,FALSE,DataProperty,,,recommended,,,,, +Check Ages,,,,,TRUE,DataProperty,,,protectAges,,,,, +Check Unique,,,,,TRUE,DataProperty,,,unique error,,,,, +Check Range,,,,,TRUE,DataProperty,,,inRange 50 100 error,,,,, +Check Date,,,,,TRUE,DataProperty,,,date,string,date,,, +Check NA,,,,,TRUE,DataProperty,,,int::IsNA,,,,, +MockRDB,,,"Component, MockRDB_id, SourceManifest",,FALSE,DataType,,,,,,,, +MockRDB_id,,,,,TRUE,DataProperty,,,int,,,,, +SourceManifest,,,,,TRUE,DataProperty,,,,,,,, +MockFilename,,,"Component, Filename",,FALSE,DataType,,,,,,,, +JSONSchemaComponent,Component to hold attributes for testing JSON Schemas,,"Component, No Rules, No Rules Not Required, String, String Not Required, Enum, Enum Not Required, Date, URL, InRange, Regex, List, List Not Required, List Enum, List Enum Not Required, List Boolean, List, Integer, List InRange",,FALSE,DataType,,,,,,,, +No Rules,,,,,TRUE,DataProperty,,,,,,,, +No Rules Not Required,,,,,FALSE,DataProperty,,,,,,,, +String,,,,,TRUE,DataProperty,,,,string,,,, +String Not Required,,,,,FALSE,DataProperty,,,,string,,,, +Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,,string,,,, +Enum Not Required,,"ab, cd, ef, gh",,,FALSE,DataProperty,,,,string,,,, +Date,,,,,TRUE,DataProperty,,,date,string,date,,, +URL,,,,,TRUE,DataProperty,,,url,string,uri,,, +InRange,,,,,TRUE,DataProperty,,,inRange 50 100,number,,,, +Regex,,,,,TRUE,DataProperty,,,regex search [a-f],string,,,, +List,,,,,TRUE,DataProperty,,,,string_list,,,, +List Not Required,,,,,FALSE,DataProperty,,,,string_list,,,, +List Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,,string_list,,,, +List Enum Not Required,,"ab, cd, ef, gh",,,FALSE,DataProperty,,,,string_list,,,, +List Boolean,,,,,TRUE,DataProperty,,,,boolean_list,,,, +List Integer,,,,,TRUE,DataProperty,,,,integer_list,,,, +List InRange,,,,,TRUE,DataProperty,,,inRange 50 100,integer_list,,,, +TypeDefinitionComponent,Component to check type specification,,"Component, String type, String type caps, Int type, Int type caps, Num type, Num type caps, Nan type, Missing type, Boolean type, Boolean type caps",,FALSE,DataType,,,,,,,, +String type,,,,,TRUE,DataProperty,,,,string,,,, +String type caps,,,,,TRUE,DataProperty,,,,STRING,,,, +Int type,,,,,TRUE,DataProperty,,,,integer,,,, +Int type caps,,,,,TRUE,DataProperty,,,,INTEGER,,,, +Num type,,,,,TRUE,DataProperty,,,,number,,,, +Num type caps,,,,,TRUE,DataProperty,,,,NUMBER,,,, +Nan type,,,,,TRUE,DataProperty,,,,nan,,,, +Missing type,,,,,TRUE,DataProperty,,,,,,,, +Boolean type,,,,,TRUE,DataProperty,,,,boolean,,,, +Boolean type caps,,,,,TRUE,DataProperty,,,,BOOLEAN,,,, +RangeComponent,Component to ensure maximum and minimum can be set correctly,,"Component, Maximum Integer, Minimum Integer, Maximum Float, Minimum Float, Maximum Minimum, Maximum Minimum Integer List, Maximum Minimum Validation Rule",,FALSE,DataType,,,,,,,, +Maximum Integer,,,,,TRUE,DataProperty,,,,integer,,100,, +Minimum Integer,,,,,TRUE,DataProperty,,,,integer,,,10, +Maximum Float,,,,,TRUE,DataProperty,,,,number,,100.5,, +Minimum Float,,,,,TRUE,DataProperty,,,,number,,,10.8, +Maximum Minimum,,,,,TRUE,DataProperty,,,,integer,,100,10, +Maximum Minimum Integer List,,,,,TRUE,DataProperty,,,,integer_list,,100,10, +Maximum Minimum Validation Rule,,,,,TRUE,DataProperty,,,inRange 50 100,integer,,200,10, diff --git a/tests/unit/synapseclient/extensions/schema_files/data_models/example.model_no_pattern_column.csv b/tests/unit/synapseclient/extensions/schema_files/data_models/example.model_no_pattern_column.csv new file mode 100644 index 000000000..b1387d1a5 --- /dev/null +++ b/tests/unit/synapseclient/extensions/schema_files/data_models/example.model_no_pattern_column.csv @@ -0,0 +1,92 @@ +Attribute,Description,Valid Values,DependsOn,Properties,Required,Parent,DependsOn Component,Source,Validation Rules,columnType,Format,Maximum,Minimum +Component,,,,,TRUE,,,,,,,, +Patient,,,"Patient ID, Sex, Year of Birth, Diagnosis, Component",,FALSE,DataType,,,,,,, +Patient ID,,,,,TRUE,DataProperty,,,#Patient unique warning^^#Biospecimen unique error,,,, +Sex,,"Female, Male, Other",,,TRUE,DataProperty,,,,,,, +Year of Birth,,,,,FALSE,DataProperty,,,,,,, +Diagnosis,,"Healthy, Cancer",,,TRUE,DataProperty,,,,,,, +Cancer,,,"Cancer Type, Family History",,FALSE,ValidValue,,,,,,, +Cancer Type,,"Breast, Colorectal, Lung, Prostate, Skin",,,TRUE,DataProperty,,,,,,, +Family History,,"Breast, Colorectal, Lung, Prostate, Skin",,,TRUE,DataProperty,,,list strict,,,, +Biospecimen,,,"Sample ID, Patient ID, Tissue Status, Component",,FALSE,DataType,Patient,,,,,, +Sample ID,,,,,TRUE,DataProperty,,,,,,, +Tissue Status,,"Healthy, Malignant, None",,,TRUE,DataProperty,,,,,,, +Bulk RNA-seq Assay,,,"Filename, Sample ID, File Format, Component",,FALSE,DataType,Biospecimen,,,,,, +Filename,,,,,TRUE,DataProperty,,,#MockFilename filenameExists^^,,,, +File Format,,"FASTQ, BAM, CRAM, CSV/TSV",,,TRUE,DataProperty,,,,,,, +BAM,,,Genome Build,,FALSE,ValidValue,,,,,,, +CRAM,,,"Genome Build, Genome FASTA",,FALSE,ValidValue,,,,,,, +CSV/TSV,,,Genome Build,,FALSE,ValidValue,,,,,,, +Genome Build,,"GRCh37, GRCh38, GRCm38, GRCm39",,,TRUE,DataProperty,,,,,,, +Genome FASTA,,,,,TRUE,DataProperty,,,,,,, +MockComponent,Component to hold mock attributes for testing all validation rules,,"Component, Check List, Check List Enum, Check List Like, Check List Like Enum, Check List Strict, Check List Enum Strict, Check Regex List, Check Regex List Like, Check Regex List Strict, Check Regex Single, Check Regex Format, Check Regex Integer, Check Num, Check Float, Check Int, Check String, Check URL,Check Match at Least, Check Match at Least values, Check Match Exactly, Check Match Exactly values, Check Match None, Check Match None values, Check Recommended, Check Ages, Check Unique, Check Range, Check Date, Check NA",,FALSE,DataType,,,,,,, +Check List,,,,,TRUE,DataProperty,,,list,,,, +Check List Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list,,,, +Check List Like,,,,,TRUE,DataProperty,,,list like,,,, +Check List Like Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list like,,,, +Check List Strict,,,,,TRUE,DataProperty,,,list strict,,,, +Check List Enum Strict,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,list strict,,,, +Check Regex List,,,,,TRUE,DataProperty,,,list::regex match [a-f],,,, +Check Regex List Strict,,,,,TRUE,DataProperty,,,list strict::regex match [a-f],,,, +Check Regex List Like,,,,,TRUE,DataProperty,,,list like::regex match [a-f],,,, +Check Regex Single,,,,,TRUE,DataProperty,,,,string,,, +Check Regex Format,,,,,TRUE,DataProperty,,,regex match [a-f],string,,, +Check Regex Integer,,,,,TRUE,DataProperty,,,regex search ^\d+$,,,, +Check Num,,,,,TRUE,DataProperty,,,num error,,,, +Check Float,,,,,TRUE,DataProperty,,,float error,number,,, +Check Int,,,,,TRUE,DataProperty,,,int error,,,, +Check String,,,,,TRUE,DataProperty,,,str error,,,, +Check URL,,,,,TRUE,DataProperty,,,url,string,uri,, +Check Match at Least,,,,,TRUE,DataProperty,,,matchAtLeastOne Patient.PatientID set,,,, +Check Match Exactly,,,,,TRUE,DataProperty,,,matchExactlyOne MockComponent.checkMatchExactly set,,,, +Check Match None,,,,,TRUE,DataProperty,,,matchNone MockComponent.checkMatchNone set error,,,, +Check Match at Least values,,,,,TRUE,DataProperty,,,matchAtLeastOne MockComponent.checkMatchatLeastvalues value,,,, +Check Match Exactly values,,,,,TRUE,DataProperty,,,matchExactlyOne MockComponent.checkMatchExactlyvalues value,,,, +Check Match None values,,,,,TRUE,DataProperty,,,matchNone MockComponent.checkMatchNonevalues value error,,,, +Check Recommended,,,,,FALSE,DataProperty,,,recommended,,,, +Check Ages,,,,,TRUE,DataProperty,,,protectAges,,,, +Check Unique,,,,,TRUE,DataProperty,,,unique error,,,, +Check Range,,,,,TRUE,DataProperty,,,inRange 50 100 error,,,, +Check Date,,,,,TRUE,DataProperty,,,date,string,date,, +Check NA,,,,,TRUE,DataProperty,,,int::IsNA,,,, +MockRDB,,,"Component, MockRDB_id, SourceManifest",,FALSE,DataType,,,,,,, +MockRDB_id,,,,,TRUE,DataProperty,,,int,,,, +SourceManifest,,,,,TRUE,DataProperty,,,,,,, +MockFilename,,,"Component, Filename",,FALSE,DataType,,,,,,, +JSONSchemaComponent,Component to hold attributes for testing JSON Schemas,,"Component, No Rules, No Rules Not Required, String, String Not Required, Enum, Enum Not Required, Date, URL, InRange, Regex, List, List Not Required, List Enum, List Enum Not Required, List Boolean, List, Integer, List InRange",,FALSE,DataType,,,,,,, +No Rules,,,,,TRUE,DataProperty,,,,,,, +No Rules Not Required,,,,,FALSE,DataProperty,,,,,,, +String,,,,,TRUE,DataProperty,,,,string,,, +String Not Required,,,,,FALSE,DataProperty,,,,string,,, +Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,,string,,, +Enum Not Required,,"ab, cd, ef, gh",,,FALSE,DataProperty,,,,string,,, +Date,,,,,TRUE,DataProperty,,,date,string,date,, +URL,,,,,TRUE,DataProperty,,,url,string,uri,, +InRange,,,,,TRUE,DataProperty,,,inRange 50 100,number,,, +Regex,,,,,TRUE,DataProperty,,,regex search [a-f],string,,, +List,,,,,TRUE,DataProperty,,,,string_list,,, +List Not Required,,,,,FALSE,DataProperty,,,,string_list,,, +List Enum,,"ab, cd, ef, gh",,,TRUE,DataProperty,,,,string_list,,, +List Enum Not Required,,"ab, cd, ef, gh",,,FALSE,DataProperty,,,,string_list,,, +List Boolean,,,,,TRUE,DataProperty,,,,boolean_list,,, +List Integer,,,,,TRUE,DataProperty,,,,integer_list,,, +List InRange,,,,,TRUE,DataProperty,,,inRange 50 100,integer_list,,, +TypeDefinitionComponent,Component to check type specification,,"Component, String type, String type caps, Int type, Int type caps, Num type, Num type caps, Nan type, Missing type, Boolean type, Boolean type caps",,FALSE,DataType,,,,,,, +String type,,,,,TRUE,DataProperty,,,,string,,, +String type caps,,,,,TRUE,DataProperty,,,,STRING,,, +Int type,,,,,TRUE,DataProperty,,,,integer,,, +Int type caps,,,,,TRUE,DataProperty,,,,INTEGER,,, +Num type,,,,,TRUE,DataProperty,,,,number,,, +Num type caps,,,,,TRUE,DataProperty,,,,NUMBER,,, +Nan type,,,,,TRUE,DataProperty,,,,nan,,, +Missing type,,,,,TRUE,DataProperty,,,,,,, +Boolean type,,,,,TRUE,DataProperty,,,,boolean,,, +Boolean type caps,,,,,TRUE,DataProperty,,,,BOOLEAN,,, +RangeComponent,Component to ensure maximum and minimum can be set correctly,,"Component, Maximum Integer, Minimum Integer, Maximum Float, Minimum Float, Maximum Minimum, Maximum Minimum Integer List, Maximum Minimum Validation Rule",,FALSE,DataType,,,,,,, +Maximum Integer,,,,,TRUE,DataProperty,,,,integer,,100, +Minimum Integer,,,,,TRUE,DataProperty,,,,integer,,,10 +Maximum Float,,,,,TRUE,DataProperty,,,,number,,100.5, +Minimum Float,,,,,TRUE,DataProperty,,,,number,,,10.8 +Maximum Minimum,,,,,TRUE,DataProperty,,,,integer,,100,10 +Maximum Minimum Integer List,,,,,TRUE,DataProperty,,,,integer_list,,100,10 +Maximum Minimum Validation Rule,,,,,TRUE,DataProperty,,,inRange 50 100,integer,,200,10 diff --git a/tests/unit/synapseclient/extensions/schema_files/data_models_jsonld/example.model.jsonld b/tests/unit/synapseclient/extensions/schema_files/data_models_jsonld/example.model.jsonld index 94972828b..bd6ae21e1 100644 --- a/tests/unit/synapseclient/extensions/schema_files/data_models_jsonld/example.model.jsonld +++ b/tests/unit/synapseclient/extensions/schema_files/data_models_jsonld/example.model.jsonld @@ -1218,11 +1218,11 @@ "schema:isPartOf": { "@id": "http://schema.biothings.io" }, + "sms:columnType": "string", "sms:displayName": "Check Regex Single", + "sms:pattern": "[a-b]", "sms:required": "sms:true", - "sms:validationRules": [ - "regex search [a-f]" - ] + "sms:validationRules": [] }, { "@id": "bts:CheckRegexFormat", @@ -1237,7 +1237,9 @@ "schema:isPartOf": { "@id": "http://schema.biothings.io" }, + "sms:columnType": "string", "sms:displayName": "Check Regex Format", + "sms:pattern": "^[a-b]", "sms:required": "sms:true", "sms:validationRules": [ "regex match [a-f]" diff --git a/tests/unit/synapseclient/extensions/schema_files/data_models_jsonld/example.model_no_pattern_column.jsonld b/tests/unit/synapseclient/extensions/schema_files/data_models_jsonld/example.model_no_pattern_column.jsonld new file mode 100644 index 000000000..018fa1fcd --- /dev/null +++ b/tests/unit/synapseclient/extensions/schema_files/data_models_jsonld/example.model_no_pattern_column.jsonld @@ -0,0 +1,2698 @@ +{ + "@context": { + "bts": "http://schema.biothings.io/", + "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", + "rdfs": "http://www.w3.org/2000/01/rdf-schema#", + "schema": "http://schema.org/", + "xsd": "http://www.w3.org/2001/XMLSchema#" + }, + "@graph": [ + { + "@id": "bts:Component", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Component", + "rdfs:subClassOf": [ + { + "@id": "bts:Thing" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Component", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Patient", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Patient", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Patient", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:PatientID" + }, + { + "@id": "bts:Sex" + }, + { + "@id": "bts:YearofBirth" + }, + { + "@id": "bts:Diagnosis" + }, + { + "@id": "bts:Component" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:PatientID", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "PatientID", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Patient ID", + "sms:required": "sms:true", + "sms:validationRules": { + "Biospecimen": "unique error", + "Patient": "unique warning" + } + }, + { + "@id": "bts:Sex", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Sex", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Female" + }, + { + "@id": "bts:Male" + }, + { + "@id": "bts:Other" + } + ], + "sms:displayName": "Sex", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:YearofBirth", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "YearofBirth", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Year of Birth", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Diagnosis", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Diagnosis", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Healthy" + }, + { + "@id": "bts:Cancer" + } + ], + "sms:displayName": "Diagnosis", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:DataType", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "DataType", + "rdfs:subClassOf": [ + { + "@id": "bts:Thing" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "DataType", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:DataProperty", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "DataProperty", + "rdfs:subClassOf": [ + { + "@id": "bts:Thing" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "DataProperty", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Female", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Female", + "rdfs:subClassOf": [ + { + "@id": "bts:Sex" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Female", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Male", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Male", + "rdfs:subClassOf": [ + { + "@id": "bts:Sex" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Male", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Other", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Other", + "rdfs:subClassOf": [ + { + "@id": "bts:Sex" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Other", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Healthy", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Healthy", + "rdfs:subClassOf": [ + { + "@id": "bts:Diagnosis" + }, + { + "@id": "bts:TissueStatus" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Healthy", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Cancer", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Cancer", + "rdfs:subClassOf": [ + { + "@id": "bts:ValidValue" + }, + { + "@id": "bts:Diagnosis" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Cancer", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:CancerType" + }, + { + "@id": "bts:FamilyHistory" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:CancerType", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CancerType", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Breast" + }, + { + "@id": "bts:Colorectal" + }, + { + "@id": "bts:Lung" + }, + { + "@id": "bts:Prostate" + }, + { + "@id": "bts:Skin" + } + ], + "sms:displayName": "Cancer Type", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:FamilyHistory", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "FamilyHistory", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Breast" + }, + { + "@id": "bts:Colorectal" + }, + { + "@id": "bts:Lung" + }, + { + "@id": "bts:Prostate" + }, + { + "@id": "bts:Skin" + } + ], + "sms:displayName": "Family History", + "sms:required": "sms:true", + "sms:validationRules": [ + "list strict" + ] + }, + { + "@id": "bts:ValidValue", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "ValidValue", + "rdfs:subClassOf": [ + { + "@id": "bts:Thing" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "ValidValue", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Breast", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Breast", + "rdfs:subClassOf": [ + { + "@id": "bts:CancerType" + }, + { + "@id": "bts:FamilyHistory" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Breast", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Colorectal", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Colorectal", + "rdfs:subClassOf": [ + { + "@id": "bts:CancerType" + }, + { + "@id": "bts:FamilyHistory" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Colorectal", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Lung", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Lung", + "rdfs:subClassOf": [ + { + "@id": "bts:CancerType" + }, + { + "@id": "bts:FamilyHistory" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Lung", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Prostate", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Prostate", + "rdfs:subClassOf": [ + { + "@id": "bts:CancerType" + }, + { + "@id": "bts:FamilyHistory" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Prostate", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Skin", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Skin", + "rdfs:subClassOf": [ + { + "@id": "bts:CancerType" + }, + { + "@id": "bts:FamilyHistory" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Skin", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Biospecimen", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Biospecimen", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Biospecimen", + "sms:required": "sms:false", + "sms:requiresComponent": [ + { + "@id": "bts:Patient" + } + ], + "sms:requiresDependency": [ + { + "@id": "bts:SampleID" + }, + { + "@id": "bts:PatientID" + }, + { + "@id": "bts:TissueStatus" + }, + { + "@id": "bts:Component" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:SampleID", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "SampleID", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Sample ID", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:TissueStatus", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "TissueStatus", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Healthy" + }, + { + "@id": "bts:Malignant" + }, + { + "@id": "bts:None" + } + ], + "sms:displayName": "Tissue Status", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Malignant", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Malignant", + "rdfs:subClassOf": [ + { + "@id": "bts:TissueStatus" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Malignant", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:None", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "None", + "rdfs:subClassOf": [ + { + "@id": "bts:TissueStatus" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "None", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:BulkRNA-seqAssay", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "BulkRNA-seqAssay", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Bulk RNA-seq Assay", + "sms:required": "sms:false", + "sms:requiresComponent": [ + { + "@id": "bts:Biospecimen" + } + ], + "sms:requiresDependency": [ + { + "@id": "bts:Filename" + }, + { + "@id": "bts:SampleID" + }, + { + "@id": "bts:FileFormat" + }, + { + "@id": "bts:Component" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:Filename", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Filename", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Filename", + "sms:required": "sms:true", + "sms:validationRules": { + "MockFilename": "filenameExists" + } + }, + { + "@id": "bts:FileFormat", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "FileFormat", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:FASTQ" + }, + { + "@id": "bts:BAM" + }, + { + "@id": "bts:CRAM" + }, + { + "@id": "bts:CSV/TSV" + } + ], + "sms:displayName": "File Format", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:FASTQ", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "FASTQ", + "rdfs:subClassOf": [ + { + "@id": "bts:FileFormat" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "FASTQ", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:BAM", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "BAM", + "rdfs:subClassOf": [ + { + "@id": "bts:ValidValue" + }, + { + "@id": "bts:FileFormat" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "BAM", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:GenomeBuild" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:CRAM", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CRAM", + "rdfs:subClassOf": [ + { + "@id": "bts:ValidValue" + }, + { + "@id": "bts:FileFormat" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "CRAM", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:GenomeBuild" + }, + { + "@id": "bts:GenomeFASTA" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:CSV/TSV", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CSV/TSV", + "rdfs:subClassOf": [ + { + "@id": "bts:ValidValue" + }, + { + "@id": "bts:FileFormat" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "CSV/TSV", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:GenomeBuild" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:GenomeBuild", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "GenomeBuild", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:GRCh37" + }, + { + "@id": "bts:GRCh38" + }, + { + "@id": "bts:GRCm38" + }, + { + "@id": "bts:GRCm39" + } + ], + "sms:displayName": "Genome Build", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:GenomeFASTA", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "GenomeFASTA", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Genome FASTA", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:GRCh37", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "GRCh37", + "rdfs:subClassOf": [ + { + "@id": "bts:GenomeBuild" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "GRCh37", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:GRCh38", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "GRCh38", + "rdfs:subClassOf": [ + { + "@id": "bts:GenomeBuild" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "GRCh38", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:GRCm38", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "GRCm38", + "rdfs:subClassOf": [ + { + "@id": "bts:GenomeBuild" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "GRCm38", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:GRCm39", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "GRCm39", + "rdfs:subClassOf": [ + { + "@id": "bts:GenomeBuild" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "GRCm39", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:MockComponent", + "@type": "rdfs:Class", + "rdfs:comment": "Component to hold mock attributes for testing all validation rules", + "rdfs:label": "MockComponent", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "MockComponent", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:Component" + }, + { + "@id": "bts:CheckList" + }, + { + "@id": "bts:CheckListEnum" + }, + { + "@id": "bts:CheckListLike" + }, + { + "@id": "bts:CheckListLikeEnum" + }, + { + "@id": "bts:CheckListStrict" + }, + { + "@id": "bts:CheckListEnumStrict" + }, + { + "@id": "bts:CheckRegexList" + }, + { + "@id": "bts:CheckRegexListLike" + }, + { + "@id": "bts:CheckRegexListStrict" + }, + { + "@id": "bts:CheckRegexSingle" + }, + { + "@id": "bts:CheckRegexFormat" + }, + { + "@id": "bts:CheckRegexInteger" + }, + { + "@id": "bts:CheckNum" + }, + { + "@id": "bts:CheckFloat" + }, + { + "@id": "bts:CheckInt" + }, + { + "@id": "bts:CheckString" + }, + { + "@id": "bts:CheckURL" + }, + { + "@id": "bts:CheckMatchatLeast" + }, + { + "@id": "bts:CheckMatchatLeastvalues" + }, + { + "@id": "bts:CheckMatchExactly" + }, + { + "@id": "bts:CheckMatchExactlyvalues" + }, + { + "@id": "bts:CheckMatchNone" + }, + { + "@id": "bts:CheckMatchNonevalues" + }, + { + "@id": "bts:CheckRecommended" + }, + { + "@id": "bts:CheckAges" + }, + { + "@id": "bts:CheckUnique" + }, + { + "@id": "bts:CheckRange" + }, + { + "@id": "bts:CheckDate" + }, + { + "@id": "bts:CheckNA" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:CheckList", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckList", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check List", + "sms:required": "sms:true", + "sms:validationRules": [ + "list" + ] + }, + { + "@id": "bts:CheckListEnum", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckListEnum", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Ab" + }, + { + "@id": "bts:Cd" + }, + { + "@id": "bts:Ef" + }, + { + "@id": "bts:Gh" + } + ], + "sms:displayName": "Check List Enum", + "sms:required": "sms:true", + "sms:validationRules": [ + "list" + ] + }, + { + "@id": "bts:CheckListLike", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckListLike", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check List Like", + "sms:required": "sms:true", + "sms:validationRules": [ + "list like" + ] + }, + { + "@id": "bts:CheckListLikeEnum", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckListLikeEnum", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Ab" + }, + { + "@id": "bts:Cd" + }, + { + "@id": "bts:Ef" + }, + { + "@id": "bts:Gh" + } + ], + "sms:displayName": "Check List Like Enum", + "sms:required": "sms:true", + "sms:validationRules": [ + "list like" + ] + }, + { + "@id": "bts:CheckListStrict", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckListStrict", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check List Strict", + "sms:required": "sms:true", + "sms:validationRules": [ + "list strict" + ] + }, + { + "@id": "bts:CheckListEnumStrict", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckListEnumStrict", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Ab" + }, + { + "@id": "bts:Cd" + }, + { + "@id": "bts:Ef" + }, + { + "@id": "bts:Gh" + } + ], + "sms:displayName": "Check List Enum Strict", + "sms:required": "sms:true", + "sms:validationRules": [ + "list strict" + ] + }, + { + "@id": "bts:CheckRegexList", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRegexList", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Regex List", + "sms:required": "sms:true", + "sms:validationRules": [ + "list", + "regex match [a-f]" + ] + }, + { + "@id": "bts:CheckRegexListLike", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRegexListLike", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Regex List Like", + "sms:required": "sms:true", + "sms:validationRules": [ + "list like", + "regex match [a-f]" + ] + }, + { + "@id": "bts:CheckRegexListStrict", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRegexListStrict", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Regex List Strict", + "sms:required": "sms:true", + "sms:validationRules": [ + "list strict", + "regex match [a-f]" + ] + }, + { + "@id": "bts:CheckRegexSingle", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRegexSingle", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "Check Regex Single", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:CheckRegexFormat", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRegexFormat", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "Check Regex Format", + "sms:required": "sms:true", + "sms:validationRules": [ + "regex match [a-f]" + ] + }, + { + "@id": "bts:CheckRegexInteger", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRegexInteger", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Regex Integer", + "sms:required": "sms:true", + "sms:validationRules": [ + "regex search ^\\d+$" + ] + }, + { + "@id": "bts:CheckNum", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckNum", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Num", + "sms:required": "sms:true", + "sms:validationRules": [ + "num error" + ] + }, + { + "@id": "bts:CheckFloat", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckFloat", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "number", + "sms:displayName": "Check Float", + "sms:required": "sms:true", + "sms:validationRules": [ + "float error" + ] + }, + { + "@id": "bts:CheckInt", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckInt", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Int", + "sms:required": "sms:true", + "sms:validationRules": [ + "int error" + ] + }, + { + "@id": "bts:CheckString", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckString", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check String", + "sms:required": "sms:true", + "sms:validationRules": [ + "str error" + ] + }, + { + "@id": "bts:CheckURL", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckURL", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "Check URL", + "sms:format": "uri", + "sms:required": "sms:true", + "sms:validationRules": [ + "url" + ] + }, + { + "@id": "bts:CheckMatchatLeast", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckMatchatLeast", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Match at Least", + "sms:required": "sms:true", + "sms:validationRules": [ + "matchAtLeastOne Patient.PatientID set" + ] + }, + { + "@id": "bts:CheckMatchatLeastvalues", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckMatchatLeastvalues", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Match at Least values", + "sms:required": "sms:true", + "sms:validationRules": [ + "matchAtLeastOne MockComponent.checkMatchatLeastvalues value" + ] + }, + { + "@id": "bts:CheckMatchExactly", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckMatchExactly", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Match Exactly", + "sms:required": "sms:true", + "sms:validationRules": [ + "matchExactlyOne MockComponent.checkMatchExactly set" + ] + }, + { + "@id": "bts:CheckMatchExactlyvalues", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckMatchExactlyvalues", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Match Exactly values", + "sms:required": "sms:true", + "sms:validationRules": [ + "matchExactlyOne MockComponent.checkMatchExactlyvalues value" + ] + }, + { + "@id": "bts:CheckMatchNone", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckMatchNone", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Match None", + "sms:required": "sms:true", + "sms:validationRules": [ + "matchNone MockComponent.checkMatchNone set error" + ] + }, + { + "@id": "bts:CheckMatchNonevalues", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckMatchNonevalues", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Match None values", + "sms:required": "sms:true", + "sms:validationRules": [ + "matchNone MockComponent.checkMatchNonevalues value error" + ] + }, + { + "@id": "bts:CheckRecommended", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRecommended", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Recommended", + "sms:required": "sms:false", + "sms:validationRules": [ + "recommended" + ] + }, + { + "@id": "bts:CheckAges", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckAges", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Ages", + "sms:required": "sms:true", + "sms:validationRules": [ + "protectAges" + ] + }, + { + "@id": "bts:CheckUnique", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckUnique", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Unique", + "sms:required": "sms:true", + "sms:validationRules": [ + "unique error" + ] + }, + { + "@id": "bts:CheckRange", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckRange", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check Range", + "sms:required": "sms:true", + "sms:validationRules": [ + "inRange 50 100 error" + ] + }, + { + "@id": "bts:CheckDate", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckDate", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "Check Date", + "sms:format": "date", + "sms:required": "sms:true", + "sms:validationRules": [ + "date" + ] + }, + { + "@id": "bts:CheckNA", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "CheckNA", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Check NA", + "sms:required": "sms:true", + "sms:validationRules": [ + "int", + "IsNA" + ] + }, + { + "@id": "bts:Ab", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Ab", + "rdfs:subClassOf": [ + { + "@id": "bts:CheckListEnum" + }, + { + "@id": "bts:CheckListLikeEnum" + }, + { + "@id": "bts:CheckListEnumStrict" + }, + { + "@id": "bts:Enum" + }, + { + "@id": "bts:EnumNotRequired" + }, + { + "@id": "bts:ListEnum" + }, + { + "@id": "bts:ListEnumNotRequired" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "ab", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Cd", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Cd", + "rdfs:subClassOf": [ + { + "@id": "bts:CheckListEnum" + }, + { + "@id": "bts:CheckListLikeEnum" + }, + { + "@id": "bts:CheckListEnumStrict" + }, + { + "@id": "bts:Enum" + }, + { + "@id": "bts:EnumNotRequired" + }, + { + "@id": "bts:ListEnum" + }, + { + "@id": "bts:ListEnumNotRequired" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "cd", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Ef", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Ef", + "rdfs:subClassOf": [ + { + "@id": "bts:CheckListEnum" + }, + { + "@id": "bts:CheckListLikeEnum" + }, + { + "@id": "bts:CheckListEnumStrict" + }, + { + "@id": "bts:Enum" + }, + { + "@id": "bts:EnumNotRequired" + }, + { + "@id": "bts:ListEnum" + }, + { + "@id": "bts:ListEnumNotRequired" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "ef", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Gh", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Gh", + "rdfs:subClassOf": [ + { + "@id": "bts:CheckListEnum" + }, + { + "@id": "bts:CheckListLikeEnum" + }, + { + "@id": "bts:CheckListEnumStrict" + }, + { + "@id": "bts:Enum" + }, + { + "@id": "bts:EnumNotRequired" + }, + { + "@id": "bts:ListEnum" + }, + { + "@id": "bts:ListEnumNotRequired" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "gh", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:MockRDB", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MockRDB", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "MockRDB", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:Component" + }, + { + "@id": "bts:MockRDBId" + }, + { + "@id": "bts:SourceManifest" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:MockRDBId", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MockRDBId", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "MockRDB_id", + "sms:required": "sms:true", + "sms:validationRules": [ + "int" + ] + }, + { + "@id": "bts:SourceManifest", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "SourceManifest", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "SourceManifest", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:MockFilename", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MockFilename", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "MockFilename", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:Component" + }, + { + "@id": "bts:Filename" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:JSONSchemaComponent", + "@type": "rdfs:Class", + "rdfs:comment": "Component to hold attributes for testing JSON Schemas", + "rdfs:label": "JSONSchemaComponent", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "JSONSchemaComponent", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:Component" + }, + { + "@id": "bts:NoRules" + }, + { + "@id": "bts:NoRulesNotRequired" + }, + { + "@id": "bts:String" + }, + { + "@id": "bts:StringNotRequired" + }, + { + "@id": "bts:Enum" + }, + { + "@id": "bts:EnumNotRequired" + }, + { + "@id": "bts:Date" + }, + { + "@id": "bts:URL" + }, + { + "@id": "bts:InRange" + }, + { + "@id": "bts:Regex" + }, + { + "@id": "bts:List" + }, + { + "@id": "bts:ListNotRequired" + }, + { + "@id": "bts:ListEnum" + }, + { + "@id": "bts:ListEnumNotRequired" + }, + { + "@id": "bts:ListBoolean" + }, + { + "@id": "bts:Integer" + }, + { + "@id": "bts:ListInRange" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:NoRules", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "NoRules", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "No Rules", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:NoRulesNotRequired", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "NoRulesNotRequired", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "No Rules Not Required", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:String", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "String", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "String", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:StringNotRequired", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "StringNotRequired", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "String Not Required", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Enum", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Enum", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Ab" + }, + { + "@id": "bts:Cd" + }, + { + "@id": "bts:Ef" + }, + { + "@id": "bts:Gh" + } + ], + "sms:columnType": "string", + "sms:displayName": "Enum", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:EnumNotRequired", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "EnumNotRequired", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Ab" + }, + { + "@id": "bts:Cd" + }, + { + "@id": "bts:Ef" + }, + { + "@id": "bts:Gh" + } + ], + "sms:columnType": "string", + "sms:displayName": "Enum Not Required", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:Date", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Date", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "Date", + "sms:format": "date", + "sms:required": "sms:true", + "sms:validationRules": [ + "date" + ] + }, + { + "@id": "bts:URL", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "URL", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "URL", + "sms:format": "uri", + "sms:required": "sms:true", + "sms:validationRules": [ + "url" + ] + }, + { + "@id": "bts:InRange", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "InRange", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "number", + "sms:displayName": "InRange", + "sms:required": "sms:true", + "sms:validationRules": [ + "inRange 50 100" + ] + }, + { + "@id": "bts:Regex", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Regex", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "Regex", + "sms:required": "sms:true", + "sms:validationRules": [ + "regex search [a-f]" + ] + }, + { + "@id": "bts:List", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "List", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string_list", + "sms:displayName": "List", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:ListNotRequired", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "ListNotRequired", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string_list", + "sms:displayName": "List Not Required", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:ListEnum", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "ListEnum", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Ab" + }, + { + "@id": "bts:Cd" + }, + { + "@id": "bts:Ef" + }, + { + "@id": "bts:Gh" + } + ], + "sms:columnType": "string_list", + "sms:displayName": "List Enum", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:ListEnumNotRequired", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "ListEnumNotRequired", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "schema:rangeIncludes": [ + { + "@id": "bts:Ab" + }, + { + "@id": "bts:Cd" + }, + { + "@id": "bts:Ef" + }, + { + "@id": "bts:Gh" + } + ], + "sms:columnType": "string_list", + "sms:displayName": "List Enum Not Required", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:ListBoolean", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "ListBoolean", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "boolean_list", + "sms:displayName": "List Boolean", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Integer", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Integer", + "rdfs:subClassOf": [ + { + "@id": "bts:Thing" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Integer", + "sms:required": "sms:false", + "sms:validationRules": [] + }, + { + "@id": "bts:ListInRange", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "ListInRange", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer_list", + "sms:displayName": "List InRange", + "sms:required": "sms:true", + "sms:validationRules": [ + "inRange 50 100" + ] + }, + { + "@id": "bts:ListInteger", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "ListInteger", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer_list", + "sms:displayName": "List Integer", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:TypeDefinitionComponent", + "@type": "rdfs:Class", + "rdfs:comment": "Component to check type specification", + "rdfs:label": "TypeDefinitionComponent", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "TypeDefinitionComponent", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:Component" + }, + { + "@id": "bts:Stringtype" + }, + { + "@id": "bts:Stringtypecaps" + }, + { + "@id": "bts:Inttype" + }, + { + "@id": "bts:Inttypecaps" + }, + { + "@id": "bts:Numtype" + }, + { + "@id": "bts:Numtypecaps" + }, + { + "@id": "bts:Nantype" + }, + { + "@id": "bts:Missingtype" + }, + { + "@id": "bts:Booleantype" + }, + { + "@id": "bts:Booleantypecaps" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:Stringtype", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Stringtype", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "String type", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Stringtypecaps", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Stringtypecaps", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "string", + "sms:displayName": "String type caps", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Inttype", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Inttype", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer", + "sms:displayName": "Int type", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Inttypecaps", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Inttypecaps", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer", + "sms:displayName": "Int type caps", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Numtype", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Numtype", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "number", + "sms:displayName": "Num type", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Numtypecaps", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Numtypecaps", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "number", + "sms:displayName": "Num type caps", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Nantype", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Nantype", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Nan type", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Missingtype", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Missingtype", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "Missing type", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Booleantype", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Booleantype", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "boolean", + "sms:displayName": "Boolean type", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:Booleantypecaps", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "Booleantypecaps", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "boolean", + "sms:displayName": "Boolean type caps", + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:RangeComponent", + "@type": "rdfs:Class", + "rdfs:comment": "Component to ensure maximum and minimum can be set correctly", + "rdfs:label": "RangeComponent", + "rdfs:subClassOf": [ + { + "@id": "bts:DataType" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:displayName": "RangeComponent", + "sms:required": "sms:false", + "sms:requiresDependency": [ + { + "@id": "bts:Component" + }, + { + "@id": "bts:MaximumInteger" + }, + { + "@id": "bts:MinimumInteger" + }, + { + "@id": "bts:MaximumFloat" + }, + { + "@id": "bts:MinimumFloat" + }, + { + "@id": "bts:MaximumMinimum" + }, + { + "@id": "bts:MaximumMinimumIntegerList" + }, + { + "@id": "bts:MaximumMinimumValidationRule" + } + ], + "sms:validationRules": [] + }, + { + "@id": "bts:MaximumInteger", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MaximumInteger", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer", + "sms:displayName": "Maximum Integer", + "sms:maximum": 100.0, + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:MinimumInteger", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MinimumInteger", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer", + "sms:displayName": "Minimum Integer", + "sms:minimum": 10.0, + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:MaximumFloat", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MaximumFloat", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "number", + "sms:displayName": "Maximum Float", + "sms:maximum": 100.5, + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:MinimumFloat", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MinimumFloat", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "number", + "sms:displayName": "Minimum Float", + "sms:minimum": 10.8, + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:MaximumMinimum", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MaximumMinimum", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer", + "sms:displayName": "Maximum Minimum", + "sms:maximum": 100.0, + "sms:minimum": 10.0, + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:MaximumMinimumIntegerList", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MaximumMinimumIntegerList", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer_list", + "sms:displayName": "Maximum Minimum Integer List", + "sms:maximum": 100.0, + "sms:minimum": 10.0, + "sms:required": "sms:true", + "sms:validationRules": [] + }, + { + "@id": "bts:MaximumMinimumValidationRule", + "@type": "rdfs:Class", + "rdfs:comment": "TBD", + "rdfs:label": "MaximumMinimumValidationRule", + "rdfs:subClassOf": [ + { + "@id": "bts:DataProperty" + } + ], + "schema:isPartOf": { + "@id": "http://schema.biothings.io" + }, + "sms:columnType": "integer", + "sms:displayName": "Maximum Minimum Validation Rule", + "sms:maximum": 200.0, + "sms:minimum": 10.0, + "sms:required": "sms:true", + "sms:validationRules": [ + "inRange 50 100" + ] + } + ], + "@id": "http://schema.biothings.io/#0.1" +} diff --git a/tests/unit/synapseclient/extensions/schema_files/expected_jsonschemas/expected.JSONSchemaComponent.display_names_schema.json b/tests/unit/synapseclient/extensions/schema_files/expected_jsonschemas/expected.JSONSchemaComponent.display_names_schema.json new file mode 100644 index 000000000..b378f46d2 --- /dev/null +++ b/tests/unit/synapseclient/extensions/schema_files/expected_jsonschemas/expected.JSONSchemaComponent.display_names_schema.json @@ -0,0 +1,211 @@ +{ + "$id": "http://example.com/JSONSchemaComponent_validation", + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Component to hold attributes for testing JSON Schemas", + "properties": { + "Component": { + "description": "TBD", + "not": { + "type": "null" + }, + "title": "Component" + }, + "Date": { + "description": "TBD", + "format": "date", + "title": "Date", + "type": "string" + }, + "Enum": { + "description": "TBD", + "oneOf": [ + { + "enum": [ + "ab", + "cd", + "ef", + "gh" + ], + "title": "enum" + } + ], + "title": "Enum" + }, + "EnumNotRequired": { + "description": "TBD", + "oneOf": [ + { + "enum": [ + "ab", + "cd", + "ef", + "gh" + ], + "title": "enum" + }, + { + "title": "null", + "type": "null" + } + ], + "title": "Enum Not Required" + }, + "InRange": { + "description": "TBD", + "maximum": 100.0, + "minimum": 50.0, + "title": "InRange", + "type": "number" + }, + "List": { + "description": "TBD", + "oneOf": [ + { + "title": "array", + "type": "array" + } + ], + "title": "List" + }, + "ListEnum": { + "description": "TBD", + "oneOf": [ + { + "items": { + "enum": [ + "ab", + "cd", + "ef", + "gh" + ] + }, + "title": "array", + "type": "array" + } + ], + "title": "List Enum" + }, + "ListEnumNotRequired": { + "description": "TBD", + "oneOf": [ + { + "items": { + "enum": [ + "ab", + "cd", + "ef", + "gh" + ] + }, + "title": "array", + "type": "array" + }, + { + "title": "null", + "type": "null" + } + ], + "title": "List Enum Not Required" + }, + "ListInRange": { + "description": "TBD", + "oneOf": [ + { + "items": { + "maximum": 100.0, + "minimum": 50.0, + "type": "number" + }, + "title": "array", + "type": "array" + } + ], + "title": "List InRange" + }, + "ListNotRequired": { + "description": "TBD", + "oneOf": [ + { + "title": "array", + "type": "array" + }, + { + "title": "null", + "type": "null" + } + ], + "title": "List Not Required" + }, + "ListString": { + "description": "TBD", + "oneOf": [ + { + "items": { + "type": "string" + }, + "title": "array", + "type": "array" + } + ], + "title": "List String" + }, + "NoRules": { + "description": "TBD", + "not": { + "type": "null" + }, + "title": "No Rules" + }, + "NoRulesNotRequired": { + "description": "TBD", + "title": "No Rules Not Required" + }, + "Regex": { + "description": "TBD", + "pattern": "[a-f]", + "title": "Regex", + "type": "string" + }, + "String": { + "description": "TBD", + "title": "String", + "type": "string" + }, + "StringNotRequired": { + "description": "TBD", + "oneOf": [ + { + "title": "string", + "type": "string" + }, + { + "title": "null", + "type": "null" + } + ], + "title": "String Not Required" + }, + "URL": { + "description": "TBD", + "format": "uri", + "title": "URL", + "type": "string" + } + }, + "required": [ + "Component", + "Date", + "Enum", + "InRange", + "List", + "ListEnum", + "ListInRange", + "ListString", + "NoRules", + "Regex", + "String", + "URL" + ], + "title": "JSONSchemaComponent_validation", + "type": "object" +} diff --git a/tests/unit/synapseclient/extensions/schema_files/expected_jsonschemas/expected.MockComponent.schema.json b/tests/unit/synapseclient/extensions/schema_files/expected_jsonschemas/expected.MockComponent.schema.json index ad384ec1a..5236a424c 100644 --- a/tests/unit/synapseclient/extensions/schema_files/expected_jsonschemas/expected.MockComponent.schema.json +++ b/tests/unit/synapseclient/extensions/schema_files/expected_jsonschemas/expected.MockComponent.schema.json @@ -156,11 +156,9 @@ }, "CheckRegexFormat": { "description": "TBD", - "not": { - "type": "null" - }, - "pattern": "^[a-f]", - "title": "Check Regex Format" + "pattern": "^[a-b]", + "title": "Check Regex Format", + "type": "string" }, "CheckRegexInteger": { "description": "TBD", @@ -172,26 +170,27 @@ }, "CheckRegexList": { "description": "TBD", + "pattern": "^[a-f]", "title": "Check Regex List", "type": "array" }, "CheckRegexListLike": { "description": "TBD", + "pattern": "^[a-f]", "title": "Check Regex List Like", "type": "array" }, "CheckRegexListStrict": { "description": "TBD", + "pattern": "^[a-f]", "title": "Check Regex List Strict", "type": "array" }, "CheckRegexSingle": { "description": "TBD", - "not": { - "type": "null" - }, - "pattern": "[a-f]", - "title": "Check Regex Single" + "pattern": "[a-b]", + "title": "Check Regex Single", + "type": "string" }, "CheckString": { "description": "TBD", diff --git a/tests/unit/synapseclient/extensions/unit_test_create_json_schema.py b/tests/unit/synapseclient/extensions/unit_test_create_json_schema.py index 9f5faa418..c84606a4a 100644 --- a/tests/unit/synapseclient/extensions/unit_test_create_json_schema.py +++ b/tests/unit/synapseclient/extensions/unit_test_create_json_schema.py @@ -6,9 +6,13 @@ import json import logging import os +import tempfile +from time import sleep from typing import Any, Optional +from unittest import mock from unittest.mock import Mock +import pandas as pd import pytest from jsonschema import Draft7Validator from jsonschema.exceptions import ValidationError @@ -16,7 +20,9 @@ from synapseclient.extensions.curator.schema_generation import ( AtomicColumnType, ColumnType, + DataModelGraph, DataModelGraphExplorer, + DataModelParser, GraphTraversalState, JSONSchema, JSONSchemaFormat, @@ -101,6 +107,8 @@ def fixture_test_nodes( "EnumNotRequired", "InRange", "Regex", + "CheckRegexSingle", + "CheckRegexFormat", "Date", "URL", "List", @@ -327,6 +335,18 @@ def test_update_property(self) -> None: ("InRange", AtomicColumnType.NUMBER, False, 50, 100, None, None), # Node with "regex search [a-f]" validation rule and columnType "string" - pattern is set, type is STRING ("Regex", AtomicColumnType.STRING, False, None, None, "[a-f]", None), + # Node with "[a-f]" pattern column specification and columnType "string" - pattern is set, type is STRING + ("CheckRegexSingle", AtomicColumnType.STRING, False, None, None, "[a-b]", None), + # Node with "regex search [a-f]" validation rule, "^[a-b]" pattern column specification, and columnType "string" - pattern is set, type is STRING + ( + "CheckRegexFormat", + AtomicColumnType.STRING, + False, + None, + None, + "^[a-b]", + None, + ), # Node with "date" validation rule and columnType "string" - format is set to DATE, type is STRING ( "Date", @@ -350,6 +370,8 @@ def test_update_property(self) -> None: "List", "InRange", "Regex", + "CheckRegexSingle", + "CheckRegexFormat", "Date", "URI", "ListBoolean", @@ -365,6 +387,7 @@ def test_node_init( expected_pattern: Optional[str], expected_format: Optional[JSONSchemaFormat], test_nodes: dict[str, TraversalNode], + caplog, ) -> None: """ Tests for TraversalNode class initialization. @@ -377,6 +400,7 @@ def test_node_init( The type property comes from the columnType field, while constraints come from parsing validation rules like "str", "inRange", "regex", etc. """ + node = test_nodes[node_name] assert node.type == expected_type assert node.format == expected_format @@ -384,6 +408,93 @@ def test_node_init( assert node.minimum == expected_min assert node.maximum == expected_max assert node.pattern == expected_pattern + if node_name == "Regex": + warning_message = "A regex validation rule is set for property: Regex, but the pattern is not set in the data model." + assert warning_message in test_nodes[node_name].logger.mock_calls[0][1][0] + + +def test_invalid_regex_columntype_traversalnode( + helpers, +) -> None: + """ + Tests for matching pattern and columnType specification. + + Verifies that when TransversalNode objects are initialized with a pattern specified and an incompatible column type, a ValueError is raised. + """ + node = "Check Regex Single" + + path_to_data_model = helpers.get_schema_file_path("data_models/example.model.csv") + + fullpath = helpers.get_schema_file_path(path_to_data_model) + + # Instantiate DataModelParser + data_model_parser = DataModelParser(path_to_data_model=fullpath, logger=Mock()) + + # Parse Model + parsed_data_model = data_model_parser.parse_model() + + # Change column type to imcompatible type + parsed_data_model[node]["Relationships"]["ColumnType"] = "integer" + + # Instantiate DataModelGraph + data_model_grapher = DataModelGraph( + parsed_data_model, data_model_labels="class_label", logger=Mock() + ) + + # Generate graph + graph_data_model = data_model_grapher.graph + + # Instantiate DataModelGraphExplorer + dmge = DataModelGraphExplorer(graph_data_model, logger=Mock()) + + # A value error should be raised when using pattern specification with non-string column type + error_message = "Column type must be set to 'string' to use column pattern specification for regex validation." + with pytest.raises(ValueError, match=error_message): + node = TraversalNode( + node.replace(" ", ""), "JSONSchemaComponent", dmge, logger=Mock() + ) + + +def test_invalid_regex_traversalnode( + helpers, +) -> None: + """ + Tests for invalid regex pattern specification. + + Verifies that only valid regex patterns are specified. + """ + node = "Check Regex Single" + + path_to_data_model = helpers.get_schema_file_path("data_models/example.model.csv") + + fullpath = helpers.get_schema_file_path(path_to_data_model) + + # Instantiate DataModelParser + data_model_parser = DataModelParser(path_to_data_model=fullpath, logger=Mock()) + + # Parse Model + parsed_data_model = data_model_parser.parse_model() + + # Change column type to imcompatible type + parsed_data_model[node]["Relationships"]["Pattern"] = "\\u" + + # Instantiate DataModelGraph + data_model_grapher = DataModelGraph( + parsed_data_model, data_model_labels="class_label", logger=Mock() + ) + + # Generate graph + graph_data_model = data_model_grapher.graph + + # Instantiate DataModelGraphExplorer + dmge = DataModelGraphExplorer(graph_data_model, logger=Mock()) + + # A value error should be raised when using pattern specification with non-string column type + error_message = "Column type must be set to 'string' to use column pattern specification for regex validation." + with pytest.raises(SyntaxError, match="The regex pattern.*is invalid"): + node = TraversalNode( + node.replace(" ", ""), "JSONSchemaComponent", dmge, logger=Mock() + ) @pytest.mark.parametrize( diff --git a/tests/unit/synapseclient/extensions/unit_test_data_model_graph_explorer.py b/tests/unit/synapseclient/extensions/unit_test_data_model_graph_explorer.py index 867237b27..6a8a46f32 100644 --- a/tests/unit/synapseclient/extensions/unit_test_data_model_graph_explorer.py +++ b/tests/unit/synapseclient/extensions/unit_test_data_model_graph_explorer.py @@ -69,6 +69,20 @@ def test_get_node_column_type( assert dmge.get_node_column_type(node_label) == column_type +@pytest.mark.parametrize( + "node_label, pattern", + [ + ("CheckRegexSingle", "[a-b]"), + ("CheckRegexFormat", "^[a-b]"), + ("CheckRegexInteger", None), + ], +) +def test_get_node_pattern( + dmge: DataModelGraphExplorer, node_label: str, pattern: str +) -> None: + assert dmge.get_node_column_pattern(node_label) == pattern + + @pytest.mark.parametrize( "node_label, column_type", [("String", None), ("Date", JSONSchemaFormat.DATE), ("URL", JSONSchemaFormat.URI)], diff --git a/tests/unit/synapseclient/extensions/unit_test_data_model_parser.py b/tests/unit/synapseclient/extensions/unit_test_data_model_parser.py index b65a099d8..605da11d2 100644 --- a/tests/unit/synapseclient/extensions/unit_test_data_model_parser.py +++ b/tests/unit/synapseclient/extensions/unit_test_data_model_parser.py @@ -1,6 +1,9 @@ +import tempfile +from time import sleep from typing import Any, Union import numpy as np +import pandas as pd import pytest from synapseclient.extensions.curator.schema_generation import ( @@ -87,6 +90,23 @@ def test_parse_format( ) -> None: assert csv_dmp.parse_format(attribute_dict) == expected_dict + @pytest.mark.parametrize( + "attribute_dict, expected_dict", + [ + ({}, {}), + ({"Pattern": np.nan}, {}), + ({"Pattern": "^[a-b]"}, {"Pattern": "^[a-b]"}), + ({"Pattern": " [a-b] "}, {"Pattern": "[a-b]"}), + ], + ) + def test_parse_regex_pattern( + self, + csv_dmp: DataModelCSVParser, + attribute_dict: dict[str, Any], + expected_dict: dict[str, str], + ) -> None: + assert csv_dmp.parse_pattern(attribute_dict) == expected_dict + @pytest.mark.parametrize( "attribute_dict, relationship, expected_dict", [ @@ -143,8 +163,6 @@ def test_gather_jsonld_attributes_relationships( assert csv_dmp.parse_minimum_maximum(attribute_dict, "Minimum") == expected_dict assert csv_dmp.parse_minimum_maximum(attribute_dict, "Maximum") == expected_dict - -class TestDataModelJsonLdParser: def test_gather_jsonld_attributes_relationships( self, helpers, diff --git a/tests/unit/synapseclient/extensions/unit_test_data_model_relationships.py b/tests/unit/synapseclient/extensions/unit_test_data_model_relationships.py index bbc3eca96..c5fb2250c 100644 --- a/tests/unit/synapseclient/extensions/unit_test_data_model_relationships.py +++ b/tests/unit/synapseclient/extensions/unit_test_data_model_relationships.py @@ -71,6 +71,7 @@ def test_retrieve_rel_headers_dict(self, dmr: DataModelRelationships, edge: bool "id": "Source", "maximum": "Maximum", "minimum": "Minimum", + "pattern": "Pattern", } def test_get_relationship_value(self, dmr: DataModelRelationships) -> None: