haste_fhir_operation_error/
lib.rs1use std::{error::Error, fmt::Display};
2
3use haste_fhir_model::r4::generated::{
4 resources::{OperationOutcome, OperationOutcomeIssue},
5 terminology::{IssueSeverity, IssueType},
6 types::FHIRString,
7};
8
9#[cfg(feature = "derive")]
10pub mod derive;
11
12#[cfg(feature = "axum")]
13pub mod axum;
14
15#[derive(Debug)]
16pub struct OperationOutcomeError {
17 _source: Option<anyhow::Error>,
18 outcome: OperationOutcome,
19}
20
21fn create_operation_outcome(
22 severity: IssueSeverity,
23 code: IssueType,
24 diagnostic: String,
25) -> OperationOutcome {
26 OperationOutcome {
27 issue: vec![OperationOutcomeIssue {
28 severity: Box::new(severity),
29 code: Box::new(code),
30 diagnostics: Some(Box::new(FHIRString {
31 value: Some(diagnostic),
32 ..Default::default()
33 })),
34 ..Default::default()
35 }],
36 ..Default::default()
37 }
38}
39
40impl OperationOutcomeError {
41 pub fn new(source: Option<anyhow::Error>, outcome: OperationOutcome) -> Self {
42 OperationOutcomeError {
43 _source: source,
44 outcome,
45 }
46 }
47
48 pub fn outcome(&self) -> &OperationOutcome {
49 &self.outcome
50 }
51
52 pub fn push_issue(
53 &mut self,
54 issue: haste_fhir_model::r4::generated::resources::OperationOutcomeIssue,
55 ) {
56 self.outcome.issue.push(issue);
57 }
58
59 pub fn backtrace(&self) -> Option<&std::backtrace::Backtrace> {
60 self._source.as_ref().map(|s| s.backtrace())
61 }
62
63 pub fn fatal(code: IssueType, diagnostic: String) -> Self {
64 OperationOutcomeError::new(
65 None,
66 create_operation_outcome(IssueSeverity::Fatal(None), code, diagnostic),
67 )
68 }
69 pub fn error(code: IssueType, diagnostic: String) -> Self {
70 OperationOutcomeError::new(
71 None,
72 create_operation_outcome(IssueSeverity::Error(None), code, diagnostic),
73 )
74 }
75 pub fn warning(code: IssueType, diagnostic: String) -> Self {
76 OperationOutcomeError::new(
77 None,
78 create_operation_outcome(IssueSeverity::Warning(None), code, diagnostic),
79 )
80 }
81 pub fn information(code: IssueType, diagnostic: String) -> Self {
82 OperationOutcomeError::new(
83 None,
84 create_operation_outcome(IssueSeverity::Information(None), code, diagnostic),
85 )
86 }
87}
88
89fn get_issue_diagnostics<'a>(
90 issue: &'a haste_fhir_model::r4::generated::resources::OperationOutcomeIssue,
91) -> Option<&'a str> {
92 issue
93 .diagnostics
94 .as_ref()
95 .and_then(|d| d.value.as_ref().map(|v| v.as_str()))
96}
97
98impl Display for OperationOutcomeError {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 write!(
101 f,
102 "Operation Error: '{}'",
103 self.outcome
104 .issue
105 .iter()
106 .map(get_issue_diagnostics)
107 .filter_map(|d| d)
108 .collect::<Vec<_>>()
109 .join(", ")
110 )
111 }
112}
113
114impl Error for OperationOutcomeError {
115 fn source(&self) -> Option<&(dyn Error + 'static)> {
116 if let Some(source) = self._source.as_ref() {
117 return Some(&**source);
118 } else {
119 None
120 }
121 }
122
123 fn description(&self) -> &str {
124 self.outcome.issue.first().map_or("Unknown error", |issue| {
125 if let Some(diagnostics) = &issue.diagnostics {
126 diagnostics
127 .value
128 .as_ref()
129 .map(|v| v.as_str())
130 .unwrap_or("No diagnostics available")
131 } else {
132 "No diagnostics available"
133 }
134 })
135 }
136
137 fn cause(&self) -> Option<&dyn Error> {
138 self.source()
139 }
140}