Skip to content

Commit f012cdb

Browse files
authored
Merge pull request #131 from mathstuf/better-diagnostic-impls
Better diagnostic impls
2 parents 42c185e + 9166ff8 commit f012cdb

File tree

2 files changed

+36
-3
lines changed

2 files changed

+36
-3
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ categories = ["network-programming", "web-programming", "wasm"]
1111
[dependencies]
1212
failure = "0.1"
1313
graphql_query_derive = {path = "./graphql_query_derive", version = "0.4.0"}
14+
itertools = "0.7"
1415
serde = "1.0"
1516
serde_derive = "1.0"
1617
serde_json = "1.0"

src/lib.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![deny(warnings)]
66
#![deny(missing_docs)]
77

8+
extern crate itertools;
89
extern crate serde;
910
#[macro_use]
1011
extern crate serde_derive;
@@ -17,6 +18,9 @@ extern crate serde_json;
1718
pub use graphql_query_derive::*;
1819

1920
use std::collections::HashMap;
21+
use std::fmt::{self, Display};
22+
23+
use itertools::Itertools;
2024

2125
/// A convenience trait that can be used to build a GraphQL request body.
2226
///
@@ -91,7 +95,7 @@ where
9195
}
9296

9397
/// Represents a location inside a query string. Used in errors. See [`Error`].
94-
#[derive(Debug, Serialize, Deserialize, PartialEq)]
98+
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize, PartialEq)]
9599
pub struct Location {
96100
/// The line number in the query string where the error originated (starting from 1).
97101
pub line: i32,
@@ -100,7 +104,7 @@ pub struct Location {
100104
}
101105

102106
/// Part of a path in a query. It can be an object key or an array index. See [`Error`].
103-
#[derive(Debug, Serialize, Deserialize, PartialEq)]
107+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
104108
#[serde(untagged)]
105109
pub enum PathFragment {
106110
/// A key inside an object
@@ -109,6 +113,15 @@ pub enum PathFragment {
109113
Index(i32),
110114
}
111115

116+
impl Display for PathFragment {
117+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
118+
match *self {
119+
PathFragment::Key(ref key) => write!(f, "{}", key),
120+
PathFragment::Index(ref idx) => write!(f, "{}", idx),
121+
}
122+
}
123+
}
124+
112125
/// An element in the top-level `errors` array of a response body.
113126
///
114127
/// This tries to be as close to the spec as possible.
@@ -177,7 +190,7 @@ pub enum PathFragment {
177190
/// # Ok(())
178191
/// # }
179192
/// ```
180-
#[derive(Debug, Serialize, Deserialize, PartialEq)]
193+
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
181194
pub struct Error {
182195
/// The human-readable error message. This is the only required field.
183196
pub message: String,
@@ -189,6 +202,25 @@ pub struct Error {
189202
pub extensions: Option<HashMap<String, serde_json::Value>>,
190203
}
191204

205+
impl Display for Error {
206+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
207+
// Use `/` as a separator like JSON Pointer.
208+
let path = self.path
209+
.as_ref()
210+
.map(|fragments| format!("{}", fragments.iter().format("/")))
211+
.unwrap_or_else(|| "<query>".to_string());
212+
213+
// Get the location of the error. We'll use just the first location for this.
214+
let loc = self.locations
215+
.as_ref()
216+
.and_then(|locations| locations.iter().next())
217+
.cloned()
218+
.unwrap_or_else(Location::default);
219+
220+
write!(f, "{}:{}:{}: {}", path, loc.line, loc.column, self.message)
221+
}
222+
}
223+
192224
/// The generic shape taken by the responses of GraphQL APIs.
193225
///
194226
/// This will generally be used with the `ResponseData` struct from a derived module.

0 commit comments

Comments
 (0)