vrc_get_litedb/
lib.rs

1//! # LiteDB in Rust
2//! This is a reimplementation of [LiteDB] in Rust.
3//!
4//! This implementation (currently?) only supports single-threaded operation.
5//!
6//! [LiteDB]: <https://www.litedb.org/>
7
8#![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}