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}