1use crate::patch::MergePatchError;
2use std::fmt;
3use thiserror::Error as ThisError;
4
5#[derive(Debug, ThisError)]
13#[error("{message}")]
14pub struct InternalError {
15 pub class: ErrorClass,
16 pub origin: ErrorOrigin,
17 pub message: String,
18
19 pub detail: Option<ErrorDetail>,
22}
23
24impl InternalError {
25 pub fn new(class: ErrorClass, origin: ErrorOrigin, message: impl Into<String>) -> Self {
29 let message = message.into();
30
31 let detail = match (class, origin) {
32 (ErrorClass::Corruption, ErrorOrigin::Store) => {
33 Some(ErrorDetail::Store(StoreError::Corrupt {
34 message: message.clone(),
35 }))
36 }
37 (ErrorClass::InvariantViolation, ErrorOrigin::Store) => {
38 Some(ErrorDetail::Store(StoreError::InvariantViolation {
39 message: message.clone(),
40 }))
41 }
42 _ => None,
43 };
44
45 Self {
46 class,
47 origin,
48 message,
49 detail,
50 }
51 }
52
53 pub fn store_not_found(key: impl Into<String>) -> Self {
54 let key = key.into();
55
56 Self {
57 class: ErrorClass::NotFound,
58 origin: ErrorOrigin::Store,
59 message: format!("data key not found: {key}"),
60 detail: Some(ErrorDetail::Store(StoreError::NotFound { key })),
61 }
62 }
63
64 pub fn unsupported_entity_path(path: impl Into<String>) -> Self {
66 let path = path.into();
67
68 Self::new(
69 ErrorClass::Unsupported,
70 ErrorOrigin::Store,
71 format!("unsupported entity path: '{path}'"),
72 )
73 }
74
75 #[must_use]
76 pub const fn is_not_found(&self) -> bool {
77 matches!(
78 self.detail,
79 Some(ErrorDetail::Store(StoreError::NotFound { .. }))
80 )
81 }
82
83 #[must_use]
84 pub fn display_with_class(&self) -> String {
85 format!("{}:{}: {}", self.origin, self.class, self.message)
86 }
87}
88
89#[derive(Debug, ThisError)]
97pub enum ErrorDetail {
98 #[error("{0}")]
99 Store(StoreError),
100 #[error("{0}")]
101 ViewPatch(crate::patch::MergePatchError),
102 }
112
113impl From<MergePatchError> for InternalError {
114 fn from(err: MergePatchError) -> Self {
115 Self {
116 class: ErrorClass::Unsupported,
117 origin: ErrorOrigin::Interface,
118 message: err.to_string(),
119 detail: Some(ErrorDetail::ViewPatch(err)),
120 }
121 }
122}
123
124#[derive(Debug, ThisError)]
132pub enum StoreError {
133 #[error("key not found: {key}")]
134 NotFound { key: String },
135
136 #[error("store corruption: {message}")]
137 Corrupt { message: String },
138
139 #[error("store invariant violation: {message}")]
140 InvariantViolation { message: String },
141}
142
143#[derive(Clone, Copy, Debug, Eq, PartialEq)]
150pub enum ErrorClass {
151 Corruption,
152 NotFound,
153 Internal,
154 Conflict,
155 Unsupported,
156 InvariantViolation,
157}
158
159impl fmt::Display for ErrorClass {
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 let label = match self {
162 Self::Corruption => "corruption",
163 Self::NotFound => "not_found",
164 Self::Internal => "internal",
165 Self::Conflict => "conflict",
166 Self::Unsupported => "unsupported",
167 Self::InvariantViolation => "invariant_violation",
168 };
169 write!(f, "{label}")
170 }
171}
172
173#[derive(Clone, Copy, Debug, Eq, PartialEq)]
180pub enum ErrorOrigin {
181 Serialize,
182 Store,
183 Index,
184 Query,
185 Response,
186 Executor,
187 Interface,
188}
189
190impl fmt::Display for ErrorOrigin {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 let label = match self {
193 Self::Serialize => "serialize",
194 Self::Store => "store",
195 Self::Index => "index",
196 Self::Query => "query",
197 Self::Response => "response",
198 Self::Executor => "executor",
199 Self::Interface => "interface",
200 };
201 write!(f, "{label}")
202 }
203}