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(crate) fn query_invariant(message: impl Into<String>) -> Self {
55 Self::new(
56 ErrorClass::InvariantViolation,
57 ErrorOrigin::Query,
58 message.into(),
59 )
60 }
61
62 pub(crate) fn index_invariant(message: impl Into<String>) -> Self {
64 Self::new(
65 ErrorClass::InvariantViolation,
66 ErrorOrigin::Index,
67 message.into(),
68 )
69 }
70
71 pub(crate) fn executor_invariant(message: impl Into<String>) -> Self {
73 Self::new(
74 ErrorClass::InvariantViolation,
75 ErrorOrigin::Executor,
76 message.into(),
77 )
78 }
79
80 pub(crate) fn store_invariant(message: impl Into<String>) -> Self {
82 Self::new(
83 ErrorClass::InvariantViolation,
84 ErrorOrigin::Store,
85 message.into(),
86 )
87 }
88
89 pub(crate) fn corruption(origin: ErrorOrigin, message: impl Into<String>) -> Self {
91 Self::new(ErrorClass::Corruption, origin, message.into())
92 }
93
94 pub(crate) fn store_internal(message: impl Into<String>) -> Self {
96 Self::new(ErrorClass::Internal, ErrorOrigin::Store, message.into())
97 }
98
99 pub(crate) fn executor_internal(message: impl Into<String>) -> Self {
101 Self::new(ErrorClass::Internal, ErrorOrigin::Executor, message.into())
102 }
103
104 pub(crate) fn index_internal(message: impl Into<String>) -> Self {
106 Self::new(ErrorClass::Internal, ErrorOrigin::Index, message.into())
107 }
108
109 pub(crate) fn store_corruption(message: impl Into<String>) -> Self {
111 Self::new(ErrorClass::Corruption, ErrorOrigin::Store, message.into())
112 }
113
114 pub(crate) fn index_corruption(message: impl Into<String>) -> Self {
116 Self::new(ErrorClass::Corruption, ErrorOrigin::Index, message.into())
117 }
118
119 pub(crate) fn serialize_corruption(message: impl Into<String>) -> Self {
121 Self::new(
122 ErrorClass::Corruption,
123 ErrorOrigin::Serialize,
124 message.into(),
125 )
126 }
127
128 pub(crate) fn store_unsupported(message: impl Into<String>) -> Self {
130 Self::new(ErrorClass::Unsupported, ErrorOrigin::Store, message.into())
131 }
132
133 pub(crate) fn index_unsupported(message: impl Into<String>) -> Self {
135 Self::new(ErrorClass::Unsupported, ErrorOrigin::Index, message.into())
136 }
137
138 pub(crate) fn executor_unsupported(message: impl Into<String>) -> Self {
140 Self::new(
141 ErrorClass::Unsupported,
142 ErrorOrigin::Executor,
143 message.into(),
144 )
145 }
146
147 pub(crate) fn serialize_unsupported(message: impl Into<String>) -> Self {
149 Self::new(
150 ErrorClass::Unsupported,
151 ErrorOrigin::Serialize,
152 message.into(),
153 )
154 }
155
156 pub fn store_not_found(key: impl Into<String>) -> Self {
157 let key = key.into();
158
159 Self {
160 class: ErrorClass::NotFound,
161 origin: ErrorOrigin::Store,
162 message: format!("data key not found: {key}"),
163 detail: Some(ErrorDetail::Store(StoreError::NotFound { key })),
164 }
165 }
166
167 pub fn unsupported_entity_path(path: impl Into<String>) -> Self {
169 let path = path.into();
170
171 Self::new(
172 ErrorClass::Unsupported,
173 ErrorOrigin::Store,
174 format!("unsupported entity path: '{path}'"),
175 )
176 }
177
178 #[must_use]
179 pub const fn is_not_found(&self) -> bool {
180 matches!(
181 self.detail,
182 Some(ErrorDetail::Store(StoreError::NotFound { .. }))
183 )
184 }
185
186 #[must_use]
187 pub fn display_with_class(&self) -> String {
188 format!("{}:{}: {}", self.origin, self.class, self.message)
189 }
190}
191
192#[derive(Debug, ThisError)]
200pub enum ErrorDetail {
201 #[error("{0}")]
202 Store(StoreError),
203 #[error("{0}")]
204 ViewPatch(crate::patch::MergePatchError),
205 }
215
216impl From<MergePatchError> for InternalError {
217 fn from(err: MergePatchError) -> Self {
218 Self {
219 class: ErrorClass::Unsupported,
220 origin: ErrorOrigin::Interface,
221 message: err.to_string(),
222 detail: Some(ErrorDetail::ViewPatch(err)),
223 }
224 }
225}
226
227#[derive(Debug, ThisError)]
235pub enum StoreError {
236 #[error("key not found: {key}")]
237 NotFound { key: String },
238
239 #[error("store corruption: {message}")]
240 Corrupt { message: String },
241
242 #[error("store invariant violation: {message}")]
243 InvariantViolation { message: String },
244}
245
246#[derive(Clone, Copy, Debug, Eq, PartialEq)]
253pub enum ErrorClass {
254 Corruption,
255 NotFound,
256 Internal,
257 Conflict,
258 Unsupported,
259 InvariantViolation,
260}
261
262impl fmt::Display for ErrorClass {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 let label = match self {
265 Self::Corruption => "corruption",
266 Self::NotFound => "not_found",
267 Self::Internal => "internal",
268 Self::Conflict => "conflict",
269 Self::Unsupported => "unsupported",
270 Self::InvariantViolation => "invariant_violation",
271 };
272 write!(f, "{label}")
273 }
274}
275
276#[derive(Clone, Copy, Debug, Eq, PartialEq)]
283pub enum ErrorOrigin {
284 Serialize,
285 Store,
286 Index,
287 Query,
288 Response,
289 Executor,
290 Interface,
291}
292
293impl fmt::Display for ErrorOrigin {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 let label = match self {
296 Self::Serialize => "serialize",
297 Self::Store => "store",
298 Self::Index => "index",
299 Self::Query => "query",
300 Self::Response => "response",
301 Self::Executor => "executor",
302 Self::Interface => "interface",
303 };
304 write!(f, "{label}")
305 }
306}