1mod error;
2mod parser;
3use crate::{
4 error::{FunctionError, OperationError},
5 parser::{Expression, FunctionInvocation, Identifier, Invocation, Literal, Operation, Term},
6};
7use dashmap::DashMap;
8pub use error::FHIRPathError;
9use haste_fhir_model::r4::{
10 conversion::{
11 BOOLEAN_TYPES, NUMBER_TYPES, STRING_TYPES, downcast_bool, downcast_number, downcast_string,
12 },
13 generated::{
14 resources::ResourceType,
15 types::{FHIRBoolean, FHIRDecimal, FHIRInteger, FHIRString, Reference},
16 },
17 get_fhir_type,
18};
19use haste_reflect::MetaValue;
20use haste_reflect_derive::Reflect;
21use std::pin::Pin;
22use std::{
23 collections::HashMap,
24 marker::PhantomData,
25 sync::{Arc, LazyLock},
26};
27use tokio::sync::Mutex;
28
29async fn evaluate_literal<'b>(
30 literal: &Literal,
31 context: Context<'b>,
32) -> Result<Context<'b>, FHIRPathError> {
33 match literal {
34 Literal::String(string) => Ok(context.new_context_from(vec![
35 context
36 .allocate(ResolvedValue::Box(Box::new(FHIRString {
37 value: Some(string.clone()),
38 ..Default::default()
39 })))
40 .await,
41 ])),
42 Literal::Integer(int) => Ok(context.new_context_from(vec![
43 context
44 .allocate(ResolvedValue::Box(Box::new(FHIRInteger {
45 value: Some(int.clone()),
46 ..Default::default()
47 })))
48 .await,
49 ])),
50 Literal::Float(decimal) => Ok(context.new_context_from(vec![
51 context
52 .allocate(ResolvedValue::Box(Box::new(FHIRDecimal {
53 value: Some(decimal.clone()),
54 ..Default::default()
55 })))
56 .await,
57 ])),
58 Literal::Boolean(bool) => Ok(context.new_context_from(vec![
59 context
60 .allocate(ResolvedValue::Box(Box::new(FHIRBoolean {
61 value: Some(bool.clone()),
62 ..Default::default()
63 })))
64 .await,
65 ])),
66 Literal::Null => Ok(context.new_context_from(vec![])),
67 _ => Err(FHIRPathError::InvalidLiteral(literal.to_owned())),
68 }
69}
70
71async fn evaluate_invocation<'a>(
72 invocation: &Invocation,
73 context: Context<'a>,
74 config: Option<Arc<Config<'a>>>,
75) -> Result<Context<'a>, FHIRPathError> {
76 match invocation {
77 Invocation::This => Ok(context),
78 Invocation::Index(index_expression) => {
79 let index = evaluate_expression(index_expression, context.clone(), config).await?;
80 if index.values.len() != 1 {
81 return Err(FHIRPathError::OperationError(
82 OperationError::InvalidCardinality,
83 ));
84 }
85 let index = downcast_number(index.values[0])? as usize;
86 if let Some(value) = context.values.get(index) {
87 Ok(context.new_context_from(vec![*value]))
88 } else {
89 Ok(context.new_context_from(vec![]))
90 }
91 }
92 Invocation::IndexAccessor => Err(FHIRPathError::NotImplemented("index access".to_string())),
93 Invocation::Total => Err(FHIRPathError::NotImplemented("total".to_string())),
94 Invocation::Identifier(Identifier(id)) => Ok(context.new_context_from(
95 context
96 .values
97 .iter()
98 .flat_map(|v| {
99 v.get_field(id)
100 .map(|v| v.flatten())
101 .unwrap_or_else(|| vec![])
102 })
103 .collect(),
104 )),
105 Invocation::Function(function) => evaluate_function(function, context, config).await,
106 }
107}
108
109async fn evaluate_term<'a>(
110 term: &Term,
111 context: Context<'a>,
112 config: Option<Arc<Config<'a>>>,
113) -> Result<Context<'a>, FHIRPathError> {
114 match term {
115 Term::Literal(literal) => evaluate_literal(literal, context).await,
116 Term::ExternalConstant(constant) => {
117 resolve_external_constant(
118 constant,
119 config.as_ref().and_then(|c| c.variable_resolver.as_ref()),
120 context,
121 )
122 .await
123 }
124 Term::Parenthesized(expression) => evaluate_expression(expression, context, config).await,
125 Term::Invocation(invocation) => evaluate_invocation(invocation, context, config).await,
126 }
127}
128
129async fn evaluate_first_term<'a>(
132 term: &Term,
133 context: Context<'a>,
134 config: Option<Arc<Config<'a>>>,
135) -> Result<Context<'a>, FHIRPathError> {
136 match term {
137 Term::Invocation(invocation) => match invocation {
138 Invocation::Identifier(identifier) => {
139 let type_filter = filter_by_type(&identifier.0, &context);
140 if !type_filter.values.is_empty() {
141 Ok(type_filter)
142 } else {
143 evaluate_invocation(invocation, context, config).await
144 }
145 }
146 _ => evaluate_invocation(invocation, context, config).await,
147 },
148 _ => evaluate_term(term, context, config).await,
149 }
150}
151
152async fn evaluate_singular<'a>(
153 expression: &Vec<Term>,
154 context: Context<'a>,
155 config: Option<Arc<Config<'a>>>,
156) -> Result<Context<'a>, FHIRPathError> {
157 let mut current_context = context;
158
159 let mut term_iterator = expression.iter();
160 let first_term = term_iterator.next();
161 if let Some(first_term) = first_term {
162 current_context = evaluate_first_term(first_term, current_context, config.clone()).await?;
163 }
164
165 for term in term_iterator {
166 current_context = evaluate_term(term, current_context, config.clone()).await?;
167 }
168
169 Ok(current_context)
170}
171
172async fn operation_2<'a>(
173 left: &Expression,
174 right: &Expression,
175 context: Context<'a>,
176 config: Option<Arc<Config<'a>>>,
177 executor: impl Fn(
178 Context<'a>,
179 Context<'a>,
180 )
181 -> Pin<Box<dyn Future<Output = Result<Context<'a>, FHIRPathError>> + Send + 'a>>,
182) -> Result<Context<'a>, FHIRPathError> {
183 let left = evaluate_expression(left, context.clone(), config.clone()).await?;
184 let right = evaluate_expression(right, context, config).await?;
185
186 if left.values.len() == 0 || right.values.len() == 0 {
188 return Ok(left.new_context_from(vec![]));
189 }
190
191 if left.values.len() != 1 || right.values.len() != 1 {
192 return Err(FHIRPathError::OperationError(
193 OperationError::InvalidCardinality,
194 ));
195 }
196
197 executor(left, right).await
198}
199
200async fn operation_n<'a>(
201 left: &Expression,
202 right: &Expression,
203 context: Context<'a>,
204 config: Option<Arc<Config<'a>>>,
205 executor: impl Fn(Context<'a>, Context<'a>) -> Result<Context<'a>, FHIRPathError>,
206) -> Result<Context<'a>, FHIRPathError> {
207 let left = evaluate_expression(left, context.clone(), config.clone()).await?;
208 let right = evaluate_expression(right, context, config).await?;
209 executor(left, right)
210}
211
212enum Cardinality {
213 Zero,
214 One,
215 Many,
216}
217
218fn validate_arguments(
219 ast_arguments: &Vec<Expression>,
220 cardinality: &Cardinality,
221) -> Result<(), FHIRPathError> {
222 match cardinality {
223 Cardinality::Zero => {
224 if ast_arguments.len() != 0 {
225 return Err(FHIRPathError::OperationError(
226 OperationError::InvalidCardinality,
227 ));
228 }
229 }
230 Cardinality::One => {
231 if ast_arguments.len() != 1 {
232 return Err(FHIRPathError::OperationError(
233 OperationError::InvalidCardinality,
234 ));
235 }
236 }
237 Cardinality::Many => {}
238 }
239 Ok(())
240}
241
242fn derive_typename(expression_ast: &Expression) -> Result<String, FHIRPathError> {
243 match expression_ast {
244 Expression::Singular(ast) => match &ast[0] {
245 Term::Invocation(Invocation::Identifier(type_id)) => Ok(type_id.0.clone()),
246 _ => Err(FHIRPathError::FailedTypeNameDerivation),
247 },
248 _ => Err(FHIRPathError::FailedTypeNameDerivation),
249 }
250}
251
252fn check_type_name(type_name: &str, type_to_check: &str) -> bool {
253 match type_to_check {
254 "Resource" | "DomainResource" => ResourceType::try_from(type_name).is_ok(),
255 _ => type_name == type_to_check,
256 }
257}
258
259fn check_type(value: &dyn MetaValue, type_to_check: &str) -> bool {
260 let fhir_type_name = get_fhir_type(value);
261
262 match fhir_type_name {
263 Some("Reference") => {
265 if type_to_check == "Reference" {
266 return true;
267 } else if let Some(reference) = value.as_any().downcast_ref::<Reference>() {
268 if let Some(resource_type) = reference
269 .reference
270 .as_ref()
271 .and_then(|r| r.value.as_ref())
272 .and_then(|r| r.split("/").next())
273 {
274 return check_type_name(resource_type, type_to_check);
275 }
276 }
277 false
278 }
279 Some(fhir_type_name) => check_type_name(fhir_type_name, type_to_check),
280 None => false,
281 }
282}
283
284fn filter_by_type<'a>(type_name: &str, context: &Context<'a>) -> Context<'a> {
285 context.new_context_from(
286 context
287 .values
288 .iter()
289 .filter(|v| check_type(**v, type_name))
290 .map(|v| *v)
291 .collect(),
292 )
293}
294
295#[derive(Debug, Reflect)]
296struct Reflection {
297 name: String,
298}
299
300async fn evaluate_function<'a>(
301 function: &FunctionInvocation,
302 context: Context<'a>,
303 config: Option<Arc<Config<'a>>>,
304) -> Result<Context<'a>, FHIRPathError> {
305 match function.name.0.as_str() {
306 "resolve" => Ok(context),
308 "where" => {
309 validate_arguments(&function.arguments, &Cardinality::One)?;
310
311 let where_condition = &function.arguments[0];
312 let mut new_context = vec![];
313 for value in context.values.iter() {
314 let result = evaluate_expression(
315 where_condition,
316 context.new_context_from(vec![*value]),
317 config.clone(),
318 )
319 .await?;
320
321 if result.values.len() > 1 {
322 return Err(FHIRPathError::InternalError(
323 "Where condition did not return a single value".to_string(),
324 ));
325 } else if !result.values.is_empty() && downcast_bool(result.values[0])? == true {
327 new_context.push(*value);
328 }
329 }
330 Ok(context.new_context_from(new_context))
331 }
332 "ofType" => {
333 validate_arguments(&function.arguments, &Cardinality::One)?;
334
335 let type_name = derive_typename(&function.arguments[0])?;
336 Ok(filter_by_type(&type_name, &context))
337 }
338 "count" => {
339 validate_arguments(&function.arguments, &Cardinality::Zero)?;
340
341 let count = context.values.len() as i64;
342 Ok(context.new_context_from(vec![
343 context
344 .allocate(ResolvedValue::Box(Box::new(FHIRInteger {
345 value: Some(count),
346 ..Default::default()
347 })))
348 .await,
349 ]))
350 }
351 op @ ("upper" | "lower") => {
352 validate_arguments(&function.arguments, &Cardinality::Zero)?;
353
354 if context.values.is_empty() {
355 return Ok(context.new_context_from(vec![]));
356 }
357 if context.values.len() > 1 {
358 return Err(FunctionError::InvalidCardinality(
359 op.to_string(),
360 context.values.len(),
361 )
362 .into());
363 }
364
365 let input = downcast_string(context.values[0])?;
366 let transformed = match op {
367 "upper" => input.to_uppercase(),
368 "lower" => input.to_lowercase(),
369 _ => unreachable!(),
370 };
371 Ok(context.new_context_from(vec![
372 context
373 .allocate(ResolvedValue::Box(Box::new(FHIRString {
374 value: Some(transformed),
375 ..Default::default()
376 })))
377 .await,
378 ]))
379 }
380 "as" => {
381 validate_arguments(&function.arguments, &Cardinality::One)?;
382
383 let type_name = derive_typename(&function.arguments[0])?;
384 Ok(filter_by_type(&type_name, &context))
385 }
386 "empty" => {
387 validate_arguments(&function.arguments, &Cardinality::Zero)?;
388 let res = Ok(context.new_context_from(vec![
389 context
390 .allocate(ResolvedValue::Box(Box::new(context.values.is_empty())))
391 .await,
392 ]));
393
394 res
395 }
396 "exists" => {
397 validate_arguments(&function.arguments, &Cardinality::Many)?;
398
399 if function.arguments.len() > 1 {
400 return Err(FunctionError::InvalidCardinality(
401 "exists".to_string(),
402 function.arguments.len(),
403 )
404 .into());
405 }
406
407 let context = if function.arguments.len() == 1 {
408 evaluate_expression(&function.arguments[0], context, config).await?
409 } else {
410 context
411 };
412
413 let res = Ok(context.new_context_from(vec![
414 context
415 .allocate(ResolvedValue::Box(Box::new(!context.values.is_empty())))
416 .await,
417 ]));
418
419 res
420 }
421 "children" => {
422 validate_arguments(&function.arguments, &Cardinality::Zero)?;
423
424 Ok(context.new_context_from(
425 context
426 .values
427 .iter()
428 .flat_map(|value| {
429 let result = value
430 .fields()
431 .iter()
432 .filter_map(|f| value.get_field(f).map(|v| v.flatten()))
433 .flatten()
434 .collect::<Vec<_>>();
435 result
436 })
437 .collect(),
438 ))
439 }
440 "repeat" => {
441 validate_arguments(&function.arguments, &Cardinality::One)?;
442
443 let projection = &function.arguments[0];
444 let mut end_result = vec![];
445 let mut cur = context;
446
447 while cur.values.len() != 0 {
448 cur = evaluate_expression(projection, cur, config.clone()).await?;
449 end_result.extend_from_slice(cur.values.as_slice());
450 }
451
452 Ok(cur.new_context_from(end_result))
453 }
454 "descendants" => {
455 validate_arguments(&function.arguments, &Cardinality::Zero)?;
456
457 let result = evaluate_expression(
459 &Expression::Singular(vec![Term::Invocation(Invocation::Function(
460 FunctionInvocation {
461 name: Identifier("repeat".to_string()),
462 arguments: vec![Expression::Singular(vec![Term::Invocation(
463 Invocation::Function(FunctionInvocation {
464 name: Identifier("children".to_string()),
465 arguments: vec![],
466 }),
467 )])],
468 },
469 ))]),
470 context,
471 config,
472 )
473 .await?;
474
475 Ok(result)
476 }
477 "type" => {
478 validate_arguments(&function.arguments, &Cardinality::Zero)?;
479
480 let mut next_ctx = Vec::with_capacity(context.values.len());
481 for v in context.values.iter() {
482 let type_name = v.typename();
483 next_ctx.push(
484 context
485 .allocate(ResolvedValue::Box(Box::new(Reflection {
486 name: type_name.to_string(),
487 })))
488 .await,
489 );
490 }
491
492 Ok(context.new_context_from(next_ctx))
493 }
494 _ => {
495 return Err(FHIRPathError::NotImplemented(format!(
496 "Function '{}' is not implemented",
497 function.name.0
498 )));
499 }
500 }
501}
502
503fn equal_check<'b>(left: &Context<'b>, right: &Context<'b>) -> Result<bool, FHIRPathError> {
504 if NUMBER_TYPES.contains(left.values[0].typename())
505 && NUMBER_TYPES.contains(right.values[0].typename())
506 {
507 let left_value = downcast_number(left.values[0])?;
508 let right_value = downcast_number(right.values[0])?;
509 Ok(left_value == right_value)
510 } else if STRING_TYPES.contains(left.values[0].typename())
511 && STRING_TYPES.contains(right.values[0].typename())
512 {
513 let left_value = downcast_string(left.values[0])?;
514 let right_value = downcast_string(right.values[0])?;
515 Ok(left_value == right_value)
516 } else if BOOLEAN_TYPES.contains(left.values[0].typename())
517 && BOOLEAN_TYPES.contains(right.values[0].typename())
518 {
519 let left_value = downcast_bool(left.values[0])?;
520 let right_value = downcast_bool(right.values[0])?;
521 Ok(left_value == right_value)
522 } else {
523 Ok(false)
530 }
531}
532
533async fn evaluate_operation<'a>(
534 operation: &Operation,
535 context: Context<'a>,
536 config: Option<Arc<Config<'a>>>,
537) -> Result<Context<'a>, FHIRPathError> {
538 match operation {
539 Operation::Add(left, right) => {
540 operation_2(left, right, context, config, |left, right| {
541 Box::pin(async move {
542 if NUMBER_TYPES.contains(left.values[0].typename())
543 && NUMBER_TYPES.contains(right.values[0].typename())
544 {
545 let left_value = downcast_number(left.values[0])?;
546 let right_value = downcast_number(right.values[0])?;
547 Ok(left.new_context_from(vec![
548 left.allocate(ResolvedValue::Box(Box::new(left_value + right_value)))
549 .await,
550 ]))
551 } else if STRING_TYPES.contains(left.values[0].typename())
552 && STRING_TYPES.contains(right.values[0].typename())
553 {
554 let left_string = downcast_string(left.values[0])?;
555 let right_string = downcast_string(right.values[0])?;
556
557 Ok(left.new_context_from(vec![
558 left.allocate(ResolvedValue::Box(Box::new(
559 left_string + &right_string,
560 )))
561 .await,
562 ]))
563 } else {
564 Err(FHIRPathError::OperationError(OperationError::TypeMismatch(
565 left.values[0].typename(),
566 right.values[0].typename(),
567 )))
568 }
569 })
570 })
571 .await
572 }
573 Operation::Subtraction(left, right) => {
574 operation_2(left, right, context, config, |left, right| {
575 Box::pin(async move {
576 let left_value = downcast_number(left.values[0])?;
577 let right_value = downcast_number(right.values[0])?;
578
579 Ok(left.new_context_from(vec![
580 left.allocate(ResolvedValue::Box(Box::new(left_value - right_value)))
581 .await,
582 ]))
583 })
584 })
585 .await
586 }
587 Operation::Multiplication(left, right) => {
588 operation_2(left, right, context, config, |left, right| {
589 Box::pin(async move {
590 let left_value = downcast_number(left.values[0])?;
591 let right_value = downcast_number(right.values[0])?;
592
593 Ok(left.new_context_from(vec![
594 left.allocate(ResolvedValue::Box(Box::new(left_value * right_value)))
595 .await,
596 ]))
597 })
598 })
599 .await
600 }
601 Operation::Division(left, right) => {
602 operation_2(left, right, context, config, |left, right| {
603 Box::pin(async move {
604 let left_value = downcast_number(left.values[0])?;
605 let right_value = downcast_number(right.values[0])?;
606
607 Ok(left.new_context_from(vec![
608 left.allocate(ResolvedValue::Box(Box::new(left_value / right_value)))
609 .await,
610 ]))
611 })
612 })
613 .await
614 }
615 Operation::Equal(left, right) => {
616 operation_2(left, right, context, config, |left, right| {
617 Box::pin(async move {
618 let are_equal = FHIRBoolean {
619 value: Some(equal_check(&left, &right)?),
620 ..Default::default()
621 };
622 Ok(left.new_context_from(vec![
623 left.allocate(ResolvedValue::Box(Box::new(are_equal))).await,
624 ]))
625 })
626 })
627 .await
628 }
629 Operation::NotEqual(left, right) => {
630 operation_2(left, right, context, config, |left, right| {
631 Box::pin(async move {
632 let not_equal = FHIRBoolean {
633 value: Some(!equal_check(&left, &right)?),
634 ..Default::default()
635 };
636 Ok(left.new_context_from(vec![
637 left.allocate(ResolvedValue::Box(Box::new(not_equal))).await,
638 ]))
639 })
640 })
641 .await
642 }
643 Operation::And(left, right) => {
644 operation_2(left, right, context, config, |left, right| {
645 Box::pin(async move {
646 let left_value = downcast_bool(left.values[0])?;
647 let right_value = downcast_bool(right.values[0])?;
648
649 Ok(left.new_context_from(vec![
650 left.allocate(ResolvedValue::Box(Box::new(FHIRBoolean {
651 value: Some(left_value && right_value),
652 ..Default::default()
653 })))
654 .await,
655 ]))
656 })
657 })
658 .await
659 }
660 Operation::Or(left, right) => {
661 operation_2(left, right, context, config, |left, right| {
662 Box::pin(async move {
663 let left_value = downcast_bool(left.values[0])?;
664 let right_value = downcast_bool(right.values[0])?;
665
666 Ok(left.new_context_from(vec![
667 left.allocate(ResolvedValue::Box(Box::new(FHIRBoolean {
668 value: Some(left_value || right_value),
669 ..Default::default()
670 })))
671 .await,
672 ]))
673 })
674 })
675 .await
676 }
677 Operation::Union(left, right) => {
678 operation_n(left, right, context, config, |left, right| {
679 let mut union = vec![];
680 union.extend(left.values.iter());
681 union.extend(right.values.iter());
682 Ok(left.new_context_from(union))
683 })
684 .await
685 }
686 Operation::Modulo(_, _) => Err(FHIRPathError::NotImplemented("Modulo".to_string())),
687 Operation::Is(expression, type_name) => {
688 let left = evaluate_expression(expression, context, config).await?;
689 if left.values.len() > 1 {
690 Err(FHIRPathError::OperationError(
691 OperationError::InvalidCardinality,
692 ))
693 } else {
694 if let Some(type_name) = type_name.0.get(0).as_ref().map(|k| &k.0) {
695 let next_context = filter_by_type(&type_name, &left);
696 Ok(left.new_context_from(vec![
697 left.allocate(ResolvedValue::Box(Box::new(
698 !next_context.values.is_empty(),
699 )))
700 .await,
701 ]))
702 } else {
703 Ok(left.new_context_from(vec![]))
704 }
705 }
706 }
707 Operation::As(expression, type_name) => {
708 let left = evaluate_expression(expression, context, config).await?;
709 if left.values.len() > 1 {
710 Err(FHIRPathError::OperationError(
711 OperationError::InvalidCardinality,
712 ))
713 } else {
714 if let Some(type_name) = type_name.0.get(0).as_ref().map(|k| &k.0) {
715 Ok(filter_by_type(&type_name, &left))
716 } else {
717 Ok(left.new_context_from(vec![]))
718 }
719 }
720 }
721 Operation::Polarity(_, _) => Err(FHIRPathError::NotImplemented("Polarity".to_string())),
722 Operation::DivisionTruncated(_, _) => Err(FHIRPathError::NotImplemented(
723 "DivisionTruncated".to_string(),
724 )),
725 Operation::LessThan(_, _) => Err(FHIRPathError::NotImplemented("LessThan".to_string())),
726 Operation::GreaterThan(_, _) => {
727 Err(FHIRPathError::NotImplemented("GreaterThan".to_string()))
728 }
729 Operation::LessThanEqual(_, _) => {
730 Err(FHIRPathError::NotImplemented("LessThanEqual".to_string()))
731 }
732 Operation::GreaterThanEqual(_, _) => Err(FHIRPathError::NotImplemented(
733 "GreaterThanEqual".to_string(),
734 )),
735 Operation::Equivalent(_, _) => Err(FHIRPathError::NotImplemented("Equivalent".to_string())),
736
737 Operation::NotEquivalent(_, _) => {
738 Err(FHIRPathError::NotImplemented("NotEquivalent".to_string()))
739 }
740 Operation::In(_left, _right) => Err(FHIRPathError::NotImplemented("In".to_string())),
741 Operation::Contains(_left, _right) => {
742 Err(FHIRPathError::NotImplemented("Contains".to_string()))
743 }
744 Operation::XOr(left, right) => {
745 operation_2(left, right, context, config, |left, right| {
746 Box::pin(async move {
747 let left_value = downcast_bool(left.values[0])?;
748 let right_value = downcast_bool(right.values[0])?;
749
750 Ok(left.new_context_from(vec![
751 left.allocate(ResolvedValue::Box(Box::new(FHIRBoolean {
752 value: Some(left_value ^ right_value),
753 ..Default::default()
754 })))
755 .await,
756 ]))
757 })
758 })
759 .await
760 }
761 Operation::Implies(_left, _right) => {
762 Err(FHIRPathError::NotImplemented("Implies".to_string()))
763 }
764 }
765}
766
767fn evaluate_expression<'a>(
768 ast: &Expression,
769 context: Context<'a>,
770 config: Option<Arc<Config<'a>>>,
771) -> Pin<Box<impl Future<Output = Result<Context<'a>, FHIRPathError>>>> {
772 Box::pin(async move {
773 match ast {
774 Expression::Operation(operation) => {
775 evaluate_operation(operation, context, config).await
776 }
777 Expression::Singular(singular_ast) => {
778 evaluate_singular(singular_ast, context, config).await
779 }
780 }
781 })
782}
783
784#[derive(Debug)]
785pub enum ResolvedValue {
786 Box(Box<dyn MetaValue>),
787 Arc(Arc<dyn MetaValue>),
788}
789
790struct Allocator<'a> {
792 pub context: Vec<ResolvedValue>,
793 _marker: PhantomData<&'a dyn MetaValue>,
794}
795
796impl<'a> Allocator<'a> {
797 pub fn new() -> Self {
798 Allocator {
799 context: Vec::new(),
800 _marker: PhantomData,
801 }
802 }
803
804 pub fn allocate(&mut self, value: ResolvedValue) -> &'a dyn MetaValue {
805 self.context.push(value);
806
807 let ptr = match &self.context.last().unwrap() {
809 ResolvedValue::Box(b) => &**b as *const _,
810 ResolvedValue::Arc(a) => &**a,
811 };
812
813 unsafe { &*ptr }
814 }
815}
816
817pub struct Context<'a> {
818 allocator: Arc<Mutex<Allocator<'a>>>,
819 values: Vec<&'a dyn MetaValue>,
820}
821
822pub enum ExternalConstantResolver<'a> {
823 Function(
824 Box<
825 dyn Fn(String) -> Pin<Box<dyn Future<Output = Option<ResolvedValue>> + Send>>
826 + Send
827 + Sync,
828 >,
829 ),
830 Variable(HashMap<String, &'a dyn MetaValue>),
831}
832
833pub struct Config<'a> {
834 pub variable_resolver: Option<ExternalConstantResolver<'a>>,
835}
836
837async fn resolve_external_constant<'a>(
838 name: &str,
839 resolver: Option<&ExternalConstantResolver<'a>>,
840 context: Context<'a>,
841) -> Result<Context<'a>, FHIRPathError> {
842 let external_constant = match resolver {
843 Some(ExternalConstantResolver::Function(func)) => {
844 let result = func(name.to_string()).await;
845
846 if let Some(result) = result {
847 Some(context.allocate(result).await)
848 } else {
849 None
850 }
851 }
852 Some(ExternalConstantResolver::Variable(map)) => map.get(name).map(|s| *s),
853 None => None,
854 };
855
856 if let Some(result) = external_constant {
857 return Ok(context.new_context_from(vec![result]));
858 } else {
859 return Ok(context.new_context_from(vec![]));
860 }
861}
862
863impl<'a> Context<'a> {
864 fn new(values: Vec<&'a dyn MetaValue>, allocator: Arc<Mutex<Allocator<'a>>>) -> Self {
865 Self {
866 allocator,
867 values: values,
868 }
869 }
870 fn new_context_from(&self, values: Vec<&'a dyn MetaValue>) -> Self {
871 Self {
872 allocator: self.allocator.clone(),
873 values: values,
874 }
875 }
876 async fn allocate(&self, value: ResolvedValue) -> &'a dyn MetaValue {
877 self.allocator.lock().await.allocate(value)
878 }
879 pub fn iter(&'a self) -> Box<dyn Iterator<Item = &'a dyn MetaValue> + 'a> {
880 Box::new(self.values.iter().map(|v| *v))
881 }
882}
883
884impl Clone for Context<'_> {
885 fn clone(&self) -> Self {
886 Self {
887 allocator: self.allocator.clone(),
888 values: self.values.clone(),
889 }
890 }
891}
892
893pub struct FPEngine {}
894
895static AST: LazyLock<Arc<DashMap<String, Expression>>> = LazyLock::new(|| Arc::new(DashMap::new()));
896
897fn get_ast(
898 path: &str,
899) -> Result<dashmap::mapref::one::Ref<'static, String, Expression>, FHIRPathError> {
900 let ast: dashmap::mapref::one::Ref<'_, String, Expression> =
901 if let Some(expression_ast) = AST.get(path) {
902 expression_ast
903 } else {
904 AST.insert(path.to_string(), parser::parse(path)?);
905 let expression_ast = AST.get(path).ok_or_else(|| {
906 FHIRPathError::InternalError("Failed to find path post insert".to_string())
907 })?;
908 expression_ast
909 };
910
911 Ok(ast)
912}
913
914impl FPEngine {
915 pub fn new() -> Self {
916 Self {}
917 }
918
919 pub async fn evaluate<'a, 'b>(
924 &self,
925 path: &str,
926 values: Vec<&'a dyn MetaValue>,
927 ) -> Result<Context<'b>, FHIRPathError>
928 where
929 'a: 'b,
930 {
931 let ast = get_ast(path)?;
932
933 let allocator: Arc<Mutex<Allocator<'b>>> = Arc::new(Mutex::new(Allocator::new()));
935
936 let context = Context::new(values, allocator.clone());
937
938 let result = evaluate_expression(&ast, context, None).await?;
939 Ok(result)
940 }
941
942 pub async fn evaluate_with_config<'a, 'b>(
948 &self,
949 path: &str,
950 values: Vec<&'a dyn MetaValue>,
951 config: Arc<Config<'b>>,
952 ) -> Result<Context<'b>, FHIRPathError>
953 where
954 'a: 'b,
955 {
956 let ast = get_ast(path)?;
957
958 let allocator: Arc<Mutex<Allocator<'b>>> = Arc::new(Mutex::new(Allocator::new()));
960
961 let context = Context::new(values, allocator.clone());
962
963 let result = evaluate_expression(&ast, context, Some(config)).await?;
964
965 Ok(result)
966 }
967}
968
969#[cfg(test)]
970mod tests {
971 use super::*;
972 use haste_fhir_model::r4::{
973 datetime::DateTime,
974 generated::{
975 resources::{
976 Bundle, Patient, PatientDeceasedTypeChoice, PatientLink, Resource, SearchParameter,
977 },
978 types::{
979 Extension, ExtensionValueTypeChoice, FHIRDateTime, FHIRString, FHIRUri, HumanName,
980 Identifier, Reference,
981 },
982 },
983 };
984 use haste_fhir_serialization_json;
985 use haste_reflect_derive::Reflect;
986
987 #[derive(Reflect, Debug)]
988 struct C {
989 c: String,
990 }
991
992 #[derive(Reflect, Debug)]
993 struct B {
994 b: Vec<Box<C>>,
995 }
996
997 #[derive(Reflect, Debug)]
998 struct A {
999 a: Vec<Box<B>>,
1000 }
1001
1002 fn load_search_parameters() -> Vec<SearchParameter> {
1003 let json =
1004 include_str!("../../artifacts/artifacts/r4/hl7/minified/search-parameters.min.json");
1005 let bundle = haste_fhir_serialization_json::from_str::<Bundle>(json).unwrap();
1006
1007 let search_parameters: Vec<SearchParameter> = bundle
1008 .entry
1009 .unwrap_or_else(|| Vec::new())
1010 .into_iter()
1011 .map(|e| e.resource)
1012 .filter(|e| e.is_some())
1013 .filter_map(|e| match e {
1014 Some(k) => match *k {
1015 Resource::SearchParameter(sp) => Some(sp),
1016 _ => None,
1017 },
1018 _ => None,
1019 })
1020 .collect();
1021
1022 search_parameters
1023 }
1024
1025 #[tokio::test]
1026 async fn filter_typechoice_test() {
1027 let patient = Patient {
1028 id: Some("patient-id".to_string()),
1029 deceased: Some(PatientDeceasedTypeChoice::Boolean(Box::new(FHIRBoolean {
1030 value: Some(true),
1031 ..Default::default()
1032 }))),
1033 ..Default::default()
1034 };
1035
1036 let engine = FPEngine::new();
1037 let result = engine
1038 .evaluate("(Patient.deceased.ofType(dateTime))", vec![&patient])
1039 .await
1040 .unwrap();
1041
1042 assert_eq!(result.values.len(), 0);
1043
1044 let result = engine
1045 .evaluate("(Patient.deceased.ofType(boolean))", vec![&patient])
1046 .await
1047 .unwrap();
1048
1049 let value = result.values[0];
1050 let boolean_value: &FHIRBoolean = value
1051 .as_any()
1052 .downcast_ref::<FHIRBoolean>()
1053 .expect("Failed to downcast to FHIRBoolean");
1054
1055 assert_eq!(boolean_value.value, Some(true));
1056
1057 let patient = Patient {
1058 id: Some("patient-id".to_string()),
1059 deceased: Some(PatientDeceasedTypeChoice::DateTime(Box::new(
1060 FHIRDateTime {
1061 value: Some(DateTime::Year(1980)),
1062 ..Default::default()
1063 },
1064 ))),
1065 ..Default::default()
1066 };
1067
1068 let result = engine
1069 .evaluate("(Patient.deceased.ofType(boolean))", vec![&patient])
1070 .await
1071 .unwrap();
1072
1073 assert_eq!(result.values.len(), 0);
1074
1075 let result = engine
1076 .evaluate("(Patient.deceased.ofType(dateTime))", vec![&patient])
1077 .await
1078 .unwrap();
1079
1080 assert_eq!(result.values.len(), 1);
1081
1082 let value = result.values[0];
1083 let datetime_value: &FHIRDateTime = value
1084 .as_any()
1085 .downcast_ref::<FHIRDateTime>()
1086 .expect("Failed to downcast to FHIRDateTime");
1087
1088 assert_eq!(datetime_value.value, Some(DateTime::Year(1980)));
1089 }
1090
1091 #[tokio::test]
1092 async fn test_variable_resolution() {
1093 let engine = FPEngine::new();
1094 let patient = Patient {
1095 id: Some("my-patient".to_string()),
1096 ..Default::default()
1097 };
1098 let config = Arc::new(Config {
1099 variable_resolver: Some(ExternalConstantResolver::Variable(
1100 vec![("patient".to_string(), &patient as &dyn MetaValue)]
1101 .into_iter()
1102 .collect(),
1103 )),
1104 });
1105
1106 let result = engine
1107 .evaluate_with_config("%patient", vec![], config.clone())
1108 .await
1109 .unwrap();
1110
1111 assert_eq!(result.values.len(), 1);
1112 let p = result.values[0].as_any().downcast_ref::<Patient>().unwrap();
1113
1114 assert_eq!(p.id, patient.id);
1115
1116 let result_failed = engine
1117 .evaluate_with_config("%nobody", vec![], config)
1118 .await
1119 .unwrap();
1120
1121 assert_eq!(result_failed.values.len(), 0);
1122 }
1123
1124 #[tokio::test]
1125 async fn test_where_clause() {
1126 let engine = FPEngine::new();
1127 let mut patient = Patient::default();
1128 let mut identifier = Identifier::default();
1129 let extension = Extension {
1130 id: None,
1131 url: "test-extension".to_string(),
1132 extension: None,
1133 value: Some(ExtensionValueTypeChoice::String(Box::new(FHIRString {
1134 id: None,
1135 extension: None,
1136 value: Some("example value".to_string()),
1137 }))),
1138 };
1139 identifier.value = Some(Box::new(FHIRString {
1140 id: None,
1141 extension: Some(vec![Box::new(extension)]),
1142 value: Some("12345".to_string()),
1143 }));
1144 patient.identifier_ = Some(vec![Box::new(identifier)]);
1145
1146 let context = engine
1147 .evaluate(
1148 "$this.identifier.value.where($this.extension.value.exists())",
1149 vec![&patient],
1150 )
1151 .await;
1152
1153 assert_eq!(context.unwrap().values.len(), 1);
1154
1155 let context = engine
1156 .evaluate(
1157 "$this.identifier.value.where($this.extension.extension.exists())",
1158 vec![&patient],
1159 )
1160 .await;
1161 assert_eq!(context.unwrap().values.len(), 0);
1162 }
1163
1164 #[tokio::test]
1165 async fn test_all_parameters() {
1166 let search_parameters = load_search_parameters();
1167 for param in search_parameters.iter() {
1168 if let Some(expression) = ¶m.expression {
1169 let engine = FPEngine::new();
1170 let context = engine
1171 .evaluate(expression.value.as_ref().unwrap().as_str(), vec![])
1172 .await;
1173
1174 if let Err(err) = context {
1175 panic!(
1176 "Failed to evaluate search parameter '{}': {}",
1177 expression.value.as_ref().unwrap(),
1178 err
1179 );
1180 }
1181 }
1182 }
1183 }
1184
1185 fn test_patient() -> Patient {
1186 let mut patient = Patient::default();
1187 let mut name = HumanName::default();
1188 name.given = Some(vec![Box::new(FHIRString {
1189 id: None,
1190 extension: None,
1191 value: Some("Bob".to_string()),
1192 })]);
1193
1194 let mut mrn_identifier = Identifier::default();
1195 mrn_identifier.value = Some(Box::new(FHIRString {
1196 id: None,
1197 extension: None,
1198 value: Some("mrn-12345".to_string()),
1199 }));
1200 mrn_identifier.system = Some(Box::new(FHIRUri {
1201 id: None,
1202 extension: None,
1203 value: Some("mrn".to_string()),
1204 }));
1205
1206 let mut ssn_identifier = Identifier::default();
1207 ssn_identifier.value = Some(Box::new(FHIRString {
1208 id: None,
1209 extension: None,
1210 value: Some("ssn-12345".to_string()),
1211 }));
1212 ssn_identifier.system = Some(Box::new(FHIRUri {
1213 id: None,
1214 extension: None,
1215 value: Some("ssn".to_string()),
1216 }));
1217
1218 mrn_identifier.system = Some(Box::new(FHIRUri {
1219 id: None,
1220 extension: None,
1221 value: Some("mrn".to_string()),
1222 }));
1223
1224 patient.identifier_ = Some(vec![Box::new(mrn_identifier), Box::new(ssn_identifier)]);
1225 patient.name = Some(vec![Box::new(name)]);
1226 patient
1227 }
1228
1229 #[tokio::test]
1230 async fn indexing_tests() {
1231 let engine = FPEngine::new();
1232 let patient = test_patient();
1233
1234 let given_name = engine
1235 .evaluate("$this.name.given[0]", vec![&patient])
1236 .await
1237 .unwrap();
1238
1239 assert_eq!(given_name.values.len(), 1);
1240 let value = given_name.values[0];
1241 let name: &FHIRString = value
1242 .as_any()
1243 .downcast_ref::<FHIRString>()
1244 .expect("Failed to downcast to FHIRString");
1245
1246 assert_eq!(name.value.as_deref(), Some("Bob"));
1247
1248 let ssn_identifier = engine
1249 .evaluate("$this.identifier[1]", vec![&patient])
1250 .await
1251 .unwrap();
1252
1253 assert_eq!(ssn_identifier.values.len(), 1);
1254 let value = ssn_identifier.values[0];
1255 let identifier: &Identifier = value
1256 .as_any()
1257 .downcast_ref::<Identifier>()
1258 .expect("Failed to downcast to Identifier");
1259
1260 assert_eq!(
1261 identifier.value.as_ref().unwrap().value.as_deref(),
1262 Some("ssn-12345")
1263 );
1264
1265 let all_identifiers = engine
1266 .evaluate("$this.identifier", vec![&patient])
1267 .await
1268 .unwrap();
1269 assert_eq!(all_identifiers.values.len(), 2);
1270 }
1271
1272 #[tokio::test]
1273 async fn where_testing() {
1274 let engine = FPEngine::new();
1275 let patient = test_patient();
1276
1277 let name_where_clause = engine
1278 .evaluate(
1279 "$this.name.given.where($this.value = 'Bob')",
1280 vec![&patient],
1281 )
1282 .await
1283 .unwrap();
1284
1285 assert_eq!(name_where_clause.values.len(), 1);
1286 let value = name_where_clause.values[0];
1287 let name: &FHIRString = value
1288 .as_any()
1289 .downcast_ref::<FHIRString>()
1290 .expect("Failed to downcast to FHIRString");
1291
1292 assert_eq!(name.value.as_deref(), Some("Bob"));
1293
1294 let ssn_identifier_clause = engine
1295 .evaluate(
1296 "$this.identifier.where($this.system.value = 'ssn')",
1297 vec![&patient],
1298 )
1299 .await
1300 .unwrap();
1301 assert_eq!(ssn_identifier_clause.values.len(), 1);
1302
1303 let ssn_identifier = ssn_identifier_clause.values[0]
1304 .as_any()
1305 .downcast_ref::<Identifier>()
1306 .expect("Failed to downcast to Identifier");
1307
1308 assert_eq!(
1309 ssn_identifier.value.as_ref().unwrap().value.as_deref(),
1310 Some("ssn-12345")
1311 );
1312 }
1313
1314 #[tokio::test]
1315 async fn test_equality() {
1316 let engine = FPEngine::new();
1317
1318 let string_equal = engine.evaluate("'test' = 'test'", vec![]).await.unwrap();
1320 for r in string_equal.iter() {
1321 let b: bool = r
1322 .as_any()
1323 .downcast_ref::<FHIRBoolean>()
1324 .unwrap()
1325 .value
1326 .unwrap()
1327 .clone();
1328 assert_eq!(b, true);
1329 }
1330 let string_unequal = engine.evaluate("'invalid' = 'test'", vec![]).await.unwrap();
1331 for r in string_unequal.iter() {
1332 let b: bool = r
1333 .as_any()
1334 .downcast_ref::<FHIRBoolean>()
1335 .unwrap()
1336 .value
1337 .unwrap()
1338 .clone();
1339 assert_eq!(b, false);
1340 }
1341
1342 let number_equal = engine.evaluate("12 = 12", vec![]).await.unwrap();
1344 for r in number_equal.iter() {
1345 let b: bool = r
1346 .as_any()
1347 .downcast_ref::<FHIRBoolean>()
1348 .unwrap()
1349 .value
1350 .unwrap()
1351 .clone();
1352 assert_eq!(b, true);
1353 }
1354 let number_unequal = engine.evaluate("13 = 12", vec![]).await.unwrap();
1355 for r in number_unequal.iter() {
1356 let b: bool = r
1357 .as_any()
1358 .downcast_ref::<FHIRBoolean>()
1359 .unwrap()
1360 .value
1361 .unwrap()
1362 .clone();
1363 assert_eq!(b, false);
1364 }
1365
1366 let bool_equal = engine.evaluate("false = false", vec![]).await.unwrap();
1368 for r in bool_equal.iter() {
1369 let b: bool = r
1370 .as_any()
1371 .downcast_ref::<FHIRBoolean>()
1372 .unwrap()
1373 .value
1374 .unwrap()
1375 .clone();
1376 assert_eq!(b, true);
1377 }
1378 let bool_unequal = engine.evaluate("false = true", vec![]).await.unwrap();
1379 for r in bool_unequal.iter() {
1380 let b: bool = r
1381 .as_any()
1382 .downcast_ref::<FHIRBoolean>()
1383 .unwrap()
1384 .value
1385 .unwrap()
1386 .clone();
1387 assert_eq!(b, false);
1388 }
1389
1390 let bool_equal = engine.evaluate("12 = 13 = false", vec![]).await.unwrap();
1392 for r in bool_equal.iter() {
1393 let b: bool = r
1394 .as_any()
1395 .downcast_ref::<FHIRBoolean>()
1396 .unwrap()
1397 .value
1398 .unwrap()
1399 .clone();
1400 assert_eq!(b, true);
1401 }
1402 let bool_unequal = engine.evaluate("12 = 13 = true", vec![]).await.unwrap();
1403 for r in bool_unequal.iter() {
1404 let b: bool = r
1405 .as_any()
1406 .downcast_ref::<FHIRBoolean>()
1407 .unwrap()
1408 .value
1409 .unwrap()
1410 .clone();
1411 assert_eq!(b, false);
1412 }
1413 let bool_unequal = engine.evaluate("12 = (13 - 1)", vec![]).await.unwrap();
1414 for r in bool_unequal.iter() {
1415 let b: bool = r
1416 .as_any()
1417 .downcast_ref::<FHIRBoolean>()
1418 .unwrap()
1419 .value
1420 .unwrap()
1421 .clone();
1422
1423 assert_eq!(b, true);
1424 }
1425 }
1426
1427 #[tokio::test]
1428 async fn test_string_concat() {
1429 let engine = FPEngine::new();
1430 let patient = test_patient();
1431
1432 let simple_result = engine.evaluate("'Hello' + ' World'", vec![]).await.unwrap();
1433 for r in simple_result.iter() {
1434 let s: String = r.as_any().downcast_ref::<String>().unwrap().clone();
1435 assert_eq!(s, "Hello World".to_string());
1436 }
1437
1438 let simple_result = engine
1439 .evaluate("$this.name.given + ' Miller'", vec![&patient])
1440 .await
1441 .unwrap();
1442 for r in simple_result.iter() {
1443 let s: String = r.as_any().downcast_ref::<String>().unwrap().clone();
1444 assert_eq!(s, "Bob Miller".to_string());
1445 }
1446 }
1447
1448 #[tokio::test]
1449 async fn test_simple() {
1450 let root = A {
1451 a: vec![Box::new(B {
1452 b: vec![Box::new(C {
1453 c: "whatever".to_string(),
1454 })],
1455 })],
1456 };
1457
1458 let engine = FPEngine::new();
1459 let result = engine.evaluate("a.b.c", vec![&root]).await.unwrap();
1460
1461 let strings: Vec<&String> = result
1462 .iter()
1463 .map(|r| r.as_any().downcast_ref::<String>().unwrap())
1464 .collect();
1465
1466 assert_eq!(strings, vec!["whatever"]);
1467 }
1468
1469 #[tokio::test]
1470 async fn allocation() {
1471 let engine = FPEngine::new();
1472 let result = engine.evaluate("'asdf'", vec![]).await.unwrap();
1473
1474 for r in result.iter() {
1475 let s = r.as_any().downcast_ref::<FHIRString>().unwrap().clone();
1476
1477 assert_eq!(s.value, Some("asdf".to_string()));
1478 }
1479 }
1480
1481 #[tokio::test]
1482 async fn order_operation() {
1483 let engine = FPEngine::new();
1484 let result = engine.evaluate("45 + 2 * 3", vec![]).await.unwrap();
1485
1486 for r in result.iter() {
1487 let s = r.as_any().downcast_ref::<f64>().unwrap().clone();
1488
1489 assert_eq!(s, 51.0);
1490 }
1491 }
1492
1493 #[tokio::test]
1494 async fn xor_operation() {
1495 let engine = FPEngine::new();
1496 let result = engine.evaluate("true xor true", vec![]).await.unwrap();
1497
1498 for r in result.iter() {
1499 let b: bool = r
1500 .as_any()
1501 .downcast_ref::<FHIRBoolean>()
1502 .unwrap()
1503 .value
1504 .unwrap()
1505 .clone();
1506
1507 assert_eq!(b, false);
1508 }
1509 }
1510
1511 #[tokio::test]
1512 async fn domain_resource_filter() {
1513 let engine = FPEngine::new();
1514
1515 let patient = haste_fhir_serialization_json::from_str::<Resource>(
1516 r#"{"id": "patient-id", "resourceType": "Patient"}"#,
1517 )
1518 .unwrap();
1519 let result = engine
1520 .evaluate("Resource.id", vec![&patient])
1521 .await
1522 .unwrap();
1523 let ids: Vec<&String> = result
1524 .iter()
1525 .map(|r| r.as_any().downcast_ref::<String>().unwrap())
1526 .collect();
1527
1528 assert_eq!(ids.len(), 1);
1529 assert_eq!(ids[0], "patient-id");
1530
1531 let result2 = engine
1532 .evaluate("DomainResource.id", vec![&patient])
1533 .await
1534 .unwrap();
1535 let ids2: Vec<&String> = result2
1536 .iter()
1537 .map(|r| r.as_any().downcast_ref::<String>().unwrap())
1538 .collect();
1539 assert_eq!(ids2.len(), 1);
1540 assert_eq!(ids2[0], "patient-id");
1541 }
1542
1543 #[tokio::test]
1544 async fn type_test() {
1545 let engine = FPEngine::new();
1546 let patient = Patient::default();
1547
1548 let result = engine
1549 .evaluate("$this.type().name", vec![&patient])
1550 .await
1551 .unwrap();
1552 let ids: Vec<&String> = result
1553 .iter()
1554 .map(|r| r.as_any().downcast_ref::<String>().unwrap())
1555 .collect();
1556
1557 assert_eq!(ids.len(), 1);
1558 assert_eq!(ids[0], "Patient");
1559 }
1560
1561 #[tokio::test]
1562 async fn resolve_test() {
1563 let engine = FPEngine::new();
1564 let observation = haste_fhir_serialization_json::from_str::<Resource>(r#"
1565 {
1566 "resourceType": "Observation",
1567 "id": "f001",
1568 "text": {
1569 "status": "generated",
1570 "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Generated Narrative with Details</b></p><p><b>id</b>: f001</p><p><b>identifier</b>: 6323 (OFFICIAL)</p><p><b>status</b>: final</p><p><b>code</b>: Glucose [Moles/volume] in Blood <span>(Details : {LOINC code '15074-8' = 'Glucose [Moles/volume] in Blood', given as 'Glucose [Moles/volume] in Blood'})</span></p><p><b>subject</b>: <a>P. van de Heuvel</a></p><p><b>effective</b>: 02/04/2013 9:30:10 AM --> (ongoing)</p><p><b>issued</b>: 03/04/2013 3:30:10 PM</p><p><b>performer</b>: <a>A. Langeveld</a></p><p><b>value</b>: 6.3 mmol/l<span> (Details: UCUM code mmol/L = 'mmol/L')</span></p><p><b>interpretation</b>: High <span>(Details : {http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation code 'H' = 'High', given as 'High'})</span></p><h3>ReferenceRanges</h3><table><tr><td>-</td><td><b>Low</b></td><td><b>High</b></td></tr><tr><td>*</td><td>3.1 mmol/l<span> (Details: UCUM code mmol/L = 'mmol/L')</span></td><td>6.2 mmol/l<span> (Details: UCUM code mmol/L = 'mmol/L')</span></td></tr></table></div>"
1571 },
1572 "identifier": [
1573 {
1574 "use": "official",
1575 "system": "http://www.bmc.nl/zorgportal/identifiers/observations",
1576 "value": "6323"
1577 }
1578 ],
1579 "status": "final",
1580 "code": {
1581 "coding": [
1582 {
1583 "system": "http://loinc.org",
1584 "code": "15074-8",
1585 "display": "Glucose [Moles/volume] in Blood"
1586 }
1587 ]
1588 },
1589 "subject": {
1590 "reference": "Patient/f001",
1591 "display": "P. van de Heuvel"
1592 },
1593 "effectivePeriod": {
1594 "start": "2013-04-02T09:30:10+01:00"
1595 },
1596 "issued": "2013-04-03T15:30:10+01:00",
1597 "performer": [
1598 {
1599 "reference": "Practitioner/f005",
1600 "display": "A. Langeveld"
1601 }
1602 ],
1603 "valueQuantity": {
1604 "value": 6.3,
1605 "unit": "mmol/l",
1606 "system": "http://unitsofmeasure.org",
1607 "code": "mmol/L"
1608 },
1609 "interpretation": [
1610 {
1611 "coding": [
1612 {
1613 "system": "http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation",
1614 "code": "H",
1615 "display": "High"
1616 }
1617 ]
1618 }
1619 ],
1620 "referenceRange": [
1621 {
1622 "low": {
1623 "value": 3.1,
1624 "unit": "mmol/l",
1625 "system": "http://unitsofmeasure.org",
1626 "code": "mmol/L"
1627 },
1628 "high": {
1629 "value": 6.2,
1630 "unit": "mmol/l",
1631 "system": "http://unitsofmeasure.org",
1632 "code": "mmol/L"
1633 }
1634 }
1635 ]
1636 }
1637 "#).unwrap();
1638
1639 let result = engine
1640 .evaluate(
1641 "Observation.subject.where(resolve() is Patient)",
1642 vec![&observation],
1643 )
1644 .await
1645 .unwrap();
1646
1647 let references: Vec<&Reference> = result
1648 .iter()
1649 .map(|r| r.as_any().downcast_ref::<Reference>().unwrap())
1650 .collect();
1651
1652 assert_eq!(references.len(), 1);
1653 assert_eq!(
1654 references[0].reference.as_ref().unwrap().value,
1655 Some("Patient/f001".to_string())
1656 );
1657 }
1658
1659 #[tokio::test]
1660 async fn children_test() {
1661 let engine = FPEngine::new();
1662 let patient = Patient {
1663 name: Some(vec![Box::new(HumanName {
1664 given: Some(vec![Box::new(FHIRString {
1665 value: Some("Alice".to_string()),
1666 ..Default::default()
1667 })]),
1668 ..Default::default()
1669 })]),
1670 deceased: Some(PatientDeceasedTypeChoice::Boolean(Box::new(FHIRBoolean {
1671 value: Some(true),
1672 ..Default::default()
1673 }))),
1674 ..Default::default()
1675 };
1676
1677 let result = engine
1678 .evaluate("$this.children()", vec![&patient])
1679 .await
1680 .unwrap();
1681
1682 assert_eq!(result.values.len(), 2);
1683 assert_eq!(
1684 result
1685 .values
1686 .iter()
1687 .map(|v| v.typename())
1688 .collect::<Vec<_>>(),
1689 vec!["HumanName", "FHIRBoolean"]
1690 );
1691 }
1692
1693 #[tokio::test]
1694 async fn repeat_test() {
1695 let engine = FPEngine::new();
1696 let patient = Patient {
1697 name: Some(vec![Box::new(HumanName {
1698 given: Some(vec![Box::new(FHIRString {
1699 value: Some("Alice".to_string()),
1700 ..Default::default()
1701 })]),
1702 ..Default::default()
1703 })]),
1704 deceased: Some(PatientDeceasedTypeChoice::Boolean(Box::new(FHIRBoolean {
1705 value: Some(true),
1706 ..Default::default()
1707 }))),
1708 ..Default::default()
1709 };
1710
1711 let result = engine
1712 .evaluate("$this.name.given", vec![&patient])
1713 .await
1714 .unwrap();
1715
1716 assert_eq!(result.values.len(), 1);
1717
1718 assert_eq!(result.values[0].typename(), "FHIRString");
1719
1720 let result = engine
1721 .evaluate("$this.repeat(children())", vec![&patient])
1722 .await
1723 .unwrap();
1724
1725 assert_eq!(
1726 result
1727 .values
1728 .iter()
1729 .map(|v| v.typename())
1730 .collect::<Vec<_>>(),
1731 vec![
1732 "HumanName",
1733 "FHIRBoolean",
1734 "FHIRString",
1735 "http://hl7.org/fhirpath/System.Boolean",
1736 "http://hl7.org/fhirpath/System.String"
1737 ]
1738 );
1739 }
1740 #[tokio::test]
1741 async fn descendants_test() {
1742 let engine = FPEngine::new();
1743 let patient = Patient {
1744 name: Some(vec![Box::new(HumanName {
1745 given: Some(vec![Box::new(FHIRString {
1746 value: Some("Alice".to_string()),
1747 ..Default::default()
1748 })]),
1749 ..Default::default()
1750 })]),
1751 deceased: Some(PatientDeceasedTypeChoice::Boolean(Box::new(FHIRBoolean {
1752 value: Some(true),
1753 ..Default::default()
1754 }))),
1755 ..Default::default()
1756 };
1757 let result = engine
1758 .evaluate("descendants()", vec![&patient])
1759 .await
1760 .unwrap();
1761
1762 assert_eq!(
1763 result
1764 .values
1765 .iter()
1766 .map(|v| v.typename())
1767 .collect::<Vec<_>>(),
1768 vec![
1769 "HumanName",
1770 "FHIRBoolean",
1771 "FHIRString",
1772 "http://hl7.org/fhirpath/System.Boolean",
1773 "http://hl7.org/fhirpath/System.String"
1774 ]
1775 );
1776 }
1777
1778 #[tokio::test]
1779 async fn descendants_test_filter() {
1780 let engine = FPEngine::new();
1781 let patient = Patient {
1782 link: Some(vec![PatientLink {
1783 other: Box::new(Reference {
1784 reference: Some(Box::new(FHIRString {
1785 value: Some("Patient/123".to_string()),
1786 ..Default::default()
1787 })),
1788 ..Default::default()
1789 }),
1790 ..Default::default()
1791 }]),
1792 name: Some(vec![Box::new(HumanName {
1793 given: Some(vec![Box::new(FHIRString {
1794 value: Some("Alice".to_string()),
1795 ..Default::default()
1796 })]),
1797 ..Default::default()
1798 })]),
1799 deceased: Some(PatientDeceasedTypeChoice::Boolean(Box::new(FHIRBoolean {
1800 value: Some(true),
1801 ..Default::default()
1802 }))),
1803 ..Default::default()
1804 };
1805 let result = engine
1806 .evaluate("descendants()", vec![&patient])
1807 .await
1808 .unwrap();
1809
1810 assert_eq!(
1811 result
1812 .values
1813 .iter()
1814 .map(|v| v.typename())
1815 .collect::<Vec<_>>(),
1816 vec![
1817 "HumanName",
1818 "FHIRBoolean",
1819 "PatientLink",
1820 "FHIRString",
1821 "http://hl7.org/fhirpath/System.Boolean",
1822 "Reference",
1823 "http://hl7.org/fhirpath/System.String",
1824 "FHIRString",
1825 "http://hl7.org/fhirpath/System.String"
1826 ]
1827 );
1828
1829 let result = engine
1830 .evaluate("descendants().ofType(Reference)", vec![&patient])
1831 .await
1832 .unwrap();
1833
1834 assert_eq!(
1835 result
1836 .values
1837 .iter()
1838 .map(|v| v.typename())
1839 .collect::<Vec<_>>(),
1840 vec!["Reference",]
1841 );
1842
1843 let value = result.values[0]
1844 .as_any()
1845 .downcast_ref::<Reference>()
1846 .unwrap();
1847
1848 assert_eq!(
1849 value.reference.as_ref().unwrap().value.as_ref().unwrap(),
1850 "Patient/123"
1851 );
1852 }
1853
1854 #[tokio::test]
1855 async fn try_unsafe_set_from_ref() {
1856 let engine = FPEngine::new();
1857 let patient = Patient {
1858 link: Some(vec![PatientLink {
1859 other: Box::new(Reference {
1860 reference: Some(Box::new(FHIRString {
1861 value: Some("Patient/123".to_string()),
1862 ..Default::default()
1863 })),
1864 ..Default::default()
1865 }),
1866 ..Default::default()
1867 }]),
1868 name: Some(vec![Box::new(HumanName {
1869 given: Some(vec![Box::new(FHIRString {
1870 value: Some("Alice".to_string()),
1871 ..Default::default()
1872 })]),
1873 ..Default::default()
1874 })]),
1875 deceased: Some(PatientDeceasedTypeChoice::Boolean(Box::new(FHIRBoolean {
1876 value: Some(true),
1877 ..Default::default()
1878 }))),
1879 ..Default::default()
1880 };
1881
1882 let result = engine
1883 .evaluate("descendants().ofType(Reference)", vec![&patient])
1884 .await
1885 .unwrap();
1886
1887 assert_eq!(
1888 result
1889 .values
1890 .iter()
1891 .map(|v| v.typename())
1892 .collect::<Vec<_>>(),
1893 vec!["Reference",]
1894 );
1895
1896 let value = result.values[0]
1897 .as_any()
1898 .downcast_ref::<Reference>()
1899 .unwrap();
1900
1901 assert_eq!(
1902 value.reference.as_ref().unwrap().value.as_ref().unwrap(),
1903 "Patient/123"
1904 );
1905
1906 unsafe {
1909 let r = value as *const Reference;
1910 let mut_ptr = r as *mut Reference;
1911
1912 (*mut_ptr).reference = Some(Box::new(FHIRString {
1913 value: Some("Patient/456".to_string()),
1914 ..Default::default()
1915 }));
1916 }
1917
1918 assert_eq!(
1919 value.reference.as_ref().unwrap().value.as_ref().unwrap(),
1920 "Patient/456"
1921 );
1922
1923 assert_eq!(
1924 patient.link.as_ref().unwrap()[0]
1925 .other
1926 .reference
1927 .as_ref()
1928 .unwrap()
1929 .value
1930 .as_ref()
1931 .unwrap(),
1932 "Patient/456"
1933 );
1934 }
1935
1936 #[tokio::test]
1937 async fn test_external_constant_function() {
1938 let engine = FPEngine::new();
1939
1940 let config = Arc::new(Config {
1941 variable_resolver: (Some(ExternalConstantResolver::Function(Box::new(|v| {
1942 Box::pin(async move {
1943 match v.as_ref() {
1944 "test_variable" => Some(ResolvedValue::Box(Box::new(Patient {
1945 name: Some(vec![Box::new(HumanName {
1946 given: Some(vec![Box::new(FHIRString {
1947 value: Some("Paul".to_string()),
1948 ..Default::default()
1949 })]),
1950 ..Default::default()
1951 })]),
1952 ..Default::default()
1953 })
1954 as Box<dyn MetaValue>)),
1955 _ => None,
1956 }
1957 })
1958 })))),
1959 });
1960
1961 let result = engine
1962 .evaluate_with_config("%test_variable.name.given", vec![], config)
1963 .await
1964 .unwrap();
1965
1966 let value = result.values[0]
1967 .as_any()
1968 .downcast_ref::<FHIRString>()
1969 .unwrap();
1970
1971 assert_eq!(value.value.as_ref(), Some(&"Paul".to_string()));
1972 }
1973
1974 #[tokio::test]
1975 async fn test_external_constant_function_reference() {
1976 let engine = FPEngine::new();
1977
1978 let patient = Arc::new(Patient {
1979 name: Some(vec![Box::new(HumanName {
1980 given: Some(vec![Box::new(FHIRString {
1981 value: Some("Paul".to_string()),
1982 ..Default::default()
1983 })]),
1984 ..Default::default()
1985 })]),
1986 ..Default::default()
1987 });
1988
1989 let resolver = {
1990 let patient = patient.clone();
1991 ExternalConstantResolver::Function(Box::new(move |v| {
1992 let patient = patient.clone();
1993 Box::pin(async move {
1994 match v.as_ref() {
1996 "test_variable" => Some(ResolvedValue::Arc(patient.clone())),
1997 _ => None,
1998 }
1999 })
2000 }))
2001 };
2002
2003 let config = Arc::new(Config {
2004 variable_resolver: (Some(resolver)),
2005 });
2006
2007 let result = engine
2008 .evaluate_with_config("%test_variable.name.given", vec![], config)
2009 .await
2010 .unwrap();
2011
2012 let value = result.values[0]
2013 .as_any()
2014 .downcast_ref::<FHIRString>()
2015 .unwrap();
2016
2017 assert_eq!(value.value.as_ref(), Some(&"Paul".to_string()));
2018 }
2019
2020 #[tokio::test]
2021 async fn test_upper_function() {
2022 let engine = FPEngine::new();
2023
2024 let result = engine.evaluate("'hello'.upper()", vec![]).await.unwrap();
2025 assert_eq!(result.values.len(), 1);
2026 let value = result.values[0]
2027 .as_any()
2028 .downcast_ref::<FHIRString>()
2029 .unwrap();
2030 assert_eq!(value.value.as_deref(), Some("HELLO"));
2031
2032 let result = engine.evaluate("'AbCd'.upper()", vec![]).await.unwrap();
2033 let value = result.values[0]
2034 .as_any()
2035 .downcast_ref::<FHIRString>()
2036 .unwrap();
2037 assert_eq!(value.value.as_deref(), Some("ABCD"));
2038
2039 let result = engine.evaluate("'XYZ'.upper()", vec![]).await.unwrap();
2040 let value = result.values[0]
2041 .as_any()
2042 .downcast_ref::<FHIRString>()
2043 .unwrap();
2044 assert_eq!(value.value.as_deref(), Some("XYZ"));
2045 }
2046
2047 #[tokio::test]
2048 async fn test_lower_function() {
2049 let engine = FPEngine::new();
2050
2051 let result = engine.evaluate("'HELLO'.lower()", vec![]).await.unwrap();
2052 assert_eq!(result.values.len(), 1);
2053 let value = result.values[0]
2054 .as_any()
2055 .downcast_ref::<FHIRString>()
2056 .unwrap();
2057 assert_eq!(value.value.as_deref(), Some("hello"));
2058
2059 let result = engine.evaluate("'AbCd'.lower()", vec![]).await.unwrap();
2060 let value = result.values[0]
2061 .as_any()
2062 .downcast_ref::<FHIRString>()
2063 .unwrap();
2064 assert_eq!(value.value.as_deref(), Some("abcd"));
2065
2066 let result = engine.evaluate("'xyz'.lower()", vec![]).await.unwrap();
2067 let value = result.values[0]
2068 .as_any()
2069 .downcast_ref::<FHIRString>()
2070 .unwrap();
2071 assert_eq!(value.value.as_deref(), Some("xyz"));
2072 }
2073}