@@ -64,9 +64,14 @@ lazy_static! {
6464}
6565
6666/// Used to configure code generation.
67+ #[ derive( Clone ) ]
6768pub struct GraphQLClientDeriveOptions {
68- /// Name of the operation we want to generate code for. If it does not match, we default to the first one.
69- pub struct_name : String ,
69+ /// Name of the operation we want to generate code for. If it does not match, we use all queries.
70+ pub operation_name : Option < String > ,
71+ /// The name of implemention target struct.
72+ pub struct_name : Option < String > ,
73+ /// The module that contains queries.
74+ pub module_name : Option < String > ,
7075 /// Comma-separated list of additional traits we want to derive.
7176 pub additional_derives : Option < String > ,
7277 /// The deprecation strategy to adopt.
@@ -81,10 +86,10 @@ pub fn generate_module_token_stream(
8186) -> Result < TokenStream , failure:: Error > {
8287 let options = options. unwrap ( ) ;
8388
84- let response_derives = options. additional_derives ;
89+ let response_derives = options. additional_derives . clone ( ) ;
8590
8691 // The user can determine what to do about deprecations.
87- let deprecation_strategy = options. deprecation_strategy . unwrap_or_default ( ) ;
92+ let deprecation_strategy = options. deprecation_strategy . clone ( ) . unwrap_or_default ( ) ;
8893
8994 // We need to qualify the query with the path to the crate it is part of
9095 let ( query_string, query) = {
@@ -100,15 +105,17 @@ pub fn generate_module_token_stream(
100105 } ;
101106
102107 // Determine which operation we are generating code for. This will be used in operationName.
103-
104- let operation = if let Some ( op) = codegen:: select_operation ( & query, & options. struct_name ) {
105- op
108+ let operations = if options. operation_name . is_some ( ) {
109+ let op = codegen:: select_operation ( & query, & ( options. operation_name . clone ( ) . unwrap ( ) ) ) ;
110+ if op. is_some ( ) {
111+ vec ! [ op. unwrap( ) ]
112+ } else {
113+ codegen:: all_operations ( & query)
114+ }
106115 } else {
107- panic ! ( "Query document defines no operation." )
116+ codegen :: all_operations ( & query )
108117 } ;
109118
110- let operation_name_literal = & operation. name ;
111-
112119 // Check the schema cache.
113120 let schema = {
114121 let mut lock = SCHEMA_CACHE . lock ( ) . expect ( "schema cache is poisoned" ) ;
@@ -141,20 +148,91 @@ pub fn generate_module_token_stream(
141148 }
142149 } ;
143150
151+ let struct_name = if options. struct_name . is_some ( ) {
152+ Some ( Ident :: new (
153+ options. struct_name . clone ( ) . unwrap ( ) . as_str ( ) ,
154+ Span :: call_site ( ) ,
155+ ) )
156+ } else {
157+ None
158+ } ;
159+
144160 let module_name = Ident :: new (
145- options. struct_name . to_snake_case ( ) . as_str ( ) ,
161+ options
162+ . module_name
163+ . clone ( )
164+ . unwrap_or_else ( || options. operation_name . clone ( ) . unwrap ( ) )
165+ . to_snake_case ( )
166+ . as_str ( ) ,
146167 Span :: call_site ( ) ,
147168 ) ;
148- let struct_name = Ident :: new ( options. struct_name . as_str ( ) , Span :: call_site ( ) ) ;
149- let schema_output = codegen:: response_for_query (
150- schema,
151- query,
152- & operation,
153- response_derives,
154- deprecation_strategy,
155- ) ?;
156-
157- let result = quote ! (
169+
170+ let operation_count = operations. len ( ) ;
171+
172+ let mulutiple_operation = operation_count > 1 ;
173+
174+ let mut schema_and_operations = Vec :: with_capacity ( operation_count) ;
175+
176+ for operation in & operations {
177+ let schema_output = codegen:: response_for_query (
178+ schema. clone ( ) ,
179+ query. clone ( ) ,
180+ & operation,
181+ response_derives. clone ( ) ,
182+ deprecation_strategy. clone ( ) ,
183+ mulutiple_operation,
184+ ) ?;
185+ let operation_name = Ident :: new ( operation. name . as_str ( ) , Span :: call_site ( ) ) ;
186+ schema_and_operations. push ( ( schema_output, operation_name, operation. name . as_str ( ) ) ) ;
187+ }
188+
189+ let result = build_module_token_stream (
190+ & module_name,
191+ & struct_name,
192+ & query_string,
193+ schema_and_operations,
194+ ) ;
195+
196+ Ok ( result)
197+ }
198+
199+ fn build_module_token_stream (
200+ module_name : & Ident ,
201+ struct_name : & Option < Ident > ,
202+ query_string : & str ,
203+ schema_and_operations : Vec < ( TokenStream , Ident , & str ) > ,
204+ ) -> TokenStream {
205+ let mut schema_token_streams = vec ! [ ] ;
206+ let mut trait_token_streams = vec ! [ ] ;
207+ let mulutiple_operation = schema_and_operations. len ( ) > 1 ;
208+ for ( schema_output, operation_name, operation_name_literal) in schema_and_operations {
209+ let ( schema_token_stream, trait_token_stream) = build_query_struct_token_stream (
210+ & module_name,
211+ struct_name. clone ( ) ,
212+ & schema_output,
213+ & operation_name,
214+ operation_name_literal,
215+ mulutiple_operation,
216+ ) ;
217+ schema_token_streams. push ( schema_token_stream) ;
218+ trait_token_streams. push ( trait_token_stream) ;
219+ }
220+
221+ merge_with_common_token_stream (
222+ & module_name,
223+ query_string,
224+ schema_token_streams,
225+ trait_token_streams,
226+ )
227+ }
228+
229+ fn merge_with_common_token_stream (
230+ module_name : & Ident ,
231+ query_string : & str ,
232+ schema_token_streams : Vec < TokenStream > ,
233+ trait_token_streams : Vec < TokenStream > ,
234+ ) -> TokenStream {
235+ quote ! (
158236 pub mod #module_name {
159237 #![ allow( non_camel_case_types) ]
160238 #![ allow( non_snake_case) ]
@@ -163,14 +241,52 @@ pub fn generate_module_token_stream(
163241 use serde;
164242
165243 pub const QUERY : & ' static str = #query_string;
166- pub const OPERATION_NAME : & ' static str = #operation_name_literal;
167-
168- #schema_output
244+ #( #schema_token_streams) *
169245 }
246+ #( #trait_token_streams) *
247+ )
248+ }
170249
250+ fn build_query_struct_token_stream (
251+ module_name : & Ident ,
252+ struct_name : Option < Ident > ,
253+ schema_output : & TokenStream ,
254+ operation_name : & Ident ,
255+ operation_name_literal : & str ,
256+ mulutiple_operation : bool ,
257+ ) -> ( TokenStream , TokenStream ) {
258+ let struct_name = if struct_name. is_some ( ) {
259+ struct_name. unwrap ( )
260+ } else {
261+ operation_name. clone ( )
262+ } ;
263+
264+ let ( respons_data_struct_name, variables_struct_name) = if mulutiple_operation {
265+ (
266+ Ident :: new (
267+ format ! ( "{}ResponseData" , operation_name_literal) . as_str ( ) ,
268+ Span :: call_site ( ) ,
269+ ) ,
270+ Ident :: new (
271+ format ! ( "{}Variables" , operation_name) . as_str ( ) ,
272+ Span :: call_site ( ) ,
273+ ) ,
274+ )
275+ } else {
276+ (
277+ Ident :: new ( "ResponseData" , Span :: call_site ( ) ) ,
278+ Ident :: new ( "Variables" , Span :: call_site ( ) ) ,
279+ )
280+ } ;
281+
282+ let schema_token = quote ! (
283+ pub const OPERATION_NAME : & ' static str = #operation_name_literal;
284+ #schema_output
285+ ) ;
286+ let trait_token = quote ! (
171287 impl :: graphql_client:: GraphQLQuery for #struct_name {
172- type Variables = #module_name:: Variables ;
173- type ResponseData = #module_name:: ResponseData ;
288+ type Variables = #module_name:: #variables_struct_name ;
289+ type ResponseData = #module_name:: #respons_data_struct_name ;
174290
175291 fn build_query( variables: Self :: Variables ) -> :: graphql_client:: QueryBody <Self :: Variables > {
176292 :: graphql_client:: QueryBody {
@@ -182,8 +298,7 @@ pub fn generate_module_token_stream(
182298 }
183299 }
184300 ) ;
185-
186- Ok ( result)
301+ ( schema_token, trait_token)
187302}
188303
189304fn read_file ( path : & :: std:: path:: Path ) -> Result < String , failure:: Error > {
0 commit comments