1use crate::httpx::error::Error as HttpError;
20use crate::memdx;
21use crate::mgmtx::error::Error as MgmtError;
22use crate::queryx::error::Error as QueryError;
23use crate::retry::RetryInfo;
24use crate::searchx::error::Error as SearchError;
25use crate::service_type::ServiceType;
26use std::error::Error as StdError;
27use std::fmt::{Display, Formatter};
28use std::ops::Deref;
29use std::sync::Arc;
30
31pub type Result<T> = std::result::Result<T, Error>;
32
33#[derive(Debug, Clone)]
34pub struct Error {
35 kind: Arc<ErrorKind>,
36 retry_info: Option<RetryInfo>,
37}
38
39impl Display for Error {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 if let Some(retry_info) = &self.retry_info {
42 return write!(f, "{}, {}", self.kind, retry_info);
43 }
44 write!(f, "{}", self.kind)
45 }
46}
47
48impl StdError for Error {
49 fn source(&self) -> Option<&(dyn StdError + 'static)> {
50 match self.kind.as_ref() {
51 ErrorKind::Memdx(err) => err.inner.source.source(),
52 ErrorKind::Query(err) => err.source(),
53 ErrorKind::Search(err) => err.source(),
54 ErrorKind::Http(err) => err.source(),
55 ErrorKind::Mgmt(err) => err.source(),
56 _ => None,
57 }
58 }
59}
60
61impl Error {
62 pub(crate) fn new(kind: ErrorKind) -> Self {
63 Self {
64 kind: Arc::new(kind),
65 retry_info: None,
66 }
67 }
68
69 pub(crate) fn new_contextual_memdx_error(e: MemdxError) -> Self {
70 Self::new(ErrorKind::Memdx(e))
71 }
72
73 pub(crate) fn new_message_error(msg: impl Into<String>) -> Self {
74 Self::new(ErrorKind::Message { msg: msg.into() })
75 }
76
77 pub(crate) fn new_invalid_argument_error(msg: impl Into<String>, arg: Option<String>) -> Self {
78 Self::new(ErrorKind::InvalidArgument {
79 msg: msg.into(),
80 arg,
81 })
82 }
83
84 pub(crate) fn new_feature_not_available_error(
85 feature: impl Into<String>,
86 msg: impl Into<String>,
87 ) -> Self {
88 Self::new(ErrorKind::FeatureNotAvailable {
89 feature: feature.into(),
90 msg: msg.into(),
91 })
92 }
93
94 pub fn kind(&self) -> &ErrorKind {
95 &self.kind
96 }
97
98 pub(crate) fn is_memdx_error(&self) -> Option<&memdx::error::Error> {
99 match self.kind.as_ref() {
100 ErrorKind::Memdx(err) => Some(err),
101 _ => None,
102 }
103 }
104
105 pub(crate) fn set_retry_info(&mut self, retry_info: RetryInfo) {
106 self.retry_info = Some(retry_info);
107 }
108
109 pub fn retry_info(&self) -> Option<&RetryInfo> {
110 self.retry_info.as_ref()
111 }
112}
113
114#[derive(Debug, PartialEq)]
115#[non_exhaustive]
116pub enum ErrorKind {
117 Memdx(MemdxError),
118 Query(QueryError),
119 Search(SearchError),
120 Http(HttpError),
121 Mgmt(MgmtError),
122 VbucketMapOutdated,
123 #[non_exhaustive]
124 InvalidArgument {
125 msg: String,
126 arg: Option<String>,
127 },
128 #[non_exhaustive]
129 EndpointNotKnown {
130 endpoint: String,
131 },
132 InvalidVbucket {
133 requested_vb_id: u16,
134 num_vbuckets: usize,
135 },
136 InvalidReplica {
137 requested_replica: u32,
138 num_servers: usize,
139 },
140 NoEndpointsAvailable,
141 Shutdown,
142 NoBucket,
143 IllegalState {
144 msg: String,
145 },
146 NoVbucketMap,
147 #[non_exhaustive]
148 NoServerAssigned {
149 requested_vb_id: u16,
150 },
151 #[non_exhaustive]
152 CollectionManifestOutdated {
153 manifest_uid: u64,
154 server_manifest_uid: u64,
155 },
156 #[non_exhaustive]
157 Message {
158 msg: String,
159 },
160 #[non_exhaustive]
161 ServiceNotAvailable {
162 service: ServiceType,
163 },
164 #[non_exhaustive]
165 FeatureNotAvailable {
166 feature: String,
167 msg: String,
168 },
169 #[non_exhaustive]
170 Compression {
171 msg: String,
172 },
173 #[non_exhaustive]
174 Internal {
175 msg: String,
176 },
177}
178
179impl Display for ErrorKind {
180 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
181 match self {
182 ErrorKind::VbucketMapOutdated => write!(f, "vbucket map outdated"),
183 ErrorKind::InvalidArgument { msg, arg } => {
184 if let Some(arg) = arg {
185 write!(f, "invalid argument {arg}: {msg}")
186 } else {
187 write!(f, "invalid argument: {msg}")
188 }
189 }
190 ErrorKind::Memdx(err) => write!(f, "{err}"),
191 ErrorKind::Query(err) => write!(f, "{err}"),
192 ErrorKind::Search(err) => write!(f, "{err}"),
193 ErrorKind::Http(err) => write!(f, "{err}"),
194 ErrorKind::Mgmt(err) => write!(f, "{err}"),
195 ErrorKind::EndpointNotKnown { endpoint } => {
196 write!(f, "endpoint not known: {endpoint}")
197 }
198 ErrorKind::NoEndpointsAvailable => write!(f, "no endpoints available"),
199 ErrorKind::Shutdown => write!(f, "shutdown"),
200 ErrorKind::NoBucket => write!(f, "no bucket selected"),
201 ErrorKind::IllegalState { msg } => write!(f, "illegal state: {msg}"),
202 ErrorKind::NoVbucketMap => write!(f, "invalid vbucket map"),
203 ErrorKind::CollectionManifestOutdated {
204 manifest_uid,
205 server_manifest_uid,
206 } => {
207 write!(
208 f,
209 "collection manifest outdated: our manifest uid: {manifest_uid}, server manifest uid: {server_manifest_uid}"
210 )
211 }
212 ErrorKind::Message { msg } => write!(f, "{msg}"),
213 ErrorKind::ServiceNotAvailable { service } => {
214 write!(f, "service not available: {service}")
215 }
216 ErrorKind::FeatureNotAvailable { feature, msg } => {
217 write!(f, "feature not available: {feature}, {msg}")
218 }
219 ErrorKind::Internal { msg } => write!(f, "internal error: {msg}"),
220 ErrorKind::NoServerAssigned { requested_vb_id } => {
221 write!(f, "no server assigned for vbucket id: {requested_vb_id}")
222 }
223 ErrorKind::InvalidVbucket {
224 requested_vb_id,
225 num_vbuckets,
226 } => write!(
227 f,
228 "invalid vbucket id: {requested_vb_id}, num vbuckets: {num_vbuckets}"
229 ),
230 ErrorKind::InvalidReplica {
231 requested_replica,
232 num_servers,
233 } => write!(
234 f,
235 "invalid replica: {requested_replica}, num servers: {num_servers}"
236 ),
237 ErrorKind::Compression { msg } => write!(f, "compression error: {msg}"),
238 }
239 }
240}
241
242#[derive(Debug, PartialEq)]
243pub struct MemdxError {
244 inner: Box<InnerMemdxError>,
245}
246
247#[derive(Debug, PartialEq)]
248pub struct InnerMemdxError {
249 source: memdx::error::Error,
250 dispatched_to: Option<String>,
251 dispatched_from: Option<String>,
252 doc_id: Option<Vec<u8>>,
253 bucket_name: Option<String>,
254 scope_name: Option<String>,
255 collection_name: Option<String>,
256}
257
258impl Deref for MemdxError {
259 type Target = memdx::error::Error;
260
261 fn deref(&self) -> &Self::Target {
262 &self.inner.source
263 }
264}
265
266impl MemdxError {
267 pub(crate) fn new(source: memdx::error::Error) -> Self {
268 Self {
269 inner: Box::new(InnerMemdxError {
270 source,
271 dispatched_to: None,
272 dispatched_from: None,
273 doc_id: None,
274 bucket_name: None,
275 scope_name: None,
276 collection_name: None,
277 }),
278 }
279 }
280
281 pub(crate) fn with_dispatched_to(mut self, dispatched_to: impl Into<String>) -> Self {
282 self.inner.dispatched_to = Some(dispatched_to.into());
283 self
284 }
285
286 pub(crate) fn with_dispatched_from(mut self, dispatched_from: impl Into<String>) -> Self {
287 self.inner.dispatched_from = Some(dispatched_from.into());
288 self
289 }
290
291 pub fn dispatched_to(&self) -> Option<&String> {
292 self.inner.dispatched_to.as_ref()
293 }
294
295 pub fn dispatched_from(&self) -> Option<&String> {
296 self.inner.dispatched_from.as_ref()
297 }
298
299 pub fn doc_id(&self) -> Option<&[u8]> {
300 self.inner.doc_id.as_deref()
301 }
302
303 pub fn bucket_name(&self) -> Option<&String> {
304 self.inner.bucket_name.as_ref()
305 }
306
307 pub fn scope_name(&self) -> Option<&String> {
308 self.inner.scope_name.as_ref()
309 }
310
311 pub fn collection_name(&self) -> Option<&String> {
312 self.inner.collection_name.as_ref()
313 }
314
315 pub(crate) fn set_doc_id(mut self, doc_id: Vec<u8>) -> Self {
316 self.inner.doc_id = Some(doc_id);
317 self
318 }
319
320 pub(crate) fn set_bucket_name(mut self, bucket_name: String) -> Self {
321 self.inner.bucket_name = Some(bucket_name);
322 self
323 }
324
325 pub(crate) fn set_scope_name(mut self, scope_name: String) -> Self {
326 self.inner.scope_name = Some(scope_name);
327 self
328 }
329
330 pub(crate) fn set_collection_name(mut self, collection_name: String) -> Self {
331 self.inner.collection_name = Some(collection_name);
332 self
333 }
334}
335
336impl Display for MemdxError {
337 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
338 write!(f, "{}", self.inner.source)?;
339 if let Some(ref dispatched_to) = self.inner.dispatched_to {
340 write!(f, ", dispatched to: {dispatched_to}")?;
341 }
342 if let Some(ref dispatched_from) = self.inner.dispatched_from {
343 write!(f, ", dispatched from: {dispatched_from}")?;
344 }
345 Ok(())
346 }
347}
348
349impl<E> From<E> for Error
350where
351 ErrorKind: From<E>,
352{
353 fn from(err: E) -> Self {
354 Self {
355 kind: Arc::new(err.into()),
356 retry_info: None,
357 }
358 }
359}
360
361impl From<QueryError> for Error {
362 fn from(value: QueryError) -> Self {
363 Self::new(ErrorKind::Query(value))
364 }
365}
366
367impl From<HttpError> for Error {
368 fn from(value: HttpError) -> Self {
369 Self::new(ErrorKind::Http(value))
370 }
371}
372
373impl From<SearchError> for Error {
374 fn from(value: SearchError) -> Self {
375 Self::new(ErrorKind::Search(value))
376 }
377}
378
379impl From<MgmtError> for Error {
380 fn from(value: MgmtError) -> Self {
381 Self::new(ErrorKind::Mgmt(value))
382 }
383}