1use error_support::{ErrorHandling, GetErrorHandling};
7use remote_settings::RemoteSettingsError;
8
9#[derive(Debug, thiserror::Error)]
13pub enum Error {
14 #[error("Error opening database: {0}")]
15 OpenDatabase(#[from] sql_support::open_database::Error),
16
17 #[error("Error executing SQL: {inner} (context: {context})")]
18 Sql {
19 inner: rusqlite::Error,
20 context: String,
21 },
22
23 #[error("Serialization error: {0}")]
24 Serialization(String),
25
26 #[error("Error from Remote Settings: {0}")]
27 RemoteSettings(#[from] RemoteSettingsError),
28
29 #[error("Remote settings record is missing an attachment (id: u64)")]
30 MissingAttachment(String),
31
32 #[error("Operation interrupted")]
33 Interrupted(#[from] interrupt_support::Interrupted),
34
35 #[error("SuggestStoreBuilder {0}")]
36 SuggestStoreBuilder(String),
37}
38
39impl Error {
40 fn sql(e: rusqlite::Error, context: impl Into<String>) -> Self {
41 Self::Sql {
42 inner: e,
43 context: context.into(),
44 }
45 }
46}
47
48impl From<rusqlite::Error> for Error {
49 fn from(e: rusqlite::Error) -> Self {
50 Self::sql(e, "<none>")
51 }
52}
53
54impl From<serde_json::Error> for Error {
55 fn from(e: serde_json::Error) -> Self {
56 Self::Serialization(e.to_string())
57 }
58}
59
60impl From<rmp_serde::decode::Error> for Error {
61 fn from(e: rmp_serde::decode::Error) -> Self {
62 Self::Serialization(e.to_string())
63 }
64}
65
66impl From<rmp_serde::encode::Error> for Error {
67 fn from(e: rmp_serde::encode::Error) -> Self {
68 Self::Serialization(e.to_string())
69 }
70}
71
72#[extend::ext(name=RusqliteResultExt)]
73pub impl<T> Result<T, rusqlite::Error> {
74 fn with_context(self, context: &str) -> Result<T, Error> {
76 self.map_err(|e| Error::sql(e, context))
77 }
78}
79
80#[derive(Debug, thiserror::Error, uniffi::Error)]
83#[non_exhaustive]
84pub enum SuggestApiError {
85 #[error("Network error: {reason}")]
86 Network { reason: String },
87 #[error("Backoff")]
89 Backoff { seconds: u64 },
90 #[error("Interrupted")]
92 Interrupted,
93 #[error("Other error: {reason}")]
94 Other { reason: String },
95}
96
97impl GetErrorHandling for Error {
100 type ExternalError = SuggestApiError;
101
102 fn get_error_handling(&self) -> ErrorHandling<Self::ExternalError> {
103 match self {
104 Self::Interrupted(_) => ErrorHandling::convert(SuggestApiError::Interrupted),
106 Self::RemoteSettings(RemoteSettingsError::Network { reason }) => {
108 ErrorHandling::convert(SuggestApiError::Network {
109 reason: reason.clone(),
110 })
111 .log_warning()
112 }
113 Self::RemoteSettings(RemoteSettingsError::Backoff { seconds }) => {
117 ErrorHandling::convert(SuggestApiError::Backoff { seconds: *seconds })
118 .report_error("suggest-backoff")
119 }
120 _ => ErrorHandling::convert(SuggestApiError::Other {
121 reason: self.to_string(),
122 })
123 .report_error("suggest-unexpected"),
124 }
125 }
126}