1#![allow(clippy::too_many_arguments)]
9
10use crate::bson::Value;
11use crate::engine::{BasePage, PageType};
12use std::fmt::Display;
13
14#[macro_use]
15pub mod bson;
16pub mod engine;
17pub mod expression;
18mod utils;
19
20#[cfg(all(feature = "shared-mutex", windows))]
21pub mod shared_mutex;
22#[cfg(feature = "tokio-fs")]
23pub mod tokio_fs;
24
25pub type Result<T> = std::result::Result<T, Error>;
26
27pub struct Error(Box<ErrorImpl>);
28
29use err_impl::Error as ErrorImpl;
30
31mod err_impl {
32 use super::*;
33 #[derive(Debug)]
34 pub(crate) enum Error {
35 Io(std::io::Error),
36 Parser(expression::ParseError),
37
38 Eval(String),
39
40 InvalidDatabase,
41 InvalidPage,
42 DatetimeOverflow,
43 Encrypted,
44 CollationMismatch,
45 InvalidPageType {
46 expected: PageType,
47 actual: PageType,
48 page: u32,
49 },
50 CollectionIndexLimitReached,
51 CollectionNameHeaderSpaceExceeds(String),
52 InvalidCollectionName(String),
53 InvalidBson,
54 SizeLimitReached,
55 TransactionLimitReached,
56 InvalidIndexKeyType,
57 IndexKeySizeExceeded,
58 DuplicatedIndexKey {
59 index: String,
60 key: Value,
61 },
62 CollectionNameAlreadyExists(String),
63 DocumentSizeLimitExceeded,
64 IndexAlreadyExists(String),
65 DropIdIndex,
66 BadAutoId {
67 auto_id: engine::BsonAutoId,
68 collection_name: String,
69 last_id: Value,
70 },
71 InvalidFieldType {
72 field: String,
73 value: Value,
74 },
75 }
76}
77
78impl Error {
79 fn new(inner: ErrorImpl) -> Error {
80 Error(Box::new(inner))
81 }
82
83 pub(crate) fn invalid_database() -> Error {
84 Error::new(ErrorImpl::InvalidDatabase)
85 }
86
87 pub(crate) fn invalid_page() -> Error {
88 Error::new(ErrorImpl::InvalidPage)
89 }
90
91 pub(crate) fn datetime_overflow() -> Error {
92 Error::new(ErrorImpl::DatetimeOverflow)
93 }
94
95 pub(crate) fn encrypted_no_password() -> Error {
96 Error::new(ErrorImpl::Encrypted)
97 }
98
99 pub(crate) fn collation_not_match() -> Error {
100 Error::new(ErrorImpl::CollationMismatch)
101 }
102
103 pub(crate) fn invalid_page_type(expected: PageType, page: BasePage) -> Error {
104 Error::new(ErrorImpl::InvalidPageType {
105 expected,
106 actual: page.page_type(),
107 page: page.page_id(),
108 })
109 }
110
111 pub(crate) fn collection_index_limit_reached() -> Error {
112 Error::new(ErrorImpl::CollectionIndexLimitReached)
113 }
114
115 pub(crate) fn name_length_header_space(name: &str) -> Error {
116 Error::new(ErrorImpl::CollectionNameHeaderSpaceExceeds(
117 name.to_string(),
118 ))
119 }
120
121 pub(crate) fn invalid_collection_name(name: &str) -> Error {
122 Error::new(ErrorImpl::InvalidCollectionName(name.to_string()))
123 }
124
125 pub(crate) fn invalid_bson() -> Error {
126 Error::new(ErrorImpl::InvalidBson)
127 }
128
129 pub(crate) fn size_limit_reached() -> Self {
130 Error::new(ErrorImpl::SizeLimitReached)
131 }
132
133 pub(crate) fn transaction_limit() -> Error {
134 Error::new(ErrorImpl::TransactionLimitReached)
135 }
136
137 pub(crate) fn invalid_index_key_type() -> Error {
138 Error::new(ErrorImpl::InvalidIndexKeyType)
139 }
140
141 pub(crate) fn index_key_too_long() -> Error {
142 Error::new(ErrorImpl::IndexKeySizeExceeded)
143 }
144
145 pub(crate) fn index_duplicate_key(index: &str, key: Value) -> Error {
146 Error::new(ErrorImpl::DuplicatedIndexKey {
147 index: index.to_string(),
148 key,
149 })
150 }
151
152 pub(crate) fn already_exists_collection_name(name: &str) -> Error {
153 Error::new(ErrorImpl::CollectionNameAlreadyExists(name.to_string()))
154 }
155
156 pub(crate) fn document_size_exceed_limit() -> Self {
157 Error::new(ErrorImpl::DocumentSizeLimitExceeded)
158 }
159
160 pub(crate) fn index_already_exists(name: &str) -> Error {
161 Error::new(ErrorImpl::IndexAlreadyExists(name.to_string()))
162 }
163
164 pub(crate) fn drop_id_index() -> Error {
165 Error::new(ErrorImpl::DropIdIndex)
166 }
167
168 #[allow(dead_code)]
169 pub(crate) fn bad_auto_id(
170 auto_id: engine::BsonAutoId,
171 collection_name: &str,
172 last_id: Value,
173 ) -> Self {
174 Error::new(ErrorImpl::BadAutoId {
175 auto_id,
176 collection_name: collection_name.to_string(),
177 last_id,
178 })
179 }
180
181 pub(crate) fn invalid_data_type(field: &str, value: &Value) -> Error {
182 Error::new(ErrorImpl::InvalidFieldType {
183 field: field.to_string(),
184 value: value.clone(),
185 })
186 }
187
188 pub(crate) fn expr_run_error(str: &str) -> Self {
189 Self::new(ErrorImpl::Eval(format!("executing: {}", str)))
190 }
191}
192
193impl From<std::io::Error> for Error {
194 fn from(err: std::io::Error) -> Self {
195 Error::new(ErrorImpl::Io(err))
196 }
197}
198
199impl From<bson::ParseError> for Error {
200 fn from(_: bson::ParseError) -> Self {
201 Error::new(ErrorImpl::InvalidBson)
202 }
203}
204
205impl From<expression::ParseError> for Error {
206 fn from(err: expression::ParseError) -> Self {
207 Error::new(ErrorImpl::Parser(err))
208 }
209}
210
211impl Display for Error {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 match self.0.as_ref() {
214 ErrorImpl::Io(e) => e.fmt(f),
215 ErrorImpl::Parser(e) => e.fmt(f),
216 ErrorImpl::Eval(e) => e.fmt(f),
217
218 ErrorImpl::InvalidDatabase => f.write_str("Invalid database"),
219 ErrorImpl::InvalidPage => f.write_str("Invalid page"),
220 ErrorImpl::DatetimeOverflow => f.write_str("DateTime overflow"),
221 ErrorImpl::Encrypted => f.write_str("Encrypted database without password"),
222 ErrorImpl::CollationMismatch => f.write_str("Collation not match"),
223 ErrorImpl::InvalidPageType {
224 expected,
225 actual,
226 page,
227 } => write!(
228 f,
229 "Invalid page type: expected {:?}, got {:?} at page {}",
230 expected, actual, page
231 ),
232 ErrorImpl::CollectionIndexLimitReached => f.write_str("Collection index limit reached"),
233 ErrorImpl::CollectionNameHeaderSpaceExceeds(name) => write!(
234 f,
235 "Collection name length exceeds available header space: {}",
236 name
237 ),
238 ErrorImpl::InvalidCollectionName(name) => {
239 write!(f, "Invalid collection name: {}", name)
240 }
241 ErrorImpl::InvalidBson => f.write_str("Invalid BSON"),
242 ErrorImpl::SizeLimitReached => f.write_str("Size limit reached"),
243 ErrorImpl::TransactionLimitReached => {
244 f.write_str("Maximum number of transactions reached")
245 }
246 ErrorImpl::InvalidIndexKeyType => f.write_str(
247 "Invalid index key: Min/Max or Document Value are not supported as index key",
248 ),
249 ErrorImpl::IndexKeySizeExceeded => f.write_str("Invalid index key: Index key too long"),
250 ErrorImpl::DuplicatedIndexKey { index, key } => write!(
251 f,
252 "Duplicate index key in unique index `{index}`, key: {key:?}"
253 ),
254 ErrorImpl::CollectionNameAlreadyExists(name) => {
255 write!(f, "Collection name '{}' already exists", name)
256 }
257 ErrorImpl::DocumentSizeLimitExceeded => f.write_str("Document size limit reached"),
258 ErrorImpl::IndexAlreadyExists(name) => write!(f, "Index '{}' already exists", name),
259 ErrorImpl::DropIdIndex => f.write_str("Drop _id index"),
260 ErrorImpl::BadAutoId {
261 auto_id,
262 collection_name,
263 last_id,
264 } => write!(
265 f,
266 "It's not possible use AutoId={auto_id:?} because '{collection_name}' collection contains not only numbers in _id index ({last_id:?})."
267 ),
268 ErrorImpl::InvalidFieldType { field, value } => {
269 write!(f, "Invalid field type: {field}, value: {value:?}")
270 }
271 }
272 }
273}
274
275impl std::fmt::Debug for Error {
276 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
277 <ErrorImpl as std::fmt::Debug>::fmt(&self.0, f)
278 }
279}
280
281impl std::error::Error for Error {}
282
283impl From<Error> for std::io::Error {
284 fn from(value: Error) -> Self {
285 use std::io::ErrorKind::*;
286 let kind = match *value.0 {
287 ErrorImpl::Io(e) => return e,
288 ErrorImpl::Parser(_) => InvalidInput,
289 ErrorImpl::Eval(_) => InvalidInput,
290 ErrorImpl::InvalidDatabase => InvalidData,
291 ErrorImpl::InvalidPage => InvalidData,
292 ErrorImpl::DatetimeOverflow => InvalidData,
293 ErrorImpl::Encrypted => InvalidInput,
294 ErrorImpl::CollationMismatch => InvalidInput,
295 ErrorImpl::InvalidPageType { .. } => InvalidInput,
296 ErrorImpl::CollectionIndexLimitReached => InvalidInput,
297 ErrorImpl::CollectionNameHeaderSpaceExceeds(_) => InvalidInput,
298 ErrorImpl::InvalidCollectionName(_) => InvalidInput,
299 ErrorImpl::InvalidBson => InvalidData,
300 ErrorImpl::SizeLimitReached => InvalidInput,
301 ErrorImpl::TransactionLimitReached => QuotaExceeded,
302 ErrorImpl::InvalidIndexKeyType => InvalidData,
303 ErrorImpl::IndexKeySizeExceeded => InvalidData,
304 ErrorImpl::DuplicatedIndexKey { .. } => InvalidData,
305 ErrorImpl::CollectionNameAlreadyExists(_) => InvalidInput,
306 ErrorImpl::DocumentSizeLimitExceeded => InvalidData,
307 ErrorImpl::IndexAlreadyExists(_) => AlreadyExists,
308 ErrorImpl::DropIdIndex => PermissionDenied,
309 ErrorImpl::BadAutoId { .. } => InvalidData,
310 ErrorImpl::InvalidFieldType { .. } => InvalidInput,
311 };
312
313 std::io::Error::new(kind, value)
314 }
315}