Skip to main content

haste_artifacts/
lib.rs

1use haste_fhir_model::r4::generated::resources::{Resource, SearchParameter};
2use rust_embed::Embed;
3use std::{collections::HashMap, sync::LazyLock};
4
5fn flatten_if_bundle(resource: Resource) -> Vec<Resource> {
6    match resource {
7        Resource::Bundle(bundle) => bundle
8            .entry
9            .unwrap_or_default()
10            .into_iter()
11            .filter_map(|e| e.resource.map(|r| *r))
12            .collect(),
13        _ => vec![resource],
14    }
15}
16
17fn load_resources() -> Vec<Resource> {
18    let mut resources = HashMap::new();
19
20    for path in EmbededResourceAssets::iter() {
21        let data = EmbededResourceAssets::get(path.as_ref()).unwrap();
22        let resource = serde_json::from_str::<Resource>(str::from_utf8(&data.data).unwrap())
23            .expect("Failed to parse artifact parameters JSON");
24
25        for r in flatten_if_bundle(resource) {
26            let resource_type = r.resource_type();
27            let id = r.id().clone().unwrap_or_else(|| {
28                panic!("Resource in '{}' does not have an ID", path.as_ref());
29            });
30
31            let key = (resource_type, id);
32
33            if resources.contains_key(&key) {
34                println!(
35                    "Duplicate resource ID '{}' '{}' found in '{}'",
36                    key.0.as_ref(),
37                    key.1,
38                    path.as_ref()
39                );
40            }
41
42            resources.insert(key, r);
43        }
44    }
45
46    resources.into_values().collect()
47}
48
49#[derive(Embed)]
50#[folder = "../../../artifacts/r4"]
51#[include = "hastehealth-core/definitions/**/*.json"]
52#[include = "hl7-core/definitions/hl7/*.min.json"]
53#[include = "r5-subscription-backport/**/*.json"]
54// Consumed by the TypeScript packages only; the server implements none of these.
55#[exclude = "hastehealth-core/definitions/haste-health/operation-frontend-only/**"]
56// The artifact folders are also pnpm workspace packages; none of the npm
57// metadata, nor anything pnpm links into them, is a FHIR resource.
58#[exclude = "*/node_modules/**"]
59#[exclude = "**/package.json"]
60#[exclude = "**/typedoc.json"]
61#[exclude = "**/.index.json"]
62struct EmbededResourceAssets;
63
64pub static ARTIFACT_RESOURCES: LazyLock<Vec<Resource>> = LazyLock::new(load_resources);
65
66#[derive(Embed)]
67#[folder = "../../../artifacts/r4"]
68#[include = "hastehealth-core/definitions/haste-health/search_parameter/*.json"]
69#[include = "hl7-core/definitions/hl7/search-parameters.min.json"]
70#[exclude = "*/node_modules/**"]
71struct EmbededSearchParameterAssets;
72
73/// System level Search Parameters. These are used for all tenants and projects and are loaded from embedded assets at startup.
74pub static R4_SEARCH_PARAMETERS: LazyLock<Vec<SearchParameter>> =
75    LazyLock::new(|| {
76        let mut search_parameters = Vec::new();
77
78        for path in EmbededSearchParameterAssets::iter() {
79            let data = EmbededSearchParameterAssets::get(path.as_ref()).unwrap();
80
81            let bundle = serde_json::from_str::<Resource>(std::str::from_utf8(&data.data).unwrap())
82                .expect("Failed to parse search parameters JSON");
83
84            search_parameters.extend(flatten_if_bundle(bundle).into_iter().filter_map(
85                |resource| match resource {
86                    Resource::SearchParameter(param) => Some(param),
87                    _ => None,
88                },
89            ));
90        }
91
92        search_parameters
93    });