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 thiserror::Error;
14
15#[derive(Error, Debug)]
17pub enum DbErr {
18 #[error("Failed to acquire connection from pool: {0}")]
20 ConnectionAcquire(#[source] ConnAcquireErr),
21 #[error("Error converting `{from}` into `{into}`: {source}")]
23 TryIntoErr {
24 from: &'static str,
26 into: &'static str,
28 source: Box<dyn std::error::Error + Send + Sync>,
30 },
31 #[error("Connection Error: {0}")]
33 Conn(#[source] RuntimeErr),
34 #[error("Execution Error: {0}")]
36 Exec(#[source] RuntimeErr),
37 #[error("Query Error: {0}")]
39 Query(#[source] RuntimeErr),
40 #[error("Type '{0}' cannot be converted from u64")]
42 ConvertFromU64(&'static str),
43 #[error("Failed to unpack last_insert_id")]
45 UnpackInsertId,
46 #[error("Failed to get primary key from model")]
49 UpdateGetPrimaryKey,
50 #[error("RecordNotFound Error: {0}")]
52 RecordNotFound(String),
53 #[error("Attribute {0} is NotSet")]
55 AttrNotSet(String),
56 #[error("Custom Error: {0}")]
58 Custom(String),
59 #[error("Type Error: {0}")]
61 Type(String),
62 #[error("Json Error: {0}")]
64 Json(String),
65 #[error("Migration Error: {0}")]
67 Migration(String),
68 #[error("None of the records are inserted")]
71 RecordNotInserted,
72 #[error("None of the records are updated")]
75 RecordNotUpdated,
76}
77
78#[derive(Debug)]
80pub enum TryGetError {
81 DbErr(DbErr),
83 Null(String),
85}
86
87#[derive(Error, Debug, PartialEq, Eq)]
89pub enum ConnAcquireErr {
90 #[error("Connection pool timed out")]
92 Timeout,
93 #[error("Connection closed")]
95 ConnectionClosed,
96}
97
98#[derive(Error, Debug)]
100pub enum RuntimeErr {
101 #[cfg(feature = "sqlx-dep")]
103 #[error("{0}")]
104 SqlxError(#[source] sqlx::error::Error),
105 #[error("{0}")]
107 Internal(String),
108}
109
110impl PartialEq for DbErr {
111 fn eq(&self, other: &Self) -> bool {
112 self.to_string() == other.to_string()
113 }
114}
115
116impl Eq for DbErr {}
117
118#[derive(Error, Debug)]
120#[error("Failed to match \"{0}\" as Column")]
121pub struct ColumnFromStrErr(pub String);
122
123#[allow(dead_code)]
124pub(crate) fn conn_err<T>(s: T) -> DbErr
125where
126 T: ToString,
127{
128 DbErr::Conn(RuntimeErr::Internal(s.to_string()))
129}
130
131#[allow(dead_code)]
132pub(crate) fn exec_err<T>(s: T) -> DbErr
133where
134 T: ToString,
135{
136 DbErr::Exec(RuntimeErr::Internal(s.to_string()))
137}
138
139#[allow(dead_code)]
140pub(crate) fn query_err<T>(s: T) -> DbErr
141where
142 T: ToString,
143{
144 DbErr::Query(RuntimeErr::Internal(s.to_string()))
145}
146
147#[allow(dead_code)]
148pub(crate) fn type_err<T>(s: T) -> DbErr
149where
150 T: ToString,
151{
152 DbErr::Type(s.to_string())
153}
154
155#[allow(dead_code)]
156pub(crate) fn json_err<T>(s: T) -> DbErr
157where
158 T: ToString,
159{
160 DbErr::Json(s.to_string())
161}
162
163#[derive(Error, Debug, Clone, PartialEq, Eq)]
165#[non_exhaustive]
166pub enum SqlErr {
167 #[error("Unique Constraint Violated: {0}")]
169 UniqueConstraintViolation(String),
170 #[error("Foreign Key Constraint Violated: {0}")]
172 ForeignKeyConstraintViolation(String),
173}
174
175#[allow(dead_code)]
176impl DbErr {
177 pub fn sql_err(&self) -> Option<SqlErr> {
179 #[cfg(any(
180 feature = "sqlx-mysql",
181 feature = "sqlx-postgres",
182 feature = "sqlx-sqlite"
183 ))]
184 {
185 use std::ops::Deref;
186 if let DbErr::Exec(RuntimeErr::SqlxError(sqlx::Error::Database(e)))
187 | DbErr::Query(RuntimeErr::SqlxError(sqlx::Error::Database(e))) = self
188 {
189 let error_code = e.code().unwrap_or_default();
190 let _error_code_expanded = error_code.deref();
191 #[cfg(feature = "sqlx-mysql")]
192 if e.try_downcast_ref::<sqlx::mysql::MySqlDatabaseError>()
193 .is_some()
194 {
195 let error_number = e
196 .try_downcast_ref::<sqlx::mysql::MySqlDatabaseError>()?
197 .number();
198 match error_number {
199 1022 | 1062 | 1169 | 1586 => {
204 return Some(SqlErr::UniqueConstraintViolation(e.message().into()))
205 }
206 1216 | 1217 | 1451 | 1452 | 1557 | 1761 | 1762 => {
214 return Some(SqlErr::ForeignKeyConstraintViolation(e.message().into()))
215 }
216 _ => return None,
217 }
218 }
219 #[cfg(feature = "sqlx-postgres")]
220 if e.try_downcast_ref::<sqlx::postgres::PgDatabaseError>()
221 .is_some()
222 {
223 match _error_code_expanded {
224 "23505" => {
225 return Some(SqlErr::UniqueConstraintViolation(e.message().into()))
226 }
227 "23503" => {
228 return Some(SqlErr::ForeignKeyConstraintViolation(e.message().into()))
229 }
230 _ => return None,
231 }
232 }
233 #[cfg(feature = "sqlx-sqlite")]
234 if e.try_downcast_ref::<sqlx::sqlite::SqliteError>().is_some() {
235 match _error_code_expanded {
236 "1555" | "2067" => {
239 return Some(SqlErr::UniqueConstraintViolation(e.message().into()))
240 }
241 "787" => {
242 return Some(SqlErr::ForeignKeyConstraintViolation(e.message().into()))
243 }
244 _ => return None,
245 }
246 }
247 }
248 }
249 None
250 }
251}