1#[cfg(feature = "serde")]
6use serde::{Deserialize, Serialize};
7
8use async_trait::async_trait;
9
10use crate::error::Result;
11use crate::evaluation::{EvaluationResult, IntoEvaluationResult, TypeInfoResult};
12
13#[async_trait]
17pub trait ModelProvider: Send + Sync + std::fmt::Debug {
18 async fn get_type(&self, type_name: &str) -> Result<Option<TypeInfo>>;
20
21 async fn get_element_type(
23 &self,
24 parent_type: &TypeInfo,
25 property_name: &str,
26 ) -> Result<Option<TypeInfo>>;
27
28 fn of_type(&self, type_info: &TypeInfo, target_type: &str) -> Option<TypeInfo>;
30
31 fn get_element_names(&self, parent_type: &TypeInfo) -> Vec<String>;
33
34 async fn get_children_type(&self, parent_type: &TypeInfo) -> Result<Option<TypeInfo>>;
36
37 async fn get_elements(&self, type_name: &str) -> Result<Vec<ElementInfo>>;
39
40 async fn get_resource_types(&self) -> Result<Vec<String>>;
42
43 async fn get_complex_types(&self) -> Result<Vec<String>>;
45
46 async fn get_primitive_types(&self) -> Result<Vec<String>>;
48
49 async fn resource_type_exists(&self, resource_type: &str) -> Result<bool> {
51 let resource_types = self.get_resource_types().await?;
52 Ok(resource_types.contains(&resource_type.to_string()))
53 }
54
55 async fn get_fhir_version(&self) -> Result<FhirVersion> {
57 Ok(FhirVersion::R4)
59 }
60
61 fn is_type_derived_from(&self, derived_type: &str, base_type: &str) -> bool {
64 derived_type == base_type
66 }
67
68 async fn get_choice_types(
70 &self,
71 parent_type: &str,
72 property_name: &str,
73 ) -> Result<Option<Vec<ChoiceTypeInfo>>> {
74 let _ = (parent_type, property_name);
75 Ok(None)
76 }
77
78 async fn get_union_types(&self, type_info: &TypeInfo) -> Result<Option<Vec<TypeInfo>>> {
80 let _ = type_info;
81 Ok(None)
82 }
83
84 fn is_union_type(&self, type_info: &TypeInfo) -> bool {
86 let _ = type_info;
87 false
88 }
89}
90
91#[derive(Debug, Clone, PartialEq)]
93#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
94pub struct TypeInfo {
95 pub type_name: String,
97 pub singleton: Option<bool>,
99 pub is_empty: Option<bool>,
101 pub namespace: Option<String>,
103 pub name: Option<String>,
105}
106
107impl TypeInfo {
108 pub fn system_type(type_name: String, singleton: bool) -> Self {
110 Self {
111 type_name: type_name.clone(),
112 singleton: Some(singleton),
113 is_empty: Some(false),
114 namespace: Some("System".to_string()),
115 name: Some(type_name),
116 }
117 }
118}
119
120#[derive(Debug, Clone, PartialEq)]
122#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
123pub struct ElementInfo {
124 pub name: String,
126 pub element_type: String,
128 pub documentation: Option<String>,
130}
131
132#[derive(Debug, Clone, PartialEq)]
134#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
135pub struct ChoiceTypeInfo {
136 pub suffix: String,
138 pub type_name: String,
140}
141
142#[derive(Debug, Clone, PartialEq, Eq)]
144#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
145pub enum FhirVersion {
146 R4,
148 R4B,
150 R5,
152 R6,
154 Custom {
156 version: String,
158 },
159}
160
161#[derive(Debug, Clone, Default)]
163pub struct EmptyModelProvider;
164
165#[async_trait]
166impl ModelProvider for EmptyModelProvider {
167 async fn get_type(&self, type_name: &str) -> Result<Option<TypeInfo>> {
168 match type_name {
169 "Patient" | "Observation" | "Practitioner" | "Organization" => Ok(Some(TypeInfo {
170 type_name: "Any".to_string(),
171 singleton: Some(true),
172 is_empty: Some(false),
173 namespace: Some("FHIR".to_string()),
174 name: Some(type_name.to_string()),
175 })),
176 "Boolean" => Ok(Some(TypeInfo {
177 type_name: "Boolean".to_string(),
178 singleton: Some(true),
179 is_empty: Some(false),
180 namespace: Some("System".to_string()),
181 name: Some("Boolean".to_string()),
182 })),
183 "String" => Ok(Some(TypeInfo {
184 type_name: "String".to_string(),
185 singleton: Some(true),
186 is_empty: Some(false),
187 namespace: Some("System".to_string()),
188 name: Some("String".to_string()),
189 })),
190 "Integer" => Ok(Some(TypeInfo {
191 type_name: "Integer".to_string(),
192 singleton: Some(true),
193 is_empty: Some(false),
194 namespace: Some("System".to_string()),
195 name: Some("Integer".to_string()),
196 })),
197 "Decimal" => Ok(Some(TypeInfo {
198 type_name: "Decimal".to_string(),
199 singleton: Some(true),
200 is_empty: Some(false),
201 namespace: Some("System".to_string()),
202 name: Some("Decimal".to_string()),
203 })),
204 _ => Ok(None),
205 }
206 }
207
208 async fn get_element_type(
209 &self,
210 parent_type: &TypeInfo,
211 property_name: &str,
212 ) -> Result<Option<TypeInfo>> {
213 match (
214 parent_type
215 .name
216 .as_deref()
217 .unwrap_or(&parent_type.type_name),
218 property_name,
219 ) {
220 ("Patient", "name") => Ok(Some(TypeInfo {
221 type_name: "Any".to_string(),
222 singleton: Some(false),
223 is_empty: Some(false),
224 namespace: Some("FHIR".to_string()),
225 name: Some("HumanName".to_string()),
226 })),
227 ("HumanName", "given") => Ok(Some(TypeInfo {
228 type_name: "String".to_string(),
229 singleton: Some(false),
230 is_empty: Some(false),
231 namespace: Some("System".to_string()),
232 name: Some("String".to_string()),
233 })),
234 _ => Ok(None),
235 }
236 }
237
238 fn of_type(&self, type_info: &TypeInfo, target_type: &str) -> Option<TypeInfo> {
239 if type_info.type_name == target_type {
241 return Some(type_info.clone());
242 }
243
244 if let Some(ref name) = type_info.name {
246 if name == target_type {
247 return Some(type_info.clone());
248 }
249 if self.is_type_derived_from(name, target_type) {
251 return Some(type_info.clone());
252 }
253 }
254
255 if self.is_type_derived_from(&type_info.type_name, target_type) {
257 return Some(type_info.clone());
258 }
259
260 None
261 }
262
263 fn is_type_derived_from(&self, derived_type: &str, base_type: &str) -> bool {
264 if derived_type == base_type {
265 return true;
266 }
267
268 matches!(
270 (derived_type, base_type),
271 ("code" | "id" | "uri", "string")
272 | ("Patient", "DomainResource")
273 | ("DomainResource", "Resource")
274 )
275 }
276
277 fn get_element_names(&self, parent_type: &TypeInfo) -> Vec<String> {
278 match parent_type
279 .name
280 .as_deref()
281 .unwrap_or(&parent_type.type_name)
282 {
283 "Patient" => vec![
284 "id".to_string(),
285 "name".to_string(),
286 "gender".to_string(),
287 "birthDate".to_string(),
288 ],
289 "HumanName" => vec!["given".to_string(), "family".to_string(), "use".to_string()],
290 "Observation" => vec![
291 "id".to_string(),
292 "status".to_string(),
293 "code".to_string(),
294 "value".to_string(),
295 "subject".to_string(),
296 ],
297 _ => Vec::new(),
298 }
299 }
300
301 async fn get_children_type(&self, parent_type: &TypeInfo) -> Result<Option<TypeInfo>> {
302 if parent_type.singleton.unwrap_or(true) {
303 Ok(None)
304 } else {
305 Ok(Some(TypeInfo {
306 type_name: parent_type.type_name.clone(),
307 singleton: Some(true),
308 is_empty: Some(false),
309 namespace: parent_type.namespace.clone(),
310 name: parent_type.name.clone(),
311 }))
312 }
313 }
314
315 async fn get_elements(&self, type_name: &str) -> Result<Vec<ElementInfo>> {
316 match type_name {
317 "Patient" => Ok(vec![
318 ElementInfo {
319 name: "id".to_string(),
320 element_type: "id".to_string(),
321 documentation: Some("Logical id of this artifact".to_string()),
322 },
323 ElementInfo {
324 name: "name".to_string(),
325 element_type: "HumanName[]".to_string(),
326 documentation: Some("A name associated with the patient".to_string()),
327 },
328 ]),
329 _ => Ok(Vec::new()),
330 }
331 }
332
333 async fn get_resource_types(&self) -> Result<Vec<String>> {
334 Ok(vec![
335 "Patient".to_string(),
336 "Observation".to_string(),
337 "Practitioner".to_string(),
338 "Organization".to_string(),
339 ])
340 }
341
342 async fn get_complex_types(&self) -> Result<Vec<String>> {
343 Ok(vec![
344 "HumanName".to_string(),
345 "Address".to_string(),
346 "ContactPoint".to_string(),
347 "CodeableConcept".to_string(),
348 "Quantity".to_string(),
349 ])
350 }
351
352 async fn get_primitive_types(&self) -> Result<Vec<String>> {
353 Ok(vec![
354 "Boolean".to_string(),
355 "String".to_string(),
356 "Integer".to_string(),
357 "Decimal".to_string(),
358 "Date".to_string(),
359 "DateTime".to_string(),
360 "Time".to_string(),
361 ])
362 }
363
364 async fn get_choice_types(
365 &self,
366 parent_type: &str,
367 property_name: &str,
368 ) -> Result<Option<Vec<ChoiceTypeInfo>>> {
369 match (parent_type, property_name) {
370 ("Observation", "value") => Ok(Some(vec![
371 ChoiceTypeInfo {
372 suffix: "String".to_string(),
373 type_name: "string".to_string(),
374 },
375 ChoiceTypeInfo {
376 suffix: "Integer".to_string(),
377 type_name: "integer".to_string(),
378 },
379 ChoiceTypeInfo {
380 suffix: "Boolean".to_string(),
381 type_name: "boolean".to_string(),
382 },
383 ChoiceTypeInfo {
384 suffix: "Quantity".to_string(),
385 type_name: "Quantity".to_string(),
386 },
387 ChoiceTypeInfo {
388 suffix: "CodeableConcept".to_string(),
389 type_name: "CodeableConcept".to_string(),
390 },
391 ])),
392 _ => Ok(None),
393 }
394 }
395
396 async fn get_union_types(&self, type_info: &TypeInfo) -> Result<Option<Vec<TypeInfo>>> {
397 match type_info.type_name.as_str() {
398 "Union" | "Choice" => Ok(Some(vec![
399 TypeInfo {
400 type_name: "String".to_string(),
401 singleton: Some(true),
402 is_empty: Some(false),
403 namespace: Some("System".to_string()),
404 name: Some("String".to_string()),
405 },
406 TypeInfo {
407 type_name: "Integer".to_string(),
408 singleton: Some(true),
409 is_empty: Some(false),
410 namespace: Some("System".to_string()),
411 name: Some("Integer".to_string()),
412 },
413 ])),
414 _ => Ok(None),
415 }
416 }
417
418 fn is_union_type(&self, type_info: &TypeInfo) -> bool {
419 matches!(type_info.type_name.as_str(), "Union" | "Choice")
420 }
421}
422
423impl std::fmt::Display for FhirVersion {
424 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
425 match self {
426 FhirVersion::R4 => write!(f, "R4"),
427 FhirVersion::R4B => write!(f, "R4B"),
428 FhirVersion::R5 => write!(f, "R5"),
429 FhirVersion::R6 => write!(f, "R6"),
430 FhirVersion::Custom { version } => write!(f, "{version}"),
431 }
432 }
433}
434
435impl IntoEvaluationResult for TypeInfo {
438 fn to_evaluation_result(&self) -> EvaluationResult {
439 let mut map = std::collections::HashMap::new();
441
442 map.insert(
443 "type_name".to_string(),
444 self.type_name.to_evaluation_result(),
445 );
446
447 if let Some(singleton) = self.singleton {
448 map.insert("singleton".to_string(), singleton.to_evaluation_result());
449 }
450
451 if let Some(is_empty) = self.is_empty {
452 map.insert("is_empty".to_string(), is_empty.to_evaluation_result());
453 }
454
455 if let Some(ref namespace) = self.namespace {
456 map.insert("namespace".to_string(), namespace.to_evaluation_result());
457 }
458
459 if let Some(ref name) = self.name {
460 map.insert("name".to_string(), name.to_evaluation_result());
461 }
462
463 let type_info = if let Some(ref namespace) = self.namespace {
464 Some(TypeInfoResult::new(namespace, &self.type_name))
465 } else {
466 Some(TypeInfoResult::system(&self.type_name))
467 };
468
469 EvaluationResult::Object { map, type_info }
470 }
471}
472
473impl IntoEvaluationResult for ElementInfo {
474 fn to_evaluation_result(&self) -> EvaluationResult {
475 let mut map = std::collections::HashMap::new();
476
477 map.insert("name".to_string(), self.name.to_evaluation_result());
478 map.insert(
479 "element_type".to_string(),
480 self.element_type.to_evaluation_result(),
481 );
482
483 if let Some(ref documentation) = self.documentation {
484 map.insert(
485 "documentation".to_string(),
486 documentation.to_evaluation_result(),
487 );
488 }
489
490 EvaluationResult::typed_object(map, "FHIR", "ElementInfo")
491 }
492}
493
494impl IntoEvaluationResult for ChoiceTypeInfo {
495 fn to_evaluation_result(&self) -> EvaluationResult {
496 let mut map = std::collections::HashMap::new();
497
498 map.insert("suffix".to_string(), self.suffix.to_evaluation_result());
499 map.insert(
500 "type_name".to_string(),
501 self.type_name.to_evaluation_result(),
502 );
503
504 EvaluationResult::typed_object(map, "FHIR", "ChoiceTypeInfo")
505 }
506}
507
508impl IntoEvaluationResult for FhirVersion {
509 fn to_evaluation_result(&self) -> EvaluationResult {
510 EvaluationResult::string(self.to_string())
511 }
512}
513
514#[derive(Debug, Clone)]
521pub struct LiteModelProvider {
522 inner: std::sync::Arc<dyn ModelProvider>,
524}
525
526impl LiteModelProvider {
527 pub fn new(inner: std::sync::Arc<dyn ModelProvider>) -> Self {
529 Self { inner }
530 }
531
532 pub fn inner(&self) -> &dyn ModelProvider {
534 self.inner.as_ref()
535 }
536
537 pub fn into_inner(self) -> std::sync::Arc<dyn ModelProvider> {
539 self.inner
540 }
541
542 pub fn supports_validation(&self) -> bool {
545 false
546 }
547}
548
549#[async_trait]
550impl ModelProvider for LiteModelProvider {
551 async fn get_type(&self, type_name: &str) -> Result<Option<TypeInfo>> {
552 self.inner.get_type(type_name).await
553 }
554
555 async fn get_element_type(
556 &self,
557 parent_type: &TypeInfo,
558 property_name: &str,
559 ) -> Result<Option<TypeInfo>> {
560 self.inner
561 .get_element_type(parent_type, property_name)
562 .await
563 }
564
565 fn of_type(&self, type_info: &TypeInfo, target_type: &str) -> Option<TypeInfo> {
566 self.inner.of_type(type_info, target_type)
567 }
568
569 fn get_element_names(&self, parent_type: &TypeInfo) -> Vec<String> {
570 self.inner.get_element_names(parent_type)
571 }
572
573 async fn get_children_type(&self, parent_type: &TypeInfo) -> Result<Option<TypeInfo>> {
574 self.inner.get_children_type(parent_type).await
575 }
576
577 async fn get_elements(&self, type_name: &str) -> Result<Vec<ElementInfo>> {
578 self.inner.get_elements(type_name).await
579 }
580
581 async fn get_resource_types(&self) -> Result<Vec<String>> {
582 self.inner.get_resource_types().await
583 }
584
585 async fn get_complex_types(&self) -> Result<Vec<String>> {
586 self.inner.get_complex_types().await
587 }
588
589 async fn get_primitive_types(&self) -> Result<Vec<String>> {
590 self.inner.get_primitive_types().await
591 }
592
593 async fn resource_type_exists(&self, resource_type: &str) -> Result<bool> {
594 self.inner.resource_type_exists(resource_type).await
595 }
596
597 async fn get_fhir_version(&self) -> Result<FhirVersion> {
598 self.inner.get_fhir_version().await
599 }
600
601 fn is_type_derived_from(&self, derived_type: &str, base_type: &str) -> bool {
602 self.inner.is_type_derived_from(derived_type, base_type)
603 }
604
605 async fn get_choice_types(
606 &self,
607 parent_type: &str,
608 property_name: &str,
609 ) -> Result<Option<Vec<ChoiceTypeInfo>>> {
610 self.inner
611 .get_choice_types(parent_type, property_name)
612 .await
613 }
614
615 async fn get_union_types(&self, type_info: &TypeInfo) -> Result<Option<Vec<TypeInfo>>> {
616 self.inner.get_union_types(type_info).await
617 }
618
619 fn is_union_type(&self, type_info: &TypeInfo) -> bool {
620 self.inner.is_union_type(type_info)
621 }
622}