Skip to main content

haste_x_fhir_query/
conversion.rs

1use haste_fhir_model::r4::generated::{
2    terminology::IssueType,
3    types::{
4        FHIRBase64Binary, FHIRBoolean, FHIRCanonical, FHIRCode, FHIRDate, FHIRDateTime,
5        FHIRDecimal, FHIRId, FHIRInstant, FHIRInteger, FHIRMarkdown, FHIROid, FHIRPositiveInt,
6        FHIRString, FHIRTime, FHIRUnsignedInt, FHIRUri, FHIRUrl, FHIRUuid,
7    },
8};
9use haste_fhir_operation_error::OperationOutcomeError;
10use haste_reflect::MetaValue;
11
12fn downcast_meta_value<T: 'static>(value: &dyn MetaValue) -> Option<&T> {
13    value.as_any().downcast_ref::<T>()
14}
15
16/// Converts a [`MetaValue`] into its string representation.
17///
18/// # Errors
19///
20/// Returns an [`OperationOutcomeError`] if:
21/// - the value cannot be downcast to the expected FHIR type,
22/// - the FHIR primitive value is missing,
23/// - the value type is not supported for stringification.
24pub fn stringify_meta_value(value: &dyn MetaValue) -> Result<String, OperationOutcomeError> {
25    match value.fhir_type() {
26        "http://hl7.org/fhirpath/System.String" => downcast_meta_value::<String>(value)
27            .cloned()
28            .ok_or_else(|| {
29                OperationOutcomeError::fatal(
30                    IssueType::invalid(),
31                    "http://hl7.org/fhirpath/System.String value is missing.".to_string(),
32                )
33            }),
34        "base64Binary" => {
35            stringify_with::<FHIRBase64Binary, _>(value, "base64Binary", |v| v.value.clone())
36        }
37        "decimal" => {
38            stringify_with::<FHIRDecimal, _>(value, "decimal", |v| v.value.map(|x| x.to_string()))
39        }
40        "boolean" => {
41            stringify_with::<FHIRBoolean, _>(value, "boolean", |v| v.value.map(|x| x.to_string()))
42        }
43        "url" => stringify_with::<FHIRUrl, _>(value, "url", |v| v.value.clone()),
44        "code" => stringify_with::<FHIRCode, _>(value, "code", |v| v.value.clone()),
45        "string" => stringify_with::<FHIRString, _>(value, "string", |v| v.value.clone()),
46        "integer" => {
47            stringify_with::<FHIRInteger, _>(value, "integer", |v| v.value.map(|x| x.to_string()))
48        }
49        "uri" => stringify_with::<FHIRUri, _>(value, "uri", |v| v.value.clone()),
50        "canonical" => stringify_with::<FHIRCanonical, _>(value, "canonical", |v| v.value.clone()),
51        "markdown" => stringify_with::<FHIRMarkdown, _>(value, "markdown", |v| v.value.clone()),
52        "id" => stringify_with::<FHIRId, _>(value, "id", |v| v.value.clone()),
53        "oid" => stringify_with::<FHIROid, _>(value, "oid", |v| v.value.clone()),
54        "uuid" => stringify_with::<FHIRUuid, _>(value, "uuid", |v| v.value.clone()),
55        "unsignedInt" => stringify_with::<FHIRUnsignedInt, _>(value, "unsignedInt", |v| {
56            v.value.map(|x| x.to_string())
57        }),
58        "positiveInt" => stringify_with::<FHIRPositiveInt, _>(value, "positiveInt", |v| {
59            v.value.map(|x| x.to_string())
60        }),
61        "instant" => stringify_with::<FHIRInstant, _>(value, "instant", |v| {
62            v.value.as_ref().map(ToString::to_string)
63        }),
64        "date" => stringify_with::<FHIRDate, _>(value, "date", |v| {
65            v.value.as_ref().map(ToString::to_string)
66        }),
67        "time" => stringify_with::<FHIRTime, _>(value, "time", |v| {
68            v.value.as_ref().map(ToString::to_string)
69        }),
70        "dateTime" => stringify_with::<FHIRDateTime, _>(value, "dateTime", |v| {
71            v.value.as_ref().map(ToString::to_string)
72        }),
73        typename => Err(OperationOutcomeError::fatal(
74            IssueType::invalid(),
75            format!("Unsupported MetaValue type for stringification: '{typename}'"),
76        )),
77    }
78}
79
80fn stringify_with<T, F>(
81    value: &dyn MetaValue,
82    type_name: &str,
83    extractor: F,
84) -> Result<String, OperationOutcomeError>
85where
86    T: MetaValue + 'static,
87    F: FnOnce(&T) -> Option<String>,
88{
89    downcast_meta_value::<T>(value)
90        .and_then(extractor)
91        .ok_or_else(|| {
92            OperationOutcomeError::fatal(
93                IssueType::invalid(),
94                format!("{type_name} value is missing."),
95            )
96        })
97}