1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use core::fmt;

#[derive(Debug, Clone)]
pub struct Error {
  status: u16,
  details: String,
}

impl Error {
  pub fn new(status: u16, details: String) -> Self {
    Self { status, details }
  }

  pub fn status(&self) -> u16 {
    self.status
  }

  pub fn details(&self) -> &str {
    &self.details
  }
}

impl fmt::Display for Error {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    write!(f, "{}", self.details)
  }
}

impl std::error::Error for Error {
  fn description(&self) -> &str {
    &self.details
  }
}

impl From<sqlx::Error> for Error {
  fn from(error: sqlx::Error) -> Self {
    match error {
      sqlx::Error::RowNotFound => Error::new(404, "Not found".to_string()),
      sqlx::Error::ColumnIndexOutOfBounds { .. } => Error::new(422, error.to_string()),
      sqlx::Error::ColumnNotFound { .. } => Error::new(422, error.to_string()),
      sqlx::Error::ColumnDecode { .. } => Error::new(422, error.to_string()),
      sqlx::Error::Decode(_) => Error::new(422, error.to_string()),
      sqlx::Error::PoolTimedOut => Error::new(503, error.to_string()),
      sqlx::Error::PoolClosed => Error::new(503, error.to_string()),
      sqlx::Error::Tls(_) => Error::new(500, error.to_string()),
      sqlx::Error::Io(_) => Error::new(500, error.to_string()),
      sqlx::Error::Protocol(_) => Error::new(500, error.to_string()),
      sqlx::Error::Configuration(_) => Error::new(500, error.to_string()),
      sqlx::Error::AnyDriverError(_) => Error::new(500, error.to_string()),
      sqlx::Error::Database(err) => {
        if let Some(code) = err.code() {
          match code.trim() {
            // Unique violation
            "23505" => return Error::new(409, err.to_string()),
            _ => (),
          }
        }
        Error::new(500, err.to_string())
      }
      sqlx::Error::Migrate(_) => Error::new(500, error.to_string()),
      sqlx::Error::TypeNotFound { type_name } => {
        Error::new(500, format!("Type not found: {}", type_name))
      }
      sqlx::Error::WorkerCrashed => Error::new(500, error.to_string()),
      _ => Error::new(500, error.to_string()),
    }
  }
}