1use thiserror::Error;
4
5pub type Result<T> = std::result::Result<T, Error>;
7
8#[derive(Error, Debug)]
10pub enum Error {
11 #[error("HTTP request failed: {0}")]
13 Http(#[from] reqwest::Error),
14
15 #[error("JSON error: {0}")]
17 Json(#[from] serde_json::Error),
18
19 #[error("URL parse error: {0}")]
21 UrlParse(#[from] url::ParseError),
22
23 #[cfg(feature = "auth")]
25 #[error("JWT error: {0}")]
26 Jwt(#[from] jsonwebtoken::errors::Error),
27
28 #[error("Authentication error: {message}")]
30 Auth { message: String },
31
32 #[error("Database error: {message}")]
34 Database { message: String },
35
36 #[error("Storage error: {message}")]
38 Storage { message: String },
39
40 #[error("Realtime error: {message}")]
42 Realtime { message: String },
43
44 #[error("Configuration error: {message}")]
46 Config { message: String },
47
48 #[error("Invalid input: {message}")]
50 InvalidInput { message: String },
51
52 #[error("Network error: {message}")]
54 Network { message: String },
55
56 #[error("Rate limit exceeded: {message}")]
58 RateLimit { message: String },
59
60 #[error("Permission denied: {message}")]
62 PermissionDenied { message: String },
63
64 #[error("Not found: {message}")]
66 NotFound { message: String },
67
68 #[error("{message}")]
70 Generic { message: String },
71
72 #[error("Functions error: {message}")]
74 Functions { message: String },
75}
76
77impl Error {
78 pub fn auth<S: Into<String>>(message: S) -> Self {
80 Self::Auth {
81 message: message.into(),
82 }
83 }
84
85 pub fn database<S: Into<String>>(message: S) -> Self {
87 Self::Database {
88 message: message.into(),
89 }
90 }
91
92 pub fn storage<S: Into<String>>(message: S) -> Self {
94 Self::Storage {
95 message: message.into(),
96 }
97 }
98
99 pub fn realtime<S: Into<String>>(message: S) -> Self {
101 Self::Realtime {
102 message: message.into(),
103 }
104 }
105
106 pub fn config<S: Into<String>>(message: S) -> Self {
108 Self::Config {
109 message: message.into(),
110 }
111 }
112
113 pub fn invalid_input<S: Into<String>>(message: S) -> Self {
115 Self::InvalidInput {
116 message: message.into(),
117 }
118 }
119
120 pub fn network<S: Into<String>>(message: S) -> Self {
122 Self::Network {
123 message: message.into(),
124 }
125 }
126
127 pub fn rate_limit<S: Into<String>>(message: S) -> Self {
129 Self::RateLimit {
130 message: message.into(),
131 }
132 }
133
134 pub fn permission_denied<S: Into<String>>(message: S) -> Self {
136 Self::PermissionDenied {
137 message: message.into(),
138 }
139 }
140
141 pub fn not_found<S: Into<String>>(message: S) -> Self {
143 Self::NotFound {
144 message: message.into(),
145 }
146 }
147
148 pub fn generic<S: Into<String>>(message: S) -> Self {
150 Self::Generic {
151 message: message.into(),
152 }
153 }
154
155 pub fn functions<T: Into<String>>(message: T) -> Self {
157 Self::Functions {
158 message: message.into(),
159 }
160 }
161}
162
163impl From<reqwest::StatusCode> for Error {
165 fn from(status: reqwest::StatusCode) -> Self {
166 match status {
167 reqwest::StatusCode::UNAUTHORIZED => Self::auth("Unauthorized"),
168 reqwest::StatusCode::FORBIDDEN => Self::permission_denied("Forbidden"),
169 reqwest::StatusCode::NOT_FOUND => Self::not_found("Resource not found"),
170 reqwest::StatusCode::TOO_MANY_REQUESTS => Self::rate_limit("Too many requests"),
171 reqwest::StatusCode::INTERNAL_SERVER_ERROR => Self::network("Internal server error"),
172 reqwest::StatusCode::BAD_GATEWAY => Self::network("Bad gateway"),
173 reqwest::StatusCode::SERVICE_UNAVAILABLE => Self::network("Service unavailable"),
174 reqwest::StatusCode::GATEWAY_TIMEOUT => Self::network("Gateway timeout"),
175 _ => Self::network(format!("HTTP error: {}", status)),
176 }
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 #[test]
185 fn test_error_creation() {
186 let error = Error::auth("test message");
187 assert_eq!(error.to_string(), "Authentication error: test message");
188 }
189
190 #[test]
191 fn test_database_error() {
192 let error = Error::database("query failed");
193 assert_eq!(error.to_string(), "Database error: query failed");
194 }
195
196 #[test]
197 fn test_from_status_code() {
198 let error = Error::from(reqwest::StatusCode::NOT_FOUND);
199 assert_eq!(error.to_string(), "Not found: Resource not found");
200 }
201}