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 #[must_use]
65 pub const fn is_not_found(&self) -> bool {
66 matches!(
67 self.detail,
68 Some(ErrorDetail::Store(StoreError::NotFound { .. }))
69 )
70 }
71
72 #[must_use]
73 pub fn display_with_class(&self) -> String {
74 format!("{}:{}: {}", self.origin, self.class, self.message)
75 }
76}
77
78#[derive(Debug, ThisError)]
86pub enum ErrorDetail {
87 #[error("{0}")]
88 Store(StoreError),
89 #[error("{0}")]
90 ViewPatch(crate::patch::MergePatchError),
91 }
101
102impl From<MergePatchError> for InternalError {
103 fn from(err: MergePatchError) -> Self {
104 Self {
105 class: ErrorClass::Unsupported,
106 origin: ErrorOrigin::Interface,
107 message: err.to_string(),
108 detail: Some(ErrorDetail::ViewPatch(err)),
109 }
110 }
111}
112
113#[derive(Debug, ThisError)]
121pub enum StoreError {
122 #[error("key not found: {key}")]
123 NotFound { key: String },
124
125 #[error("store corruption: {message}")]
126 Corrupt { message: String },
127
128 #[error("store invariant violation: {message}")]
129 InvariantViolation { message: String },
130}
131
132#[derive(Clone, Copy, Debug, Eq, PartialEq)]
139pub enum ErrorClass {
140 Corruption,
141 NotFound,
142 Internal,
143 Conflict,
144 Unsupported,
145 InvariantViolation,
146}
147
148impl fmt::Display for ErrorClass {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 let label = match self {
151 Self::Corruption => "corruption",
152 Self::NotFound => "not_found",
153 Self::Internal => "internal",
154 Self::Conflict => "conflict",
155 Self::Unsupported => "unsupported",
156 Self::InvariantViolation => "invariant_violation",
157 };
158 write!(f, "{label}")
159 }
160}
161
162#[derive(Clone, Copy, Debug, Eq, PartialEq)]
169pub enum ErrorOrigin {
170 Serialize,
171 Store,
172 Index,
173 Query,
174 Response,
175 Executor,
176 Interface,
177}
178
179impl fmt::Display for ErrorOrigin {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 let label = match self {
182 Self::Serialize => "serialize",
183 Self::Store => "store",
184 Self::Index => "index",
185 Self::Query => "query",
186 Self::Response => "response",
187 Self::Executor => "executor",
188 Self::Interface => "interface",
189 };
190 write!(f, "{label}")
191 }
192}