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