1use serde::{Deserialize, Serialize};
2use std::fmt;
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct GraphQLError {
7 pub message: String,
8 #[serde(default)]
9 pub extensions: Option<serde_json::Value>,
10}
11
12#[derive(Debug)]
14pub enum LinearError {
15 Authentication(String),
17 RateLimited {
19 retry_after: Option<f64>,
20 message: String,
21 },
22 InvalidInput(String),
24 Forbidden(String),
26 Network(reqwest::Error),
28 GraphQL(Vec<GraphQLError>),
30 MissingData(String),
32 AuthConfig(String),
34}
35
36impl fmt::Display for LinearError {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 match self {
39 Self::Authentication(msg) => write!(f, "Authentication error: {}", msg),
40 Self::RateLimited { message, .. } => write!(f, "Rate limited: {}", message),
41 Self::InvalidInput(msg) => write!(f, "Invalid input: {}", msg),
42 Self::Forbidden(msg) => write!(f, "Forbidden: {}", msg),
43 Self::Network(e) => write!(f, "Network error: {}", e),
44 Self::GraphQL(errors) => {
45 let msgs: Vec<String> = errors
46 .iter()
47 .map(|e| {
48 if let Some(ext) = &e.extensions {
49 format!("{} ({})", e.message, ext)
50 } else {
51 e.message.clone()
52 }
53 })
54 .collect();
55 write!(f, "GraphQL errors: {}", msgs.join("; "))
56 }
57 Self::MissingData(path) => write!(f, "Missing data at path: {}", path),
58 Self::AuthConfig(msg) => write!(f, "Auth configuration error: {}", msg),
59 }
60 }
61}
62
63impl std::error::Error for LinearError {
64 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
65 match self {
66 Self::Network(e) => Some(e),
67 _ => None,
68 }
69 }
70}
71
72impl From<reqwest::Error> for LinearError {
73 fn from(e: reqwest::Error) -> Self {
74 Self::Network(e)
75 }
76}