1#[derive(Debug)]
4pub enum Error {
5 NotFound,
7 Invalid,
9 Db(rusqlite::Error),
11 Other(String),
14}
15
16impl From<rusqlite::Error> for Error {
17 fn from(e: rusqlite::Error) -> Self {
18 Error::Db(e)
19 }
20}
21
22impl From<anyhow::Error> for Error {
23 fn from(e: anyhow::Error) -> Self {
24 Error::Other(e.to_string())
25 }
26}
27
28impl std::fmt::Display for Error {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 Error::NotFound => write!(f, "not found"),
32 Error::Invalid => write!(f, "invalid input"),
33 Error::Db(e) => write!(f, "database error: {e}"),
34 Error::Other(msg) => write!(f, "{msg}"),
35 }
36 }
37}
38
39impl std::error::Error for Error {}
40
41pub type Result<T> = std::result::Result<T, Error>;
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn display_matches_each_variant() {
49 assert_eq!(Error::NotFound.to_string(), "not found");
50 assert_eq!(Error::Invalid.to_string(), "invalid input");
51 assert_eq!(Error::Other("boom".to_string()).to_string(), "boom");
52 }
53
54 #[test]
55 fn display_for_db_variant_includes_the_underlying_error() {
56 let e = Error::Db(rusqlite::Error::QueryReturnedNoRows);
57 assert!(e.to_string().starts_with("database error: "));
58 assert!(e.to_string().contains("Query returned no rows"));
59 }
60
61 #[test]
62 fn from_rusqlite_error_wraps_as_db_variant() {
63 let e: Error = rusqlite::Error::QueryReturnedNoRows.into();
64 assert!(matches!(e, Error::Db(_)));
65 }
66
67 #[test]
68 fn from_anyhow_error_wraps_message_as_other_variant() {
69 let e: Error = anyhow::anyhow!("something broke").into();
70 match e {
71 Error::Other(msg) => assert_eq!(msg, "something broke"),
72 other => panic!("expected Error::Other, got {other:?}"),
73 }
74 }
75}