1#[cfg(feature = "sqlx-dep")]
2pub use sqlx::error::Error as SqlxError;
3
4#[cfg(feature = "sqlx-mysql")]
5pub use sqlx::mysql::MySqlDatabaseError as SqlxMySqlError;
6
7#[cfg(feature = "sqlx-postgres")]
8pub use sqlx::postgres::PgDatabaseError as SqlxPostgresError;
9
10#[cfg(feature = "sqlx-sqlite")]
11pub use sqlx::sqlite::SqliteError as SqlxSqliteError;
12
13use std::sync::Arc;
14use thiserror::Error;
15
16#[derive(Error, Debug, Clone)]
18pub enum DbErr {
19 #[error("Failed to acquire connection from pool: {0}")]
21 ConnectionAcquire(#[source] ConnAcquireErr),
22 #[error("Error converting `{from}` into `{into}`: {source}")]
24 TryIntoErr {
25 from: &'static str,
27 into: &'static str,
29 source: Arc<dyn std::error::Error>,
31 },
32 #[error("Connection Error: {0}")]
34 Conn(#[source] RuntimeErr),
35 #[error("Execution Error: {0}")]
37 Exec(#[source] RuntimeErr),
38 #[error("Query Error: {0}")]
40 Query(#[source] RuntimeErr),
41 #[error("Type '{0}' cannot be converted from u64")]
43 ConvertFromU64(&'static str),
44 #[error("Failed to unpack last_insert_id")]
46 UnpackInsertId,
47 #[error("Failed to get primary key from model")]
50 UpdateGetPrimaryKey,
51 #[error("RecordNotFound Error: {0}")]
53 RecordNotFound(String),
54 #[error("Attribute {0} is NotSet")]
56 AttrNotSet(String),
57 #[error("Custom Error: {0}")]
59 Custom(String),
60 #[error("Type Error: {0}")]
62 Type(String),
63 #[error("Json Error: {0}")]
65 Json(String),
66 #[error("Migration Error: {0}")]
68 Migration(String),
69 #[error("None of the records are inserted")]
72 RecordNotInserted,
73 #[error("None of the records are updated")]
76 RecordNotUpdated,
77 #[error("Operation not supported by backend {db}: {ctx}")]
79 BackendNotSupported {
80 db: &'static str,
82 ctx: &'static str,
84 },
85 #[error("Key arity mismatch: expected {expected}, received {received}")]
87 KeyArityMismatch {
88 expected: u8,
90 received: u8,
92 },
93 #[error("Primay key not set for {ctx}")]
95 PrimaryKeyNotSet {
96 ctx: &'static str,
98 },
99 #[error("RBAC error: {0}")]
101 RbacError(String),
102 #[error("Access denied: cannot perform `{permission}` on `{resource}`")]
104 AccessDenied {
105 permission: String,
107 resource: String,
109 },
110 #[error("Mutex poisoned")]
112 MutexPoisonError,
113}
114
115#[derive(Debug)]
117pub enum TryGetError {
118 DbErr(DbErr),
120 Null(String),
122}
123
124#[derive(Error, Debug, PartialEq, Eq, Copy, Clone)]
126pub enum ConnAcquireErr {
127 #[error("Connection pool timed out")]
129 Timeout,
130 #[error("Connection closed")]
132 ConnectionClosed,
133}
134
135#[derive(Error, Debug, Clone)]
137pub enum RuntimeErr {
138 #[cfg(feature = "sqlx-dep")]
140 #[error("{0}")]
141 SqlxError(Arc<sqlx::error::Error>),
142 #[cfg(feature = "rusqlite")]
144 #[error("{0}")]
145 Rusqlite(Arc<crate::driver::rusqlite::RusqliteError>),
146 #[error("{0}")]
148 Internal(String),
149}
150
151impl PartialEq for DbErr {
152 fn eq(&self, other: &Self) -> bool {
153 self.to_string() == other.to_string()
154 }
155}
156
157impl Eq for DbErr {}
158
159#[derive(Error, Debug)]
161#[error("Failed to match \"{0}\" as Column")]
162pub struct ColumnFromStrErr(pub String);
163
164#[allow(dead_code)]
165pub(crate) fn conn_err<T>(s: T) -> DbErr
166where
167 T: ToString,
168{
169 DbErr::Conn(RuntimeErr::Internal(s.to_string()))
170}
171
172#[allow(dead_code)]
173pub(crate) fn exec_err<T>(s: T) -> DbErr
174where
175 T: ToString,
176{
177 DbErr::Exec(RuntimeErr::Internal(s.to_string()))
178}
179
180#[allow(dead_code)]
181pub(crate) fn query_err<T>(s: T) -> DbErr
182where
183 T: ToString,
184{
185 DbErr::Query(RuntimeErr::Internal(s.to_string()))
186}
187
188#[allow(dead_code)]
189pub(crate) fn type_err<T>(s: T) -> DbErr
190where
191 T: ToString,
192{
193 DbErr::Type(s.to_string())
194}
195
196#[allow(dead_code)]
197pub(crate) fn json_err<T>(s: T) -> DbErr
198where
199 T: ToString,
200{
201 DbErr::Json(s.to_string())
202}
203
204#[derive(Error, Debug, Clone, PartialEq, Eq)]
206#[non_exhaustive]
207pub enum SqlErr {
208 #[error("Unique Constraint Violated: {0}")]
210 UniqueConstraintViolation(String),
211 #[error("Foreign Key Constraint Violated: {0}")]
213 ForeignKeyConstraintViolation(String),
214}
215
216#[allow(dead_code)]
217impl DbErr {
218 pub fn sql_err(&self) -> Option<SqlErr> {
220 #[cfg(any(
221 feature = "sqlx-mysql",
222 feature = "sqlx-postgres",
223 feature = "sqlx-sqlite"
224 ))]
225 {
226 use std::ops::Deref;
227 if let DbErr::Exec(RuntimeErr::SqlxError(e)) | DbErr::Query(RuntimeErr::SqlxError(e)) =
228 self
229 {
230 if let sqlx::Error::Database(e) = e.deref() {
231 let error_code = e.code().unwrap_or_default();
232 let _error_code_expanded = error_code.deref();
233 #[cfg(feature = "sqlx-mysql")]
234 if e.try_downcast_ref::<sqlx::mysql::MySqlDatabaseError>()
235 .is_some()
236 {
237 let error_number = e
238 .try_downcast_ref::<sqlx::mysql::MySqlDatabaseError>()?
239 .number();
240 match error_number {
241 1022 | 1062 | 1169 | 1586 => {
246 return Some(SqlErr::UniqueConstraintViolation(e.message().into()));
247 }
248 1216 | 1217 | 1451 | 1452 | 1557 | 1761 | 1762 => {
256 return Some(SqlErr::ForeignKeyConstraintViolation(
257 e.message().into(),
258 ));
259 }
260 _ => return None,
261 }
262 }
263 #[cfg(feature = "sqlx-postgres")]
264 if e.try_downcast_ref::<sqlx::postgres::PgDatabaseError>()
265 .is_some()
266 {
267 match _error_code_expanded {
268 "23505" => {
269 return Some(SqlErr::UniqueConstraintViolation(e.message().into()));
270 }
271 "23503" => {
272 return Some(SqlErr::ForeignKeyConstraintViolation(
273 e.message().into(),
274 ));
275 }
276 _ => return None,
277 }
278 }
279 #[cfg(feature = "sqlx-sqlite")]
280 if e.try_downcast_ref::<sqlx::sqlite::SqliteError>().is_some() {
281 match _error_code_expanded {
282 "1555" | "2067" => {
285 return Some(SqlErr::UniqueConstraintViolation(e.message().into()));
286 }
287 "787" => {
288 return Some(SqlErr::ForeignKeyConstraintViolation(
289 e.message().into(),
290 ));
291 }
292 _ => return None,
293 }
294 }
295 }
296 }
297 }
298 #[cfg(feature = "rusqlite")]
299 if let DbErr::Exec(RuntimeErr::Rusqlite(err)) | DbErr::Query(RuntimeErr::Rusqlite(err)) =
300 self
301 {
302 use crate::driver::rusqlite::RusqliteError;
303 use std::ops::Deref;
304
305 if let RusqliteError::SqliteFailure(err, msg) = err.deref() {
306 match err.extended_code {
307 1555 | 2067 => {
308 return Some(SqlErr::UniqueConstraintViolation(
309 msg.to_owned().unwrap_or_else(|| err.to_string()),
310 ));
311 }
312 787 => {
313 return Some(SqlErr::ForeignKeyConstraintViolation(
314 msg.to_owned().unwrap_or_else(|| err.to_string()),
315 ));
316 }
317 _ => (),
318 }
319 }
320 }
321 None
322 }
323}