1from typing import Mapping 2 3# LINT.IfChange(fhir_resource_type_mapping) 4RESOURCE_TYPE_STRING_TO_HC_INT_MAPPING = { 5 "Immunization": 1, 6 "AllergyIntolerance": 2, 7 "Observation": 3, 8 "Condition": 4, 9 "Procedure": 5, 10 "Medication": 6, 11 "MedicationRequest": 7, 12 "MedicationStatement": 8, 13 "Patient": 9, 14 "Practitioner": 10, 15 "PractitionerRole": 11, 16 "Encounter": 12, 17 "Location": 13, 18 "Organization": 14, 19} 20# LINT.ThenChange(/framework/java/android/health/connect/datatypes/FhirResource.java) 21 22HC_SUPPORTED_RESOURCE_SET = set(RESOURCE_TYPE_STRING_TO_HC_INT_MAPPING.keys()) 23 24FHIR_VERSION_R4 = "4.0.1" 25 26 27def to_upper_snake_case(string: str) -> str: 28 snake_case_string = string[0].upper() + "".join( 29 ["_" + c if c.isupper() else c for c in string[1:]]) 30 31 return snake_case_string.upper().replace('-', '_') 32 33 34def extract_type_to_structure_definitions_from_spec( 35 definitions_json: Mapping, type_names: set[str]) -> Mapping: 36 """Returns structure definitions by type for the requested type_names. 37 38 The type name extraction is not case sensitive (everything gets converted to upper case) to make 39 it easier to extract type definitions from enum names. 40 41 Args: 42 definitions_json: The contents of a fhir spec file with type definitions, which is in 43 the structure of a https://hl7.org/fhir/Bundle.html, parsed to dict. The Bundle.entry 44 will contain the list of https://hl7.org/fhir/StructureDefinition.html that we are 45 interested in. 46 type_names: The set of FHIR types to extract StructureDefinitions for. If type_names is 47 None, all types will be extracted that have a url starting with 48 "http://hl7.org/fhir/StructureDefinition/". 49 50 Returns: 51 The mapping of type name to StructureDefinition. 52 """ 53 type_to_structure_definition = {} 54 upper_case_type_names = None 55 56 if type_names is not None: 57 upper_case_type_names = set(name.upper() for name in type_names) 58 if len(upper_case_type_names) != len(type_names): 59 raise ValueError("Found type name duplicates after converting to upper case") 60 61 for entry in definitions_json["entry"]: 62 fullUrl = entry["fullUrl"] 63 if not fullUrl.startswith("http://hl7.org/fhir/StructureDefinition/"): 64 continue 65 66 type_name = fullUrl.split("/")[-1] 67 if type_names is not None and type_name.upper() not in upper_case_type_names: 68 continue 69 70 type_structure_definition = entry["resource"] 71 72 # Do some assertions on expected values 73 if type_structure_definition["fhirVersion"] != FHIR_VERSION_R4: 74 raise ValueError("Unexpected fhir version found") 75 # The definitions for SimpleQuantity and MoneyQuantity have type = Quantity 76 if type_structure_definition["type"] != type_name and type_name not in [ 77 "SimpleQuantity", "MoneyQuantity"]: 78 raise ValueError( 79 f"Unexpected type in structure definition: {type_structure_definition['type']}" + 80 "for {type_name}") 81 82 if type_name in type_to_structure_definition: 83 raise ValueError("Type definition already exists: " + type_name) 84 type_to_structure_definition[type_name] = type_structure_definition 85 86 if type_names is not None and len(type_to_structure_definition.keys()) != len(type_names): 87 raise ValueError("Did not find type definitions for all requested types.") 88 89 return type_to_structure_definition 90 91 92def extract_element_definitions_from_structure_def(structure_definition): 93 """Returns the list of "snapshot" ElementDefinitions from the provided StructureDefinition 94 95 We select the list of elements in "snapshot" (as opposed to "differential"), as we want the full 96 definition of fields, including fields from any base definitions. Each ElementDefinition 97 contains the spec for a path / field of the type. 98 """ 99 return structure_definition["snapshot"]["element"] 100 101def generate_fhir_type_string_for_child_type_path(path): 102 """Generates a type string from a path to be used to get the child type enum. 103 104 The resulting string can be used in the same way as the type.code field in a 105 StructureDefinition. 106 107 For example, a path "Immunization.performer" will be turned into "ImmunizationPerformer". 108 """ 109 return path.replace('.', ' ').title().replace(' ', '') 110