rusty_gql/
error.rs

1use std::{
2    collections::BTreeMap,
3    fmt::{self, Debug, Display, Formatter},
4};
5
6use graphql_parser::Pos;
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Deserialize, Serialize)]
10pub struct Location {
11    pub line: usize,
12    pub column: usize,
13}
14
15#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
16pub enum GqlErrorType {
17    BadRequest,
18    FailedPreCondition,
19    Internal,
20    NotFound,
21    PermissionDenied,
22    Unauthenticated,
23    Unavailable,
24    Unknown,
25}
26
27#[derive(Debug, Clone, Deserialize, Serialize, PartialEq)]
28#[serde(rename_all = "camelCase")]
29pub struct GqlTypedError {
30    pub error_type: GqlErrorType,
31    pub error_detail: Option<String>,
32    pub origin: Option<String>,
33    pub debug_info: Option<BTreeMap<String, String>>,
34    pub debug_uri: Option<String>,
35}
36
37#[derive(Debug, Clone, Deserialize, Serialize)]
38pub struct GqlError {
39    pub message: String,
40    pub locations: Vec<Location>,
41    pub path: Vec<String>,
42    pub extensions: Option<GqlTypedError>,
43}
44
45impl GqlError {
46    pub fn new(message: impl Into<String>, pos: Option<Pos>) -> Self {
47        GqlError {
48            message: message.into(),
49            locations: pos
50                .map(|pos| {
51                    vec![Location {
52                        line: pos.line,
53                        column: pos.column,
54                    }]
55                })
56                .unwrap_or_default(),
57            path: Vec::new(),
58            extensions: None,
59        }
60    }
61
62    pub fn set_path(&mut self, path: &str) -> Self {
63        self.path.push(path.to_string());
64        self.clone()
65    }
66
67    pub fn set_extentions(&mut self, typed_error: GqlTypedError) -> Self {
68        self.extensions = Some(typed_error);
69        self.clone()
70    }
71}
72
73impl Display for GqlError {
74    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
75        f.debug_struct("GqlError")
76            .field("message", &self.message)
77            .field("locations", &self.locations)
78            .field("path", &self.path)
79            .field("extensions", &self.extensions)
80            .finish()
81    }
82}
83
84pub struct Error {
85    pub message: String,
86    pub extensions: Option<GqlTypedError>,
87}
88
89impl Error {
90    pub fn new(message: impl Into<String>) -> Self {
91        Self {
92            message: message.into(),
93            extensions: None,
94        }
95    }
96    pub fn into_gql_error(self, pos: Pos) -> GqlError {
97        GqlError {
98            message: self.message,
99            locations: vec![Location {
100                line: pos.line,
101                column: pos.column,
102            }],
103            path: Vec::new(),
104            extensions: self.extensions,
105        }
106    }
107}
108
109impl<T: Display + Send + Sync + 'static> From<T> for Error {
110    fn from(err: T) -> Self {
111        Self {
112            message: err.to_string(),
113            extensions: None,
114        }
115    }
116}
117
118impl Debug for Error {
119    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
120        f.debug_struct("Error")
121            .field("message", &self.message)
122            .finish()
123    }
124}
125
126impl PartialEq for Error {
127    fn eq(&self, other: &Self) -> bool {
128        self.message.eq(&other.message) && self.extensions.eq(&other.extensions)
129    }
130}