Skip to main content

webdav_server/model/
error.rs

1use std::{num::TryFromIntError, time::SystemTimeError};
2
3use axum::response::IntoResponse;
4use hyper::StatusCode;
5
6use crate::{
7    error::internal,
8    logger::{Level, Loggable, Module},
9    wrap_internal_err,
10};
11
12/// Errors that originate from the model layer (database queries and data mapping).
13///
14/// These errors sit between the raw database driver and the rest of the application.
15/// Most are internal failures from `sqlx` that should never leak to the HTTP client.
16/// The `IntoResponse` implementation ensures only safe, generic messages are returned.
17#[derive(thiserror::Error, Debug)]
18pub enum Error {
19    /// A `sqlx` database error. This covers connection failures, constraint violations,
20    /// malformed queries, and any other error from the `SQLite` driver.
21    #[error("Database Error : {}", .0)]
22    Database(#[from] sqlx::Error),
23
24    /// The requested asset was not found in the database.
25    ///
26    /// This is distinct from a storage-layer `NotFound`. This variant means the asset
27    /// record does not exist in the `assets` table, not necessarily that the file is
28    /// missing from disk.
29    #[error("Asset not found")]
30    AssetNotFound,
31
32    /// A low-level internal error, typically from integer or time conversions.
33    #[error("Internal Err {}", .0)]
34    Internal(#[from] internal::Error),
35}
36
37pub type Result<T> = std::result::Result<T, Error>;
38
39wrap_internal_err! {
40    TryFromIntError, SystemTimeError => Error::Internal
41}
42
43impl IntoResponse for Error {
44    fn into_response(self) -> axum::response::Response {
45        use Error::{AssetNotFound, Database, Internal};
46
47        match self {
48            // Client-facing: safe to expose.
49            AssetNotFound => {
50                (StatusCode::NOT_FOUND, "Asset not found in database")
51            }
52
53            // Internal: hide the SQL details from the client.
54            Database(_) | Internal(_) => {
55                (StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error")
56            }
57        }
58        .into_response()
59    }
60}
61
62impl Loggable for Error {
63    fn log_level(&self) -> crate::logger::Level {
64        use Error::{AssetNotFound, Database, Internal};
65        match self {
66            AssetNotFound => Level::Info,
67            Internal(_) => Level::Fatal,
68            Database(_) => Level::Error,
69        }
70    }
71
72    #[inline]
73    fn log_module(&self) -> crate::logger::Module {
74        Module::Database
75    }
76}