1use sea_orm::{DbErr, SqlErr};
2use sova_core::extend::ErrorResponse;
3use sova_core::{Error, IntoResponse, Response};
4
5#[derive(Debug)]
7pub struct DbError(pub DbErr);
8
9impl From<DbErr> for DbError {
10 fn from(err: DbErr) -> Self {
11 Self(err)
12 }
13}
14
15fn map_db_err(err: DbErr) -> Error {
16 let (status, public) = if matches!(err, DbErr::RecordNotFound(_)) {
17 (404, "Not Found")
18 } else if let Some(sql) = err.sql_err() {
19 match sql {
20 SqlErr::UniqueConstraintViolation(_) => (409, "Conflict"),
21 SqlErr::ForeignKeyConstraintViolation(_) => (422, "Unprocessable Entity"),
22 _ => match &err {
23 DbErr::ConnectionAcquire(_) | DbErr::Conn(_) => (503, "Service Unavailable"),
24 _ => (500, "Internal Server Error"),
25 },
26 }
27 } else {
28 match &err {
29 DbErr::ConnectionAcquire(_) | DbErr::Conn(_) => (503, "Service Unavailable"),
30 _ => (500, "Internal Server Error"),
31 }
32 };
33 if status >= 500 {
34 tracing::error!(error = %err, "database error");
35 }
36 Error::Response(Box::new(Response::text(public).status(status)))
37}
38
39impl From<DbError> for Error {
40 fn from(err: DbError) -> Self {
41 map_db_err(err.0)
42 }
43}
44
45impl IntoResponse for DbError {
46 fn into_response(self) -> Response {
47 Error::from(self).into_response()
48 }
49}
50
51impl ErrorResponse for DbError {}