1#![forbid(unsafe_code)]
4#![warn(
5 clippy::cargo,
6 missing_docs,
7 clippy::pedantic,
9 future_incompatible,
10 rust_2018_idioms,
11)]
12#![allow(
13 clippy::missing_errors_doc, clippy::option_if_let_else,
15 clippy::module_name_repetitions,
16 clippy::use_self, )]
18
19pub mod permissions;
21
22pub mod admin;
24pub mod connection;
26pub mod document;
27pub mod limits;
28pub mod schema;
30pub mod transaction;
32
33pub mod keyvalue;
35
36pub mod api;
38
39pub mod key;
41
42pub mod networking;
44
45pub mod pubsub;
47
48use std::fmt::Display;
49use std::string::FromUtf8Error;
50
51use schema::{view, CollectionName, SchemaName, ViewName};
52use serde::{Deserialize, Serialize};
53pub use {
54 actionable, arc_bytes, async_trait, circulate, num_traits, ordered_varint, transmog,
55 transmog_pot,
56};
57
58use crate::api::ApiName;
59use crate::connection::HasSchema;
60use crate::document::{DocumentId, Header, InvalidHexadecimal};
61use crate::key::time::TimeError;
62use crate::key::NextValueError;
63use crate::schema::InsertError;
64
65#[derive(Clone, thiserror::Error, Debug, Serialize, Deserialize)]
67pub enum Error {
68 #[error(
71 "database '{database_name}' was created with schema '{stored_schema}', not '{schema}'"
72 )]
73 SchemaMismatch {
74 database_name: String,
76
77 schema: SchemaName,
79
80 stored_schema: SchemaName,
82 },
83
84 #[error("schema '{0}' was already registered")]
86 SchemaAlreadyRegistered(SchemaName),
87
88 #[error("schema '{0}' is not registered")]
90 SchemaNotRegistered(SchemaName),
91
92 #[error("view '{0}' was already registered")]
94 ViewAlreadyRegistered(ViewName),
95
96 #[error("invalid database name: {0}")]
100 InvalidDatabaseName(String),
101
102 #[error("database '{0}' was not found")]
104 DatabaseNotFound(String),
105
106 #[error("view was not found")]
108 ViewNotFound,
109
110 #[error("collection was not found")]
112 CollectionNotFound,
113
114 #[error("api '{0}' was not found")]
116 ApiNotFound(ApiName),
117
118 #[error("a database with name '{0}' already exists")]
120 DatabaseNameAlreadyTaken(String),
121
122 #[error("a networking error occurred: '{0}'")]
124 Networking(networking::Error),
125
126 #[error("attempted to define a collection that already has been defined")]
128 CollectionAlreadyDefined,
129
130 #[error("the requested document id {1} from collection {0} was not found")]
132 DocumentNotFound(CollectionName, Box<DocumentId>),
133
134 #[error(
136 "an value was provided for a `DocumentId` that was larger than `DocumentId::MAX_LENGTH`"
137 )]
138 DocumentIdTooLong,
139
140 #[error("a conflict was detected while updating document {1} from collection {0}")]
144 DocumentConflict(CollectionName, Box<Header>),
145
146 #[error("a unique key violation occurred: document `{existing_document}` already has the same key as `{conflicting_document}` for {view}")]
150 UniqueKeyViolation {
151 view: ViewName,
153 conflicting_document: Box<Header>,
155 existing_document: Box<Header>,
157 },
158
159 #[error("an error occurred generating a new unique id for {0}: {1}")]
161 DocumentPush(CollectionName, NextValueError),
162
163 #[error("an invalid name was used in a schema: {0}")]
165 InvalidName(#[from] schema::InvalidNameError),
166
167 #[error("permission error: {0}")]
169 PermissionDenied(#[from] actionable::PermissionDenied),
170
171 #[error("error with password: {0}")]
173 Password(String),
174
175 #[error("user not found")]
179 UserNotFound,
180
181 #[error("invalid string: {0}")]
183 InvalidUnicode(String),
184
185 #[error("invalid credentials")]
187 InvalidCredentials,
188
189 #[error("reduce is unimplemented")]
191 ReduceUnimplemented,
192
193 #[error("floating point operation yielded NaN")]
195 NotANumber,
196
197 #[error("time error: {0}")]
199 Time(#[from] TimeError),
200
201 #[error("error from {origin}: {error}")]
203 Other {
204 origin: String,
206 error: String,
208 },
209}
210
211impl Error {
212 pub fn other(origin: impl Display, error: impl Display) -> Self {
214 Self::Other {
215 origin: origin.to_string(),
216 error: error.to_string(),
217 }
218 }
219
220 pub fn is_unique_key_error<View: schema::View, C: HasSchema>(&self, connection: &C) -> bool {
223 if let Self::UniqueKeyViolation { view, .. } = self {
224 if let Ok(schema_view) = connection.schematic().view::<View>() {
225 return view == &schema_view.view_name();
226 }
227 }
228
229 false
230 }
231
232 #[must_use]
235 pub fn conflicting_document<Collection: schema::Collection>(&self) -> Option<Header> {
236 match self {
237 Self::DocumentConflict(collection, header)
238 if collection == &Collection::collection_name() =>
239 {
240 Some(header.as_ref().clone())
241 }
242 _ => None,
243 }
244 }
245}
246
247impl From<pot::Error> for Error {
248 fn from(err: pot::Error) -> Self {
249 Self::other("pot", err)
250 }
251}
252
253impl<T> From<InsertError<T>> for Error {
254 fn from(err: InsertError<T>) -> Self {
255 err.error
256 }
257}
258
259impl From<view::Error> for Error {
260 fn from(err: view::Error) -> Self {
261 Self::other("view", err)
262 }
263}
264
265impl From<FromUtf8Error> for Error {
266 fn from(err: FromUtf8Error) -> Self {
267 Self::InvalidUnicode(err.to_string())
268 }
269}
270
271impl From<InvalidHexadecimal> for Error {
272 fn from(err: InvalidHexadecimal) -> Self {
273 Self::other("invalid hexadecimal", err)
274 }
275}
276
277#[cfg(any(feature = "test-util", test))]
279#[allow(missing_docs)]
280pub mod test_util;
281
282#[cfg(feature = "encryption")]
284pub const ENCRYPTION_ENABLED: bool = true;
285
286#[cfg(not(feature = "encryption"))]
288pub const ENCRYPTION_ENABLED: bool = false;
289
290pub trait AnyError: std::error::Error + Send + Sync + 'static {}
292
293impl<T> AnyError for T where T: std::error::Error + Send + Sync + 'static {}