1use haste_fhir_operation_error::derive::OperationOutcomeError;
2use haste_reflect::{MetaValue, derive::Reflect};
3use std::{collections::HashMap, fmt::Display};
4
5#[derive(Debug, Clone, Reflect)]
6pub struct Parameter {
7 pub name: String,
8 pub value: Vec<String>,
9 pub modifier: Option<String>,
10 pub chains: Option<Vec<String>>,
11}
12
13#[derive(Debug, Clone)]
16pub enum ParsedParameter {
17 Result(Parameter),
18 Resource(Parameter),
19}
20
21impl ParsedParameter {
22 pub fn name(&self) -> &str {
23 match self {
24 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => &p.name,
25 }
26 }
27}
28
29impl MetaValue for ParsedParameter {
30 fn fields(&self) -> Vec<&'static str> {
31 match self {
32 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.fields(),
33 }
34 }
35
36 fn get_field<'a>(&'a self, field: &str) -> Option<&'a dyn MetaValue> {
37 match self {
38 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.get_field(field),
39 }
40 }
41
42 fn get_field_mut<'a>(&'a mut self, field: &str) -> Option<&'a mut dyn MetaValue> {
43 match self {
44 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.get_field_mut(field),
45 }
46 }
47
48 fn get_index<'a>(&'a self, index: usize) -> Option<&'a dyn MetaValue> {
49 match self {
50 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.get_index(index),
51 }
52 }
53
54 fn get_index_mut<'a>(&'a mut self, index: usize) -> Option<&'a mut dyn MetaValue> {
55 match self {
56 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.get_index_mut(index),
57 }
58 }
59
60 fn flatten(&self) -> Vec<&dyn MetaValue> {
61 match self {
62 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.flatten(),
63 }
64 }
65
66 fn as_any(&self) -> &dyn std::any::Any {
67 match self {
68 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.as_any(),
69 }
70 }
71
72 fn typename(&self) -> &'static str {
73 match self {
74 ParsedParameter::Result(p) | ParsedParameter::Resource(p) => p.typename(),
75 }
76 }
77
78 fn is_many(&self) -> bool {
79 false
80 }
81}
82
83#[derive(Debug, OperationOutcomeError)]
84pub enum ParseError {
85 #[fatal(
86 code = "invalid",
87 diagnostic = "Error parsing query parameters '{arg0}'"
88 )]
89 InvalidParameter(String),
90}
91
92impl Display for ParseError {
93 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
94 match self {
95 ParseError::InvalidParameter(param) => {
96 write!(f, "Invalid query parameter: {}", param)
97 }
98 }
99 }
100}
101
102impl std::error::Error for ParseError {}
103
104static RESULT_PARAMETERS: &[&str] = &[
105 "_count",
106 "_offset",
107 "_total",
108 "_sort",
109 "_include",
110 "_revinclude",
111 "_summary",
112 "_elements",
113 "_contained",
114 "_containedType",
115 "_since",
116];
117
118#[derive(Debug, Clone)]
119pub struct ParsedParameters(Vec<ParsedParameter>);
120
121impl ParsedParameters {
122 pub fn new(params: Vec<ParsedParameter>) -> Self {
123 Self(params)
124 }
125 pub fn parameters<'a>(&'a self) -> &'a Vec<ParsedParameter> {
126 &self.0
127 }
128 pub fn owned_parameters<'a>(self) -> Vec<ParsedParameter> {
129 self.0
130 }
131 pub fn get<'a>(&'a self, name: &str) -> Option<&'a ParsedParameter> {
132 self.0.iter().find(|p| match p {
133 ParsedParameter::Resource(param) | ParsedParameter::Result(param) => param.name == name,
134 })
135 }
136}
137
138impl MetaValue for ParsedParameters {
139 fn fields(&self) -> Vec<&'static str> {
140 todo!()
141 }
142
143 fn get_field<'a>(&'a self, field: &str) -> Option<&'a dyn MetaValue> {
144 if let Some(p) = self.get(field) {
145 Some(p)
146 } else {
147 None
148 }
149 }
150
151 fn get_field_mut<'a>(&'a mut self, _field: &str) -> Option<&'a mut dyn MetaValue> {
152 None
153 }
154
155 fn get_index<'a>(&'a self, _index: usize) -> Option<&'a dyn MetaValue> {
156 None
157 }
158
159 fn get_index_mut<'a>(&'a mut self, _index: usize) -> Option<&'a mut dyn MetaValue> {
160 None
161 }
162
163 fn flatten(&self) -> Vec<&dyn MetaValue> {
164 vec![]
165 }
166
167 fn as_any(&self) -> &dyn std::any::Any {
168 self
169 }
170
171 fn typename(&self) -> &'static str {
172 "ParsedParameters"
173 }
174
175 fn is_many(&self) -> bool {
176 true
177 }
178}
179
180impl TryFrom<&str> for ParsedParameters {
181 type Error = ParseError;
182 fn try_from(query_string: &str) -> Result<Self, ParseError> {
183 let mut query_string = query_string;
184 if query_string.is_empty() {
185 return Ok(Self(vec![]));
186 }
187
188 if query_string.starts_with('?') {
189 query_string = &query_string[1..];
190 }
191
192 let query_map = query_string.split('&').fold(
193 Ok(HashMap::new()),
194 |acc: Result<HashMap<String, String>, ParseError>, pair| {
195 let mut map = acc?;
196 let mut split = pair.splitn(2, '=');
197 let key = split
198 .next()
199 .ok_or_else(|| ParseError::InvalidParameter(pair.to_string()))?;
200 let value = split
201 .next()
202 .ok_or_else(|| ParseError::InvalidParameter(pair.to_string()))?;
203 map.insert(key.to_string(), value.to_string());
204 Ok(map)
205 },
206 )?;
207
208 Self::try_from(&query_map)
209 }
210}
211
212impl TryFrom<&HashMap<String, String>> for ParsedParameters {
213 type Error = ParseError;
214 fn try_from(query_params: &HashMap<String, String>) -> Result<Self, ParseError> {
215 if query_params.is_empty() {
216 return Ok(Self(vec![]));
217 }
218
219 let params = query_params
220 .keys()
221 .map(|param_name| {
222 let value = query_params.get(param_name).unwrap();
223
224 let chain = param_name
225 .split('.')
226 .map(|s| s.to_string())
227 .collect::<Vec<String>>();
228
229 if chain.is_empty() {
230 return Err(ParseError::InvalidParameter(param_name.to_string()));
231 }
232
233 let name_and_modifier = chain[0].split(':').collect::<Vec<&str>>();
234
235 if name_and_modifier.len() > 2 || name_and_modifier.is_empty() {
236 return Err(ParseError::InvalidParameter(param_name.to_string()));
237 }
238
239 let name = name_and_modifier[0].to_string();
240
241 let param = Parameter {
242 name,
243 modifier: name_and_modifier.get(1).map(|s| s.to_string()),
244 value: value.split(',').map(|v| v.to_string()).collect(),
245 chains: if chain.len() > 1 {
246 Some(chain[1..].to_vec())
247 } else {
248 None
249 },
250 };
251
252 if RESULT_PARAMETERS.contains(¶m.name.as_str()) {
253 Ok(ParsedParameter::Result(param))
254 } else {
255 Ok(ParsedParameter::Resource(param))
256 }
257 })
258 .collect::<Result<Vec<ParsedParameter>, ParseError>>()?;
259
260 Ok(Self(params))
261 }
262}
263
264pub fn parse_prefix<'a>(v: &'a str) -> (Option<&'a str>, &'a str) {
265 if v.len() < 3 {
266 return (None, v);
267 }
268
269 let sub_str = &v[..2];
270 let remainder = &v[2..];
271
272 match sub_str {
273 "lt" => (Some(sub_str), remainder),
274 "le" => (Some(sub_str), remainder),
275 "gt" => (Some(sub_str), remainder),
276 "ge" => (Some(sub_str), remainder),
277 "eq" => (Some(sub_str), remainder),
278 "ne" => (Some(sub_str), remainder),
279 _ => (None, v),
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286
287 #[test]
288 fn test_parse_prefix() {
289 let cases = vec![
290 ("lt5.0", (Some("lt"), "5.0")),
291 ("le10", (Some("le"), "10")),
292 ("gt3.14", (Some("gt"), "3.14")),
293 ("ge2.71", (Some("ge"), "2.71")),
294 ("eq42", (Some("eq"), "42")),
295 ("ne0", (Some("ne"), "0")),
296 ("5.0", (None, "5.0")),
297 ("10", (None, "10")),
298 ];
299
300 for (input, expected) in cases {
301 let result = parse_prefix(input);
302 assert_eq!(result, expected, "Failed for input: {}", input);
303 }
304 }
305
306 #[test]
307 fn test_parse_parameters() {
308 let query_string = "?name=John,Doe&_count=10&address.city=NewYork&status:exact=active";
309 let parsed_params = ParsedParameters::try_from(query_string).unwrap();
310
311 assert_eq!(parsed_params.parameters().len(), 4);
312
313 match parsed_params.get("name") {
314 Some(ParsedParameter::Resource(param)) => {
315 assert_eq!(param.name, "name");
316 assert_eq!(param.value, vec!["John", "Doe"]);
317 assert!(param.modifier.is_none());
318 assert!(param.chains.is_none());
319 }
320 _ => panic!("Expected Resource parameter"),
321 }
322
323 match parsed_params.get("_count") {
324 Some(ParsedParameter::Result(param)) => {
325 assert_eq!(param.name, "_count");
326 assert_eq!(param.value, vec!["10"]);
327 assert!(param.modifier.is_none());
328 assert!(param.chains.is_none());
329 }
330 _ => panic!("Expected Result parameter"),
331 }
332
333 match parsed_params.get("address") {
334 Some(ParsedParameter::Resource(param)) => {
335 assert_eq!(param.name, "address");
336 assert_eq!(param.value, vec!["NewYork"]);
337 assert!(param.modifier.is_none());
338 assert_eq!(param.chains, Some(vec!["city".to_string()]));
339 }
340 _ => panic!("Expected Resource parameter"),
341 }
342
343 match parsed_params.get("status") {
344 Some(ParsedParameter::Resource(param)) => {
345 assert_eq!(param.name, "status");
346 assert_eq!(param.value, vec!["active"]);
347 assert_eq!(param.modifier, Some("exact".to_string()));
348 assert!(param.chains.is_none());
349 }
350 _ => panic!("Expected Resource parameter"),
351 }
352 }
353}