haste_artifacts/
search_parameters.rs1use haste_fhir_model::r4::generated::resources::{Resource, ResourceType, SearchParameter};
2use rust_embed::Embed;
3use std::{
4 collections::HashMap,
5 sync::{Arc, LazyLock},
6};
7
8#[derive(Debug)]
9pub enum ArtifactError {
10 InvalidResource(String),
11}
12
13pub struct SearchParametersIndex {
14 by_url: HashMap<String, Arc<SearchParameter>>,
15 by_resource_type: HashMap<String, HashMap<String, Arc<SearchParameter>>>,
16}
17
18impl Default for SearchParametersIndex {
19 fn default() -> Self {
20 SearchParametersIndex {
21 by_url: HashMap::new(),
22 by_resource_type: HashMap::new(),
23 }
24 }
25}
26
27fn index_parameter(
28 index: &mut SearchParametersIndex,
29 resource: Resource,
30) -> Result<(), ArtifactError> {
31 match resource {
32 Resource::Bundle(bundle) => {
33 let params = bundle
34 .entry
35 .unwrap_or(vec![])
36 .into_iter()
37 .flat_map(|e| e.resource)
38 .filter_map(|resource| match *resource {
39 Resource::SearchParameter(search_param) => Some(Arc::new(search_param)),
40 _ => None,
41 });
42
43 for param in params {
44 index
45 .by_url
46 .insert(param.id.clone().unwrap(), param.clone());
47 for resource_type in ¶m.base {
48 let resource_type: Option<String> = (&**resource_type).into();
49 if let Some(resource_type) = resource_type {
50 index
51 .by_resource_type
52 .entry(resource_type)
53 .or_default()
54 .insert(
55 param.code.value.as_ref().unwrap().to_string(),
56 param.clone(),
57 );
58 }
59 }
60 }
61
62 Ok(())
63 }
64 Resource::SearchParameter(search_param) => {
65 let param = Arc::new(search_param);
66 index
67 .by_url
68 .insert(param.id.clone().unwrap(), param.clone());
69 for resource_type in ¶m.base {
70 let resource_type: Option<String> = (&**resource_type).into();
71 if let Some(resource_type) = resource_type.as_ref() {
72 index
73 .by_resource_type
74 .entry(resource_type.to_string())
75 .or_default()
76 .insert(
77 param.code.value.as_ref().unwrap().to_string(),
78 param.clone(),
79 );
80 }
81 }
82 Ok(())
83 }
84 _ => Err(ArtifactError::InvalidResource(
85 "Expected a Bundle resource".to_string(),
86 )),
87 }
88}
89
90#[derive(Embed)]
91#[folder = "./artifacts/r4"]
92#[include = "haste_health/search_parameter/*.json"]
93#[include = "hl7/minified/search-parameters.min.json"]
94
95struct EmbededSearchParameterAssets;
96
97static R4_SEARCH_PARAMETERS: LazyLock<SearchParametersIndex> = LazyLock::new(|| {
98 let mut index = SearchParametersIndex::default();
99
100 for path in EmbededSearchParameterAssets::iter() {
101 let data = EmbededSearchParameterAssets::get(path.as_ref()).unwrap();
102 let bundle = haste_fhir_serialization_json::from_str::<Resource>(
103 std::str::from_utf8(&data.data).unwrap(),
104 )
105 .expect("Failed to parse search parameters JSON");
106 index_parameter(&mut index, bundle).expect("Failed to extract search parameters");
107 }
108
109 index
110});
111
112pub fn get_all_search_parameters() -> Vec<Arc<SearchParameter>> {
113 R4_SEARCH_PARAMETERS
114 .by_url
115 .values()
116 .cloned()
117 .collect::<Vec<_>>()
118}
119
120pub fn get_search_parameters_for_resource(
121 resource_type: &ResourceType,
122) -> Vec<Arc<SearchParameter>> {
123 let resource_params = R4_SEARCH_PARAMETERS
124 .by_resource_type
125 .get("Resource")
126 .unwrap();
127 let domain_params = R4_SEARCH_PARAMETERS
128 .by_resource_type
129 .get("DomainResource")
130 .unwrap();
131 let mut return_vec = Vec::new();
132 return_vec.extend(resource_params.values().cloned());
133 return_vec.extend(domain_params.values().cloned());
134
135 if let Some(params) = R4_SEARCH_PARAMETERS
136 .by_resource_type
137 .get(resource_type.as_ref())
138 {
139 return_vec.extend(params.values().cloned());
140 }
141
142 return_vec
143}
144
145pub fn get_search_parameter_for_name(
146 resource_type: Option<&ResourceType>,
147 name: &str,
148) -> Option<Arc<SearchParameter>> {
149 resource_type
150 .and_then(|resource_type| {
151 R4_SEARCH_PARAMETERS
152 .by_resource_type
153 .get(resource_type.as_ref())
154 })
155 .and_then(|params| params.get(name))
156 .or_else(|| {
157 R4_SEARCH_PARAMETERS
158 .by_resource_type
159 .get("Resource")
160 .and_then(|params| params.get(name))
161 })
162 .or_else(|| {
163 R4_SEARCH_PARAMETERS
164 .by_resource_type
165 .get("DomainResource")
166 .and_then(|params| params.get(name))
167 })
168 .cloned()
169}