Skip to content

Commit df091a7

Browse files
committed
Provide helpful feedback when a struct name does not match any operation
1 parent 7991ca6 commit df091a7

File tree

7 files changed

+65
-16
lines changed

7 files changed

+65
-16
lines changed

graphql_client/tests/interfaces/interface_not_on_everything_query.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.

graphql_client/tests/unions/union_query.rs

Lines changed: 0 additions & 1 deletion
This file was deleted.

graphql_client_cli/src/generate.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use failure;
2-
use graphql_client_codegen::{generate_module_token_stream, GraphQLClientCodegenOptions};
2+
use graphql_client_codegen::{
3+
generate_module_token_stream, CodegenMode, GraphQLClientCodegenOptions,
4+
};
35
use std::fs::File;
46
use std::io::Write as _;
57
use std::path::PathBuf;
@@ -21,7 +23,7 @@ pub(crate) fn generate_code(params: CliCodegenParams) -> Result<(), failure::Err
2123
.as_ref()
2224
.and_then(|s| s.parse().ok());
2325

24-
let mut options = GraphQLClientCodegenOptions::new_default();
26+
let mut options = GraphQLClientCodegenOptions::new(CodegenMode::Cli);
2527

2628
options.set_module_visibility(
2729
syn::VisPublic {

graphql_client_codegen/src/codegen.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use query::QueryContext;
77
use schema;
88
use selection::Selection;
99

10-
/// Selects the first operation matching `struct_name` or the first one. Returns `None` when the query document defines no operation.
10+
/// Selects the first operation matching `struct_name`. Returns `None` when the query document defines no operation, or when the selected operation does not match any defined operation.
1111
pub(crate) fn select_operation<'query>(
1212
query: &'query query::Document,
1313
struct_name: &str,
@@ -18,7 +18,6 @@ pub(crate) fn select_operation<'query>(
1818
.iter()
1919
.find(|op| op.name == struct_name)
2020
.map(|i| i.to_owned())
21-
.or_else(|| operations.iter().next().map(|i| i.to_owned()))
2221
}
2322

2423
pub(crate) fn all_operations(query: &query::Document) -> Vec<Operation> {

graphql_client_codegen/src/codegen_options.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,20 @@ use proc_macro2::Ident;
33
use std::path::{Path, PathBuf};
44
use syn::Visibility;
55

6+
/// Which context is this code generation effort taking place.
7+
#[derive(Debug)]
8+
pub enum CodegenMode {
9+
/// The graphql-client CLI.
10+
Cli,
11+
/// The derive macro defined in graphql_query_derive.
12+
Derive,
13+
}
14+
615
/// Used to configure code generation.
7-
#[derive(Debug, Default)]
16+
#[derive(Debug)]
817
pub struct GraphQLClientCodegenOptions {
18+
/// Which context is this code generation effort taking place.
19+
pub mode: CodegenMode,
920
/// Name of the operation we want to generate code for. If it does not match, we use all queries.
1021
pub operation_name: Option<String>,
1122
/// The name of implemention target struct.
@@ -28,8 +39,20 @@ pub struct GraphQLClientCodegenOptions {
2839

2940
impl GraphQLClientCodegenOptions {
3041
/// Creates an empty options object with default params. It probably wants to be configured.
31-
pub fn new_default() -> GraphQLClientCodegenOptions {
32-
std::default::Default::default()
42+
pub fn new(mode: CodegenMode) -> GraphQLClientCodegenOptions {
43+
use std::default::Default;
44+
45+
GraphQLClientCodegenOptions {
46+
mode,
47+
additional_derives: Default::default(),
48+
deprecation_strategy: Default::default(),
49+
module_visibility: Default::default(),
50+
operation_name: Default::default(),
51+
struct_ident: Default::default(),
52+
struct_name: Default::default(),
53+
query_file: Default::default(),
54+
schema_file: Default::default(),
55+
}
3356
}
3457

3558
/// The visibility (public/private) to apply to the target module.

graphql_client_codegen/src/lib.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ mod variables;
5151
#[cfg(test)]
5252
mod tests;
5353

54-
pub use codegen_options::GraphQLClientCodegenOptions;
54+
pub use codegen_options::{CodegenMode, GraphQLClientCodegenOptions};
5555

5656
use std::collections::HashMap;
5757

@@ -88,8 +88,21 @@ pub fn generate_module_token_stream(
8888
.operation_name
8989
.as_ref()
9090
.and_then(|operation_name| codegen::select_operation(&query, &operation_name))
91-
.map(|op| vec![op])
92-
.unwrap_or_else(|| codegen::all_operations(&query));
91+
.map(|op| vec![op]);
92+
93+
let operations = match (operations, &options.mode) {
94+
(Some(ops), _) => ops,
95+
(None, &CodegenMode::Cli) => codegen::all_operations(&query),
96+
(None, &CodegenMode::Derive) => {
97+
return Err(
98+
format_err!("The struct name does not match any defined operation in the query file.\nStruct name: {}\nDefined operations: {}", options.struct_ident().map(|i| i.to_string()).as_ref().map(String::as_str).unwrap_or(""), query.definitions.iter().filter_map(|definition| match definition { graphql_parser::query::Definition::Operation(op) => match op { graphql_parser::query::OperationDefinition::Mutation(m) => Some(m.name.as_ref().unwrap()),
99+
graphql_parser::query::OperationDefinition::Query(m) => Some(m.name.as_ref().unwrap()),
100+
graphql_parser::query::OperationDefinition::Subscription(m) => Some(m.name.as_ref().unwrap()),
101+
graphql_parser::query::OperationDefinition::SelectionSet(_) => panic!("Bare selection sets are not supported"),
102+
}, _ => None }).fold(String::new(), |mut acc, item| { acc.push_str(&item); acc.push_str(", "); acc }).trim_end_matches(", ")),
103+
)
104+
}
105+
};
93106

94107
let schema_extension = schema_path
95108
.extension()

graphql_query_derive/src/lib.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ extern crate syn;
99
mod attributes;
1010

1111
use failure::ResultExt;
12-
use graphql_client_codegen::{generate_module_token_stream, GraphQLClientCodegenOptions};
12+
use graphql_client_codegen::{
13+
generate_module_token_stream, CodegenMode, GraphQLClientCodegenOptions,
14+
};
1315
use std::path::{Path, PathBuf};
1416

1517
use proc_macro2::TokenStream;
@@ -18,7 +20,15 @@ use proc_macro2::TokenStream;
1820
pub fn graphql_query_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
1921
match graphql_query_derive_inner(input) {
2022
Ok(ts) => ts,
21-
Err(err) => panic!("{:?}", err),
23+
Err(err) => panic!(
24+
"{}",
25+
err.iter_chain()
26+
.fold(String::new(), |mut acc, item| {
27+
acc.push_str(&format!("{}\n", item));
28+
acc
29+
})
30+
.trim_end_matches("\n")
31+
),
2232
}
2333
}
2434

@@ -29,7 +39,11 @@ fn graphql_query_derive_inner(
2939
let ast = syn::parse2(input).context("Derive input parsing.")?;
3040
let (query_path, schema_path) = build_query_and_schema_path(&ast)?;
3141
let options = build_graphql_client_derive_options(&ast, query_path.to_path_buf())?;
32-
generate_module_token_stream(query_path, &schema_path, options).map(|module| module.into())
42+
Ok(
43+
generate_module_token_stream(query_path, &schema_path, options)
44+
.map(|module| module.into())
45+
.context("Code generation failed.")?,
46+
)
3347
}
3448

3549
fn build_query_and_schema_path(
@@ -54,7 +68,7 @@ fn build_graphql_client_derive_options(
5468
) -> Result<GraphQLClientCodegenOptions, failure::Error> {
5569
let response_derives = attributes::extract_attr(input, "response_derives").ok();
5670

57-
let mut options = GraphQLClientCodegenOptions::new_default();
71+
let mut options = GraphQLClientCodegenOptions::new(CodegenMode::Derive);
5872
options.set_query_file(query_path);
5973

6074
if let Some(response_derives) = response_derives {

0 commit comments

Comments
 (0)