From 68a7928df11136fc9cdeb51ca1a29dcb566ce1a8 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Sun, 2 Feb 2025 20:11:32 +0000 Subject: [PATCH 1/2] tidy error handling --- Cargo.lock | 1 + graphql_client_cli/src/error.rs | 27 ++++++------------- graphql_client_codegen/Cargo.toml | 1 + .../src/generated_module.rs | 14 ++-------- graphql_client_codegen/src/lib.rs | 17 +++--------- 5 files changed, 16 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 422b21cd..5e66e4bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -474,6 +474,7 @@ dependencies = [ "serde", "serde_json", "syn 1.0.109", + "thiserror 2.0.11", ] [[package]] diff --git a/graphql_client_cli/src/error.rs b/graphql_client_cli/src/error.rs index feb682c2..3c597d3a 100644 --- a/graphql_client_cli/src/error.rs +++ b/graphql_client_cli/src/error.rs @@ -1,5 +1,3 @@ -use std::fmt::{Debug, Display}; - pub struct Error { source: Option>, message: Option, @@ -28,25 +26,16 @@ impl Error { } // This is the impl that shows up when the error bubbles up to `main()`. -impl Debug for Error { +impl std::fmt::Debug for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(msg) = &self.message { - f.write_str(msg)?; - f.write_str("\n")?; - } - - if self.source.is_some() && self.message.is_some() { - f.write_str("Cause: ")?; + match (&self.message, &self.source) { + (Some(msg), Some(source)) => { + write!(f, "{msg}\nCause: {source}\nLocation: {}", self.location) + } + (Some(msg), None) => write!(f, "{msg}\nLocation: {}", self.location), + (None, Some(source)) => write!(f, "{source}\nLocation: {}", self.location), + (None, None) => write!(f, "\nLocation: {}", self.location), } - - if let Some(source) = self.source.as_ref() { - Display::fmt(source, f)?; - } - - f.write_str("\nLocation: ")?; - Display::fmt(self.location, f)?; - - Ok(()) } } diff --git a/graphql_client_codegen/Cargo.toml b/graphql_client_codegen/Cargo.toml index 5a20e1f7..9c1392a4 100644 --- a/graphql_client_codegen/Cargo.toml +++ b/graphql_client_codegen/Cargo.toml @@ -17,3 +17,4 @@ quote = "^1.0" serde_json = "1.0" serde = { version = "^1.0", features = ["derive"] } syn = "^1.0" +thiserror = "2.0.11" diff --git a/graphql_client_codegen/src/generated_module.rs b/graphql_client_codegen/src/generated_module.rs index b225d001..0913d520 100644 --- a/graphql_client_codegen/src/generated_module.rs +++ b/graphql_client_codegen/src/generated_module.rs @@ -6,23 +6,13 @@ use crate::{ use heck::*; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; -use std::{error::Error, fmt::Display}; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("Could not find an operation named {operation_name} in the query document.")] struct OperationNotFound { operation_name: String, } -impl Display for OperationNotFound { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str("Could not find an operation named ")?; - f.write_str(&self.operation_name)?; - f.write_str(" in the query document.") - } -} - -impl Error for OperationNotFound {} - /// This struct contains the parameters necessary to generate code for a given operation. pub(crate) struct GeneratedModule<'a> { pub operation: &'a str, diff --git a/graphql_client_codegen/src/lib.rs b/graphql_client_codegen/src/lib.rs index 8d087057..28b595ed 100644 --- a/graphql_client_codegen/src/lib.rs +++ b/graphql_client_codegen/src/lib.rs @@ -30,17 +30,10 @@ pub use crate::codegen_options::{CodegenMode, GraphQLClientCodegenOptions}; use std::{collections::BTreeMap, fmt::Display, io}; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("{0}")] struct GeneralError(String); -impl Display for GeneralError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.0) - } -} - -impl std::error::Error for GeneralError {} - type BoxError = Box; type CacheMap = std::sync::Mutex>; type QueryDocument = graphql_parser::query::Document<'static, String>; @@ -179,12 +172,10 @@ impl Display for ReadFileError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { ReadFileError::FileNotFound { path, .. } => { - write!(f, "Could not find file with path: {}\n - Hint: file paths in the GraphQLQuery attribute are relative to the project root (location of the Cargo.toml). Example: query_path = \"src/my_query.graphql\".", path) + write!(f, "Could not find file with path: {path}\nHint: file paths in the GraphQLQuery attribute are relative to the project root (location of the Cargo.toml). Example: query_path = \"src/my_query.graphql\".") } ReadFileError::ReadError { path, .. } => { - f.write_str("Error reading file at: ")?; - f.write_str(path) + write!(f, "Error reading file at: {}", path) } } } From f0990a83142778ec703d9df9dd9d82494969f969 Mon Sep 17 00:00:00 2001 From: Daniel Eades Date: Sun, 2 Feb 2025 20:16:50 +0000 Subject: [PATCH 2/2] tidy error handling --- graphql_client_codegen/src/lib.rs | 40 ++++++++++------------------- graphql_client_codegen/src/query.rs | 16 +++--------- 2 files changed, 17 insertions(+), 39 deletions(-) diff --git a/graphql_client_codegen/src/lib.rs b/graphql_client_codegen/src/lib.rs index 28b595ed..bfee221f 100644 --- a/graphql_client_codegen/src/lib.rs +++ b/graphql_client_codegen/src/lib.rs @@ -28,7 +28,7 @@ mod tests; pub use crate::codegen_options::{CodegenMode, GraphQLClientCodegenOptions}; -use std::{collections::BTreeMap, fmt::Display, io}; +use std::{collections::BTreeMap, io}; #[derive(Debug, thiserror::Error)] #[error("{0}")] @@ -162,32 +162,20 @@ fn generate_module_token_stream_inner( Ok(modules) } -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] enum ReadFileError { - FileNotFound { path: String, io_error: io::Error }, - ReadError { path: String, io_error: io::Error }, -} - -impl Display for ReadFileError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - ReadFileError::FileNotFound { path, .. } => { - write!(f, "Could not find file with path: {path}\nHint: file paths in the GraphQLQuery attribute are relative to the project root (location of the Cargo.toml). Example: query_path = \"src/my_query.graphql\".") - } - ReadFileError::ReadError { path, .. } => { - write!(f, "Error reading file at: {}", path) - } - } - } -} - -impl std::error::Error for ReadFileError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - match self { - ReadFileError::FileNotFound { io_error, .. } - | ReadFileError::ReadError { io_error, .. } => Some(io_error), - } - } + #[error("Could not find file with path: {path}\nHint: file paths in the GraphQLQuery attribute are relative to the project root (location of the Cargo.toml). Example: query_path = \"src/my_query.graphql\".")] + FileNotFound { + path: String, + #[source] + io_error: io::Error, + }, + #[error("Error reading file at: {path}")] + ReadError { + path: String, + #[source] + io_error: io::Error, + }, } fn read_file(path: &std::path::Path) -> Result { diff --git a/graphql_client_codegen/src/query.rs b/graphql_client_codegen/src/query.rs index bb2b6318..1593a64c 100644 --- a/graphql_client_codegen/src/query.rs +++ b/graphql_client_codegen/src/query.rs @@ -18,24 +18,14 @@ use crate::{ StoredInputType, StoredScalar, TypeId, UnionId, }, }; -use std::{ - collections::{BTreeMap, BTreeSet}, - fmt::Display, -}; +use std::collections::{BTreeMap, BTreeSet}; -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] +#[error("{message}")] pub(crate) struct QueryValidationError { message: String, } -impl Display for QueryValidationError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.message) - } -} - -impl std::error::Error for QueryValidationError {} - impl QueryValidationError { pub(crate) fn new(message: String) -> Self { QueryValidationError { message }