Skip to main content

invoice_cli/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum AppError {
5    #[error("Invalid input: {0}")]
6    InvalidInput(String),
7
8    #[error("Config error: {0}")]
9    Config(String),
10
11    #[error("Not found: {0}")]
12    NotFound(String),
13
14    #[error("Ambiguous: {0}")]
15    Ambiguous(String),
16
17    #[error("IO error: {0}")]
18    Io(#[from] std::io::Error),
19
20    #[error("Database error: {0}")]
21    Db(#[from] rusqlite::Error),
22
23    #[error("Serde error: {0}")]
24    Serde(#[from] serde_json::Error),
25
26    #[error("Typst render error: {0}")]
27    Render(String),
28
29    #[error(transparent)]
30    Core(#[from] finance_core::error::CoreError),
31
32    #[error("Other: {0}")]
33    Other(String),
34}
35
36impl AppError {
37    pub fn exit_code(&self) -> i32 {
38        match self {
39            Self::InvalidInput(_) | Self::Ambiguous(_) => 3,
40            Self::Config(_) => 2,
41            Self::NotFound(_) => 3,
42            Self::Io(_) | Self::Render(_) | Self::Other(_) => 1,
43            Self::Db(_) | Self::Serde(_) => 1,
44            Self::Core(_) => 1,
45        }
46    }
47
48    pub fn error_code(&self) -> &'static str {
49        match self {
50            Self::InvalidInput(_) => "invalid_input",
51            Self::Ambiguous(_) => "ambiguous",
52            Self::Config(_) => "config_error",
53            Self::NotFound(_) => "not_found",
54            Self::Io(_) => "io_error",
55            Self::Db(_) => "db_error",
56            Self::Serde(_) => "serde_error",
57            Self::Render(_) => "render_error",
58            Self::Core(_) => "core_error",
59            Self::Other(_) => "other",
60        }
61    }
62
63    pub fn suggestion(&self) -> &'static str {
64        match self {
65            Self::InvalidInput(_) => "Check arguments with: invoice --help",
66            Self::Ambiguous(_) => "Use the full id or a more specific slug",
67            Self::Config(_) => "Check config with: invoice config show",
68            Self::NotFound(_) => "List available entities with: invoice <kind> list",
69            Self::Io(_) => "Retry the command",
70            Self::Db(_) => "Check database integrity: invoice doctor",
71            Self::Serde(_) => "Malformed data — check input",
72            Self::Render(_) => "Typst render failed — run: invoice doctor",
73            Self::Core(_) => "Check diagnostics: invoice doctor",
74            Self::Other(_) => "",
75        }
76    }
77}
78
79pub type Result<T> = std::result::Result<T, AppError>;