• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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