couchbase_core/searchx/
error.rs

1/*
2 *
3 *  * Copyright (c) 2025 Couchbase, Inc.
4 *  *
5 *  * Licensed under the Apache License, Version 2.0 (the "License");
6 *  * you may not use this file except in compliance with the License.
7 *  * You may obtain a copy of the License at
8 *  *
9 *  *    http://www.apache.org/licenses/LICENSE-2.0
10 *  *
11 *  * Unless required by applicable law or agreed to in writing, software
12 *  * distributed under the License is distributed on an "AS IS" BASIS,
13 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  * See the License for the specific language governing permissions and
15 *  * limitations under the License.
16 *
17 */
18
19use http::StatusCode;
20use std::error::Error as StdError;
21use std::fmt::{Display, Formatter};
22
23pub type Result<T> = std::result::Result<T, Error>;
24
25#[derive(Debug, Clone, PartialEq)]
26pub struct Error {
27    inner: ErrorImpl,
28}
29
30impl Display for Error {
31    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32        write!(f, "{}", self.inner.kind)
33    }
34}
35
36impl StdError for Error {}
37
38impl Error {
39    pub(crate) fn new_server_error(e: ServerError) -> Error {
40        Self {
41            inner: ErrorImpl {
42                kind: Box::new(ErrorKind::Server(e)),
43            },
44        }
45    }
46
47    pub(crate) fn new_message_error(
48        msg: impl Into<String>,
49        endpoint: impl Into<Option<String>>,
50    ) -> Error {
51        Self {
52            inner: ErrorImpl {
53                kind: Box::new(ErrorKind::Message {
54                    msg: msg.into(),
55                    endpoint: endpoint.into(),
56                }),
57            },
58        }
59    }
60
61    pub(crate) fn new_encoding_error(msg: impl Into<String>) -> Error {
62        Self {
63            inner: ErrorImpl {
64                kind: Box::new(ErrorKind::Encoding { msg: msg.into() }),
65            },
66        }
67    }
68
69    pub(crate) fn new_invalid_argument_error(
70        msg: impl Into<String>,
71        arg: impl Into<Option<String>>,
72    ) -> Self {
73        Self {
74            inner: ErrorImpl {
75                kind: Box::new(ErrorKind::InvalidArgument {
76                    msg: msg.into(),
77                    arg: arg.into(),
78                }),
79            },
80        }
81    }
82
83    pub(crate) fn new_http_error(endpoint: impl Into<String>) -> Self {
84        Self {
85            inner: ErrorImpl {
86                kind: Box::new(ErrorKind::Http {
87                    endpoint: endpoint.into(),
88                }),
89            },
90        }
91    }
92
93    pub(crate) fn new_unsupported_feature_error(feature: String) -> Self {
94        Self {
95            inner: ErrorImpl {
96                kind: Box::new(ErrorKind::UnsupportedFeature { feature }),
97            },
98        }
99    }
100
101    pub fn kind(&self) -> &ErrorKind {
102        &self.inner.kind
103    }
104}
105
106#[derive(Debug, Clone)]
107struct ErrorImpl {
108    kind: Box<ErrorKind>,
109}
110
111impl PartialEq for ErrorImpl {
112    fn eq(&self, other: &Self) -> bool {
113        self.kind == other.kind
114    }
115}
116
117#[derive(Clone, Debug, PartialEq, Eq)]
118#[non_exhaustive]
119pub enum ErrorKind {
120    Server(ServerError),
121    #[non_exhaustive]
122    Http {
123        endpoint: String,
124    },
125    #[non_exhaustive]
126    Message {
127        msg: String,
128        endpoint: Option<String>,
129    },
130    #[non_exhaustive]
131    InvalidArgument {
132        msg: String,
133        arg: Option<String>,
134    },
135    #[non_exhaustive]
136    Encoding {
137        msg: String,
138    },
139    UnsupportedFeature {
140        feature: String,
141    },
142}
143
144impl Display for ErrorKind {
145    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
146        match self {
147            ErrorKind::Server(e) => write!(f, "{e}"),
148            ErrorKind::Http { endpoint } => write!(f, "http error for endpoint {endpoint}"),
149            ErrorKind::Message { msg, endpoint } => {
150                if let Some(endpoint) = endpoint {
151                    write!(f, "message error for endpoint {endpoint}: {msg}")
152                } else {
153                    write!(f, "message error: {msg}")
154                }
155            }
156            ErrorKind::InvalidArgument { msg, arg } => {
157                if let Some(arg) = arg {
158                    write!(f, "invalid argument error for argument {arg}: {msg}")
159                } else {
160                    write!(f, "invalid argument error: {msg}")
161                }
162            }
163            ErrorKind::Encoding { msg } => write!(f, "encoding error: {msg}"),
164            ErrorKind::UnsupportedFeature { feature } => {
165                write!(f, "unsupported feature: {feature}")
166            }
167        }
168    }
169}
170
171#[derive(Clone, Debug, PartialEq, Eq)]
172pub struct ServerError {
173    kind: ServerErrorKind,
174
175    index_name: String,
176
177    error_text: String,
178    endpoint: String,
179    status_code: StatusCode,
180}
181
182impl Display for ServerError {
183    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
184        write!(
185            f,
186            "server error for index {} at endpoint {}, status code: {}: {}, error text: {}",
187            self.index_name, self.endpoint, self.status_code, self.kind, self.error_text
188        )
189    }
190}
191
192impl ServerError {
193    pub(crate) fn new(
194        kind: ServerErrorKind,
195        index_name: impl Into<String>,
196        error_text: impl Into<String>,
197        endpoint: impl Into<String>,
198        status_code: StatusCode,
199    ) -> Self {
200        Self {
201            kind,
202            error_text: error_text.into(),
203            index_name: index_name.into(),
204            endpoint: endpoint.into(),
205            status_code,
206        }
207    }
208
209    pub fn kind(&self) -> &ServerErrorKind {
210        &self.kind
211    }
212
213    pub fn index_name(&self) -> &str {
214        &self.index_name
215    }
216
217    pub fn endpoint(&self) -> &str {
218        &self.endpoint
219    }
220
221    pub fn status_code(&self) -> StatusCode {
222        self.status_code
223    }
224
225    pub fn error_text(&self) -> &str {
226        &self.error_text
227    }
228}
229
230#[derive(Clone, Debug, PartialEq, Eq)]
231#[non_exhaustive]
232pub enum ServerErrorKind {
233    Internal,
234    AuthenticationFailure,
235    IndexExists,
236    IndexNotFound,
237    UnknownIndexType,
238    SourceTypeIncorrect,
239    SourceNotFound,
240    NoIndexPartitionsPlanned,
241    NoIndexPartitionsFound,
242    UnsupportedFeature,
243    RateLimitedFailure,
244    Unknown,
245}
246
247impl Display for ServerErrorKind {
248    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
249        match self {
250            ServerErrorKind::Internal => write!(f, "internal server error"),
251            ServerErrorKind::AuthenticationFailure => write!(f, "authentication failure"),
252            ServerErrorKind::IndexExists => write!(f, "index exists"),
253            ServerErrorKind::IndexNotFound => write!(f, "index not found"),
254            ServerErrorKind::UnknownIndexType => write!(f, "unknown index type"),
255            ServerErrorKind::SourceTypeIncorrect => write!(f, "source type incorrect"),
256            ServerErrorKind::SourceNotFound => write!(f, "source not found"),
257            ServerErrorKind::NoIndexPartitionsPlanned => write!(f, "no index partitions planned"),
258            ServerErrorKind::NoIndexPartitionsFound => write!(f, "no index partitions found"),
259            ServerErrorKind::UnsupportedFeature => write!(f, "unsupported feature"),
260            ServerErrorKind::RateLimitedFailure => write!(f, "rate limited failure"),
261            ServerErrorKind::Unknown => write!(f, "unknown error"),
262        }
263    }
264}