juniper_from_schema/
lib.rs

1//! This library contains a procedural macro that reads a GraphQL schema file, and generates the
2//! corresponding [Juniper](https://crates.io/crates/juniper) [macro calls]. This means you can
3//! have a real schema file and be guaranteed that it matches your Rust implementation. It also
4//! removes most of the boilerplate involved in using Juniper.
5//!
6//! [macro calls]: https://graphql-rust.github.io/types/objects/complex_fields.html
7//!
8//! # Table of contents
9//!
10//! - [Example](#example)
11//! - [Example web app](#example-web-app)
12//! - [GraphQL features](#graphql-features)
13//!     - [The `ID` type](#the-id-type)
14//!     - [Custom scalar types](#custom-scalar-types)
15//!     - [Special case scalars](#special-case-scalars)
16//!     - [Interfaces](#interfaces)
17//!     - [Union types](#union-types)
18//!     - [Input objects](#input-objects)
19//!     - [Enumeration types](#enumeration-types)
20//!     - [Default argument values](#default-argument-values)
21//! - [Supported schema directives](#supported-schema-directives)
22//!     - [Definition for `@juniper`](#definition-for-juniper)
23//!     - [Customizing ownership](#customizing-ownership)
24//!     - [Infallible fields](#infallible-fields)
25//! - [GraphQL to Rust types](#graphql-to-rust-types)
26//! - [Query trails](#query-trails)
27//!     - [Abbreviated example](#abbreviated-example)
28//!     - [Types](#types)
29//!     - [Downcasting for interface and union `QueryTrail`s](#downcasting-for-interface-and-union-querytrails)
30//!     - [`QueryTrail`s for fields that take arguments](#querytrails-for-fields-that-take-arguments)
31//! - [Customizing the error type](#customizing-the-error-type)
32//! - [Customizing the context type](#customizing-the-context-type)
33//! - [Inspecting the generated code](#inspecting-the-generated-code)
34//!
35//! # Example
36//!
37//! Schema:
38//!
39//! ```graphql
40//! schema {
41//!   query: Query
42//!   mutation: Mutation
43//! }
44//!
45//! type Query {
46//!   // The directive makes the return value `FieldResult<String>`
47//!   // rather than the default `FieldResult<&String>`
48//!   helloWorld(name: String!): String! @juniper(ownership: "owned")
49//! }
50//!
51//! type Mutation {
52//!   noop: Boolean!
53//! }
54//! ```
55//!
56//! How you could implement that schema:
57//!
58//! ```
59//! #[macro_use]
60//! extern crate juniper;
61//!
62//! use juniper_from_schema::graphql_schema_from_file;
63//!
64//! // This is the important line
65//! graphql_schema_from_file!("tests/schemas/doc_schema.graphql");
66//!
67//! pub struct Context;
68//! impl juniper::Context for Context {}
69//!
70//! pub struct Query;
71//!
72//! impl QueryFields for Query {
73//!     fn field_hello_world(
74//!         &self,
75//!         executor: &juniper::Executor<'_, Context>,
76//!         name: String,
77//!     ) -> juniper::FieldResult<String> {
78//!         Ok(format!("Hello, {}!", name))
79//!     }
80//! }
81//!
82//! pub struct Mutation;
83//!
84//! impl MutationFields for Mutation {
85//!     fn field_noop(&self, executor: &juniper::Executor<'_, Context>) -> juniper::FieldResult<&bool> {
86//!         Ok(&true)
87//!     }
88//! }
89//!
90//! fn main() {
91//!     let ctx = Context;
92//!
93//!     let query = "query { helloWorld(name: \"Ferris\") }";
94//!
95//!     let (result, errors) = juniper::execute(
96//!         query,
97//!         None,
98//!         &Schema::new(Query, Mutation),
99//!         &juniper::Variables::new(),
100//!         &ctx,
101//!     )
102//!     .unwrap();
103//!
104//!     assert_eq!(errors.len(), 0);
105//!     assert_eq!(
106//!         result
107//!             .as_object_value()
108//!             .unwrap()
109//!             .get_field_value("helloWorld")
110//!             .unwrap()
111//!             .as_scalar_value::<String>()
112//!             .unwrap(),
113//!         "Hello, Ferris!",
114//!     );
115//! }
116//! ```
117//!
118//! And with `graphql_schema_from_file!` expanded your code would look something like this:
119//!
120//! ```
121//! #[macro_use]
122//! extern crate juniper;
123//!
124//! pub struct Context;
125//! impl juniper::Context for Context {}
126//!
127//! pub struct Query;
128//!
129//! juniper::graphql_object!(Query: Context |&self| {
130//!     field hello_world(&executor, name: String) -> juniper::FieldResult<String> {
131//!         <Self as QueryFields>::field_hello_world(&self, &executor, name)
132//!     }
133//! });
134//!
135//! trait QueryFields {
136//!     fn field_hello_world(
137//!         &self,
138//!         executor: &juniper::Executor<'_, Context>,
139//!         name: String,
140//!     ) -> juniper::FieldResult<String>;
141//! }
142//!
143//! impl QueryFields for Query {
144//!     fn field_hello_world(
145//!         &self,
146//!         executor: &juniper::Executor<'_, Context>,
147//!         name: String,
148//!     ) -> juniper::FieldResult<String> {
149//!         Ok(format!("Hello, {}!", name))
150//!     }
151//! }
152//!
153//! pub struct Mutation;
154//!
155//! juniper::graphql_object!(Mutation: Context |&self| {
156//!     field noop(&executor) -> juniper::FieldResult<&bool> {
157//!         <Self as MutationFields>::field_noop(&self, &executor)
158//!     }
159//! });
160//!
161//! trait MutationFields {
162//!     fn field_noop(&self, executor: &juniper::Executor<'_, Context>) -> juniper::FieldResult<&bool>;
163//! }
164//!
165//! impl MutationFields for Mutation {
166//!     fn field_noop(&self, executor: &juniper::Executor<'_, Context>) -> juniper::FieldResult<&bool> {
167//!         Ok(&true)
168//!     }
169//! }
170//!
171//! type Schema = juniper::RootNode<'static, Query, Mutation>;
172//!
173//! fn main() {
174//!     let ctx = Context;
175//!
176//!     let query = "query { helloWorld(name: \"Ferris\") }";
177//!
178//!     let (result, errors) = juniper::execute(
179//!         query,
180//!         None,
181//!         &Schema::new(Query, Mutation),
182//!         &juniper::Variables::new(),
183//!         &ctx,
184//!     )
185//!     .unwrap();
186//!
187//!     assert_eq!(errors.len(), 0);
188//!     assert_eq!(
189//!         result
190//!             .as_object_value()
191//!             .unwrap()
192//!             .get_field_value("helloWorld")
193//!             .unwrap()
194//!             .as_scalar_value::<String>()
195//!             .unwrap(),
196//!         "Hello, Ferris!",
197//!     );
198//! }
199//! ```
200//!
201//! # Example web app
202//!
203//! You can find an example of how to use this library together with [Rocket] and [Diesel] to make
204//! a GraphQL web app at <https://github.com/davidpdrsn/graphql-app-example> or an example of how
205//! to use this library with [Actix] and [Diesel] at
206//! <https://github.com/husseinraoouf/graphql-actix-example>.
207//!
208//! [Rocket]: https://rocket.rs
209//! [Diesel]: http://diesel.rs
210//! [Actix]: https://actix.rs/
211//!
212//! # GraphQL features
213//!
214//! The goal of this library is to support as much of GraphQL as Juniper does.
215//!
216//! Here is the complete list of features:
217//!
218//! Supported:
219//! - Object types including converting lists and non-nulls to Rust types
220//! - Custom scalar types including the `ID` type
221//! - Interfaces
222//! - Unions
223//! - Input objects
224//! - Enumeration types
225//!
226//! Not supported yet:
227//! - Subscriptions (will be supported once Juniper supports subscriptions)
228//! - Type extensions
229//!
230//! ## The `ID` type
231//!
232//! The `ID` GraphQL type will be generated into [`juniper::ID`].
233//!
234//! [`juniper::ID`]: https://docs.rs/juniper/latest/juniper/struct.ID.html
235//!
236//! ## Custom scalar types
237//!
238//! Custom scalar types will be generated into a newtype wrapper around a `String`. For example:
239//!
240//! ```graphql
241//! scalar Cursor
242//! ```
243//!
244//! Would result in
245//!
246//! ```
247//! pub struct Cursor(pub String);
248//! ```
249//!
250//! ## Special case scalars
251//!
252//! A couple of scalar names have special meaning. Those are:
253//!
254//! - `Url` becomes
255//! [`url::Url`](https://docs.rs/url/2.1.0/url/struct.Url.html).
256//! - `Uuid` becomes
257//! [`uuid::Uuid`](https://docs.rs/uuid/0.7.4/uuid/struct.Uuid.html).
258//! - `Date` becomes
259//! [`chrono::naive::NaiveDate`](https://docs.rs/chrono/0.4.6/chrono/naive/struct.NaiveDate.html).
260//! - `DateTimeUtc` becomes [`chrono::DateTime<chrono::offset::Utc>`] by default but if defined with
261//! `scalar DateTimeUtc @juniper(with_time_zone: false)` it will become [`chrono::naive::NaiveDateTime`].
262//!
263//! Juniper doesn't support [`chrono::Date`](https://docs.rs/chrono/0.4.9/chrono/struct.Date.html)
264//! so therefore this library cannot support that either. You can read about Juniper's supported
265//! integrations [here](https://docs.rs/juniper/0.13.1/juniper/integrations/index.html).
266//!
267//! [`chrono::DateTime<chrono::offset::Utc>`]: https://docs.rs/chrono/0.4.9/chrono/struct.DateTime.html
268//! [`chrono::naive::NaiveDateTime`]: https://docs.rs/chrono/0.4.9/chrono/naive/struct.NaiveDateTime.html
269//!
270//! ## Interfaces
271//!
272//! Juniper has several ways of representing GraphQL interfaces in Rust. They are listed
273//! [here](https://graphql-rust.github.io/types/interfaces.html#enums) along with their advantages
274//! and disadvantages.
275//!
276//! For the generated code we use the `enum` pattern because we found it to be the most flexible.
277//!
278//! Abbreviated example (find [complete example here](https://github.com/davidpdrsn/juniper-from-schema/blob/master/examples/interface.rs)):
279//!
280//! ```
281//! # #[macro_use]
282//! # extern crate juniper;
283//! # use juniper::*;
284//! # use juniper_from_schema::graphql_schema;
285//! # fn main() {}
286//! # pub struct Context;
287//! # impl juniper::Context for Context {}
288//! # pub struct Article { id: ID, text: String }
289//! # impl ArticleFields for Article {
290//! #     fn field_id(
291//! #         &self,
292//! #         executor: &Executor<'_, Context>,
293//! #     ) -> FieldResult<&ID> { unimplemented!() }
294//! #     fn field_text(
295//! #         &self,
296//! #         executor: &Executor<'_, Context>,
297//! #     ) -> FieldResult<&String> { unimplemented!() }
298//! # }
299//! # pub struct Tweet { id: ID, text: String }
300//! # impl TweetFields for Tweet {
301//! #     fn field_id(
302//! #         &self,
303//! #         executor: &Executor<'_, Context>,
304//! #     ) -> FieldResult<&ID> { unimplemented!() }
305//! #     fn field_text(
306//! #         &self,
307//! #         executor: &Executor<'_, Context>,
308//! #     ) -> FieldResult<&String> { unimplemented!() }
309//! # }
310//! #
311//! graphql_schema! {
312//!     schema {
313//!         query: Query
314//!     }
315//!
316//!     type Query {
317//!         search(query: String!): [SearchResult!]! @juniper(ownership: "owned")
318//!     }
319//!
320//!     interface SearchResult {
321//!         id: ID!
322//!         text: String!
323//!     }
324//!
325//!     type Article implements SearchResult {
326//!         id: ID!
327//!         text: String!
328//!     }
329//!
330//!     type Tweet implements SearchResult {
331//!         id: ID!
332//!         text: String!
333//!     }
334//! }
335//!
336//! pub struct Query;
337//!
338//! impl QueryFields for Query {
339//!     fn field_search(
340//!         &self,
341//!         executor: &Executor<'_, Context>,
342//!         trail: &QueryTrail<'_, SearchResult, juniper_from_schema::Walked>,
343//!         query: String,
344//!     ) -> FieldResult<Vec<SearchResult>> {
345//!         let article: Article = Article { id: ID::new("1"), text: "Business".to_string() };
346//!         let tweet: Tweet = Tweet { id: ID::new("2"), text: "1 weird tip".to_string() };
347//!
348//!         let posts = vec![
349//!             SearchResult::from(article),
350//!             SearchResult::from(tweet),
351//!         ];
352//!
353//!         Ok(posts)
354//!     }
355//! }
356//! ```
357//!
358//! The enum that gets generated has variants for each type that implements the interface and also
359//! implements `From<T>` for each type.
360//!
361//! ## Union types
362//!
363//! Union types are basically just interfaces so they work in very much the same way.
364//!
365//! Abbreviated example (find [complete example here](https://github.com/davidpdrsn/juniper-from-schema/blob/master/examples/union_types.rs)):
366//!
367//! ```
368//! # #[macro_use]
369//! # extern crate juniper;
370//! # use juniper::*;
371//! # use juniper_from_schema::graphql_schema;
372//! # fn main() {}
373//! # pub struct Context;
374//! # impl juniper::Context for Context {}
375//! # pub struct Article { id: ID, text: String }
376//! # impl ArticleFields for Article {
377//! #     fn field_id(
378//! #         &self,
379//! #         executor: &Executor<'_, Context>,
380//! #     ) -> FieldResult<&ID> { unimplemented!() }
381//! #     fn field_text(
382//! #         &self,
383//! #         executor: &Executor<'_, Context>,
384//! #     ) -> FieldResult<&String> { unimplemented!() }
385//! # }
386//! # pub struct Tweet { id: ID, text: String }
387//! # impl TweetFields for Tweet {
388//! #     fn field_id(
389//! #         &self,
390//! #         executor: &Executor<'_, Context>,
391//! #     ) -> FieldResult<&ID> { unimplemented!() }
392//! #     fn field_text(
393//! #         &self,
394//! #         executor: &Executor<'_, Context>,
395//! #     ) -> FieldResult<&String> { unimplemented!() }
396//! # }
397//! #
398//! graphql_schema! {
399//!     schema {
400//!         query: Query
401//!     }
402//!
403//!     type Query {
404//!         search(query: String!): [SearchResult!]! @juniper(ownership: "owned")
405//!     }
406//!
407//!     union SearchResult = Article | Tweet
408//!
409//!     type Article {
410//!         id: ID!
411//!         text: String!
412//!     }
413//!
414//!     type Tweet {
415//!         id: ID!
416//!         text: String!
417//!     }
418//! }
419//!
420//! pub struct Query;
421//!
422//! impl QueryFields for Query {
423//!     fn field_search(
424//!         &self,
425//!         executor: &Executor<'_, Context>,
426//!         trail: &QueryTrail<'_, SearchResult, juniper_from_schema::Walked>,
427//!         query: String,
428//!     ) -> FieldResult<Vec<SearchResult>> {
429//!         let article: Article = Article { id: ID::new("1"), text: "Business".to_string() };
430//!         let tweet: Tweet = Tweet { id: ID::new("2"), text: "1 weird tip".to_string() };
431//!
432//!         let posts = vec![
433//!             SearchResult::from(article),
434//!             SearchResult::from(tweet),
435//!         ];
436//!
437//!         Ok(posts)
438//!     }
439//! }
440//! ```
441//!
442//! ## Input objects
443//!
444//! Input objects will be converted into Rust structs with public fields.
445//!
446//! Abbreviated example (find [complete example here](https://github.com/davidpdrsn/juniper-from-schema/blob/master/examples/input_types.rs)):
447//!
448//! ```
449//! # #[macro_use]
450//! # extern crate juniper;
451//! # use juniper::*;
452//! # use juniper_from_schema::graphql_schema;
453//! # fn main() {}
454//! # pub struct Context;
455//! # impl juniper::Context for Context {}
456//! # pub struct Post { id: ID }
457//! # impl PostFields for Post {
458//! #     fn field_id(
459//! #         &self,
460//! #         executor: &Executor<'_, Context>,
461//! #     ) -> FieldResult<&ID> {
462//! #         unimplemented!()
463//! #     }
464//! #     fn field_title(
465//! #         &self,
466//! #         executor: &Executor<'_, Context>,
467//! #     ) -> FieldResult<&String> {
468//! #         unimplemented!()
469//! #     }
470//! # }
471//! # pub struct Query;
472//! # impl QueryFields for Query {
473//! #     fn field_noop(
474//! #         &self,
475//! #         executor: &Executor<'_, Context>,
476//! #     ) -> FieldResult<&bool> {
477//! #         unimplemented!()
478//! #     }
479//! # }
480//! graphql_schema! {
481//!     schema {
482//!         query: Query
483//!         mutation: Mutation
484//!     }
485//!
486//!     type Mutation {
487//!         createPost(input: CreatePost!): Post @juniper(ownership: "owned")
488//!     }
489//!
490//!     input CreatePost {
491//!         title: String!
492//!     }
493//!
494//!     type Post {
495//!         id: ID!
496//!         title: String!
497//!     }
498//!
499//!     type Query { noop: Boolean! }
500//! }
501//!
502//! pub struct Mutation;
503//!
504//! impl MutationFields for Mutation {
505//!     fn field_create_post(
506//!         &self,
507//!         executor: &Executor<'_, Context>,
508//!         trail: &QueryTrail<'_, Post, juniper_from_schema::Walked>,
509//!         input: CreatePost,
510//!     ) -> FieldResult<Option<Post>> {
511//!         let title: String = input.title;
512//!
513//!         unimplemented!()
514//!     }
515//! }
516//! ```
517//!
518//! From that example `CreatePost` will be defined as
519//!
520//! ```
521//! pub struct CreatePost {
522//!     pub title: String,
523//! }
524//! ```
525//!
526//! ## Enumeration types
527//!
528//! GraphQL enumeration types will be converted into normal Rust enums. The name of each variant
529//! will be camel cased.
530//!
531//! Abbreviated example (find [complete example here](https://github.com/davidpdrsn/juniper-from-schema/blob/master/examples/enumeration_types.rs)):
532//!
533//! ```
534//! # #[macro_use]
535//! # extern crate juniper;
536//! # use juniper::*;
537//! # use juniper_from_schema::graphql_schema;
538//! # fn main() {}
539//! # pub struct Context;
540//! # impl juniper::Context for Context {}
541//! # pub struct Post { id: ID }
542//! # impl PostFields for Post {
543//! #     fn field_id(
544//! #         &self,
545//! #         executor: &Executor<'_, Context>,
546//! #     ) -> FieldResult<&ID> {
547//! #         Ok(&self.id)
548//! #     }
549//! # }
550//! #
551//! graphql_schema! {
552//!     schema {
553//!         query: Query
554//!     }
555//!
556//!     enum Status {
557//!         PUBLISHED
558//!         UNPUBLISHED
559//!     }
560//!
561//!     type Query {
562//!         allPosts(status: Status!): [Post!]! @juniper(ownership: "owned")
563//!     }
564//!
565//!     type Post {
566//!         id: ID!
567//!     }
568//! }
569//!
570//! pub struct Query;
571//!
572//! impl QueryFields for Query {
573//!     fn field_all_posts(
574//!         &self,
575//!         executor: &Executor<'_, Context>,
576//!         trail: &QueryTrail<'_, Post, juniper_from_schema::Walked>,
577//!         status: Status,
578//!     ) -> FieldResult<Vec<Post>> {
579//!         match status {
580//!             Status::Published => unimplemented!("find published posts"),
581//!             Status::Unpublished => unimplemented!("find unpublished posts"),
582//!         }
583//!     }
584//! }
585//! ```
586//!
587//! ## Default argument values
588//!
589//! In GraphQL you are able to provide default values for field arguments, provided the argument is
590//! nullable.
591//!
592//! Arguments of the following types support default values:
593//! - `Float`
594//! - `Int`
595//! - `String`
596//! - `Boolean`
597//! - Enumerations
598//! - Input objects (as field arguments, see below)
599//! - Lists containing some other supported type
600//!
601//! Abbreviated example (find [complete example here](https://github.com/davidpdrsn/juniper-from-schema/blob/master/examples/default_argument_values.rs)):
602//!
603//! ```
604//! # #[macro_use]
605//! # extern crate juniper;
606//! # use juniper::*;
607//! # use juniper_from_schema::graphql_schema;
608//! # fn main() {}
609//! # pub struct Context;
610//! # impl juniper::Context for Context {}
611//! # pub struct Post { id: ID }
612//! # impl PostFields for Post {
613//! #     fn field_id(
614//! #         &self,
615//! #         executor: &Executor<'_, Context>,
616//! #     ) -> FieldResult<&ID> {
617//! #         Ok(&self.id)
618//! #     }
619//! # }
620//! #
621//! graphql_schema! {
622//!     schema {
623//!         query: Query
624//!     }
625//!
626//!     enum Status {
627//!         PUBLISHED
628//!         UNPUBLISHED
629//!     }
630//!
631//!     input Pagination {
632//!         pageSize: Int!
633//!         cursor: ID
634//!     }
635//!
636//!     type Query {
637//!         allPosts(
638//!             status: Status = PUBLISHED,
639//!             pagination: Pagination = { pageSize: 20 }
640//!         ): [Post!]! @juniper(ownership: "owned")
641//!     }
642//!
643//!     type Post {
644//!         id: ID!
645//!     }
646//! }
647//!
648//! pub struct Query;
649//!
650//! impl QueryFields for Query {
651//!     fn field_all_posts(
652//!         &self,
653//!         executor: &Executor<'_, Context>,
654//!         trail: &QueryTrail<'_, Post, juniper_from_schema::Walked>,
655//!         status: Status,
656//!         pagination: Pagination,
657//!     ) -> FieldResult<Vec<Post>> {
658//!         // `status` will be `Status::Published` if not given in the query
659//!
660//!         match status {
661//!             Status::Published => unimplemented!("find published posts"),
662//!             Status::Unpublished => unimplemented!("find unpublished posts"),
663//!         }
664//!     }
665//! }
666//! ```
667//!
668//! ### Input object gotchas
669//!
670//! Defaults for input objects are only supported as field arguments. The following is not
671//! supported
672//!
673//! ```graphql
674//! input SomeType {
675//!   field: Int = 1
676//! }
677//! ```
678//!
679//! This isn't supported because [the spec is unclear about how to handle multiple nested
680//! defaults](https://github.com/webonyx/graphql-php/issues/350).
681//!
682//! Also, defaults are only used if no arguments are passed. So given the schema
683//!
684//! ```graphql
685//! input Input {
686//!   a: String
687//!   b: String
688//! }
689//!
690//! type Query {
691//!   field(arg: Input = { a: "a" }): Int!
692//! }
693//! ```
694//!
695//! and the query
696//!
697//! ```graphql
698//! query MyQuery {
699//!   field(arg: { b: "my b" })
700//! }
701//! ```
702//!
703//! The value of `arg` inside the resolver would be `Input { a: None, b: Some("my b") }`. Note that
704//! even though `a` has a default value in the field doesn't get used here because we set `arg` in
705//! the query.
706//!
707//! # Supported schema directives
708//!
709//! A number of [schema directives][] are supported that lets you customize the generated code:
710//!
711//! - `@juniper(ownership: "owned|borrowed|as_ref")`. For customizing ownership of returned data.
712//! More info [here](#customizing-ownership).
713//! - `@juniper(infallible: true|false)`. Customize if a field should return `Result<T, _>` or
714//! just `T`. More info
715//! [here](http://localhost:4000/juniper_from_schema/index.html#infallible-fields).
716//! - `@deprecated`. For deprecating types in your schema. Also supports supplying a reason with
717//! `@deprecated(reason: "...")`
718//!
719//! [schema directives]: https://www.apollographql.com/docs/apollo-server/schema/directives/
720//!
721//! ## Definition for `@juniper`
722//!
723//! Some tools that operate on your GraphQL schema require you to include the definition for all
724//! directives used. So in case you need it the definition for `@juniper` is:
725//!
726//! ```graphql
727//! directive @juniper(
728//!     ownership: String = "borrowed",
729//!     infallible: Boolean = false,
730//!     with_time_zone: Boolean = true
731//! ) on FIELD_DEFINITION
732//! ```
733//!
734//! This directive definition is allowed in your schema, as well as any other directive definition.
735//! Definitions of `@juniper` that differ from this are not allowed though.
736//!
737//! The definition might change in future versions. Please refer to the [changelog][].
738//!
739//! juniper-from-schema doesn't require to put this in your schema, so you only need to include it
740//! if some other tool requires it.
741//!
742//! [changelog]: https://github.com/davidpdrsn/juniper-from-schema/blob/master/CHANGELOG.md
743//!
744//! ## Customizing ownership
745//!
746//! By default all fields return borrowed values. Specifically the type is
747//! `juniper::FieldResult<&'a T>` where `'a` is the lifetime of `self`. This works well for
748//! returning data owned by `self` and avoids needless `.clone()` calls you would need if fields
749//! returned owned values.
750//!
751//! However if you need to change the ownership you have to add the directive
752//! `@juniper(ownership:)` to the field in the schema.
753//!
754//! It takes the following arguments:
755//!
756//! - `@juniper(ownership: "borrowed")`: The data returned will be borrowed from `self`
757//! (`FieldResult<&T>`).
758//! - `@juniper(ownership: "owned")`: The return type will be owned (`FieldResult<T>`).
759//! - `@juniper(ownership: "as_ref")`: Only applicable for `Option` and `Vec` return types. Changes
760//! the inner type to be borrowed (`FieldResult<Option<&T>>` or `FieldResult<Vec<&T>>`).
761//!
762//! Example:
763//!
764//! ```
765//! # #[macro_use]
766//! # extern crate juniper;
767//! # use juniper_from_schema::*;
768//! # use juniper::*;
769//! # pub struct Context;
770//! # impl juniper::Context for Context {}
771//! # fn main() {}
772//! graphql_schema! {
773//!     schema {
774//!         query: Query
775//!     }
776//!
777//!     type Query {
778//!         borrowed: String!
779//!         owned: String! @juniper(ownership: "owned")
780//!         asRef: String @juniper(ownership: "as_ref")
781//!     }
782//! }
783//!
784//! pub struct Query;
785//!
786//! impl QueryFields for Query {
787//!     fn field_borrowed(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
788//!         // ...
789//!         # unimplemented!()
790//!     }
791//!
792//!     fn field_owned(&self, _: &Executor<'_, Context>) -> FieldResult<String> {
793//!         // ...
794//!         # unimplemented!()
795//!     }
796//!
797//!     fn field_as_ref(&self, _: &Executor<'_, Context>) -> FieldResult<Option<&String>> {
798//!         // ...
799//!         # unimplemented!()
800//!     }
801//! }
802//! ```
803//!
804//! All field arguments will be owned.
805//!
806//! ## Infallible fields
807//!
808//! By default the generated resolvers are fallible, meaining they return a `Result<T, _>` rather
809//! than a bare `T`. You can customize that using `@juniper(infallible: true)`.
810//!
811//! Example:
812//!
813//! ```
814//! # #[macro_use]
815//! # extern crate juniper;
816//! # use juniper_from_schema::*;
817//! # use juniper::*;
818//! # pub struct Context;
819//! # impl juniper::Context for Context {}
820//! # fn main() {}
821//! graphql_schema! {
822//!     schema {
823//!         query: Query
824//!     }
825//!
826//!     type Query {
827//!         canError: String!
828//!         cannotError: String! @juniper(infallible: true)
829//!         cannotErrorAndOwned: String! @juniper(infallible: true, ownership: "owned")
830//!     }
831//! }
832//!
833//! pub struct Query;
834//!
835//! impl QueryFields for Query {
836//!     fn field_can_error(&self, _: &Executor<'_, Context>) -> FieldResult<&String> {
837//!         // ...
838//!         # unimplemented!()
839//!     }
840//!
841//!     fn field_cannot_error(&self, _: &Executor<'_, Context>) -> &String {
842//!         // ...
843//!         # unimplemented!()
844//!     }
845//!
846//!     fn field_cannot_error_and_owned(&self, _: &Executor<'_, Context>) -> String {
847//!         // ...
848//!         # unimplemented!()
849//!     }
850//! }
851//! ```
852//!
853//! # GraphQL to Rust types
854//!
855//! This is how the standard GraphQL types will be mapped to Rust:
856//!
857//! - `Int` -> `i32`
858//! - `Float` -> `f64`
859//! - `String` -> `String`
860//! - `Boolean` -> `bool`
861//! - `ID` -> [`juniper::ID`](https://docs.rs/juniper/latest/juniper/struct.ID.html)
862//!
863//! # Query trails
864//!
865//! If you're not careful about preloading associations for deeply nested queries you risk getting
866//! lots of [N+1 query bugs][]. Juniper provides a [look ahead API][] which lets you inspect things
867//! coming up further down a query. However the API is string based, so you risk making typos and
868//! checking for fields that don't exist.
869//!
870//! `QueryTrail` is a thin wrapper around Juniper look aheads with generated methods for each field
871//! on all your types. This means the compiler will reject your code if you're checking for invalid
872//! fields.
873//!
874//! Resolver methods (`field_*`) that return object types (non scalar values) will also get a
875//! `QueryTrail` argument besides the executor.
876//!
877//! Since the `QueryTrail` type itself is defined in this crate (rather than being inserted into
878//! your code) we cannot directly add methods for your GraphQL fields. Those methods have to be
879//! added through ["extension traits"](http://xion.io/post/code/rust-extension-traits.html). So if
880//! you see an error like
881//!
882//! ```text
883//!    |  trail.foo();
884//!    |        ^^^ method not found in `&juniper_from_schema::QueryTrail<'a, User, juniper_from_schema::Walked>`
885//!    |
886//!    = help: items from traits can only be used if the trait is in scope
887//! help: the following trait is implemented but not in scope, perhaps add a `use` for it:
888//!    |
889//! 2  | use crate::graphql_schema::query_trails::QueryTrailUserExtensions;
890//!    |
891//! ```
892//!
893//! Then adding `use crate::graphql_schema::query_trails::*` to you module should fix it. This is
894//! necessary because all the extention traits are generated inside a module called `query_trails`.
895//! This is done so you can glob import the `QueryTrail` extension traits without glob importing
896//! everything from your GraphQL schema.
897//!
898//! If you just want everything from the schema `use crate::graphql_schema::*` will also bring in
899//! the extension traits.
900//!
901//! [N+1 query bugs]: https://secure.phabricator.com/book/phabcontrib/article/n_plus_one/
902//! [look ahead API]: https://docs.rs/juniper/0.11.1/juniper/struct.LookAheadSelection.html
903//!
904//! ## Abbreviated example
905//!
906//! Find [complete example here](https://github.com/davidpdrsn/juniper-from-schema/blob/master/examples/query_trails.rs)
907//!
908//! ```
909//! # #[macro_use]
910//! # extern crate juniper;
911//! # use juniper::*;
912//! # use juniper_from_schema::graphql_schema;
913//! # fn main() {}
914//! # pub struct Context;
915//! # impl juniper::Context for Context {}
916//! #
917//! graphql_schema! {
918//!     schema {
919//!         query: Query
920//!     }
921//!
922//!     type Query {
923//!         allPosts: [Post!]! @juniper(ownership: "owned")
924//!     }
925//!
926//!     type Post {
927//!         id: Int!
928//!         author: User!
929//!     }
930//!
931//!     type User {
932//!         id: Int!
933//!     }
934//! }
935//!
936//! pub struct Query;
937//!
938//! impl QueryFields for Query {
939//!     fn field_all_posts(
940//!         &self,
941//!         executor: &Executor<'_, Context>,
942//!         trail: &QueryTrail<'_, Post, juniper_from_schema::Walked>,
943//!     ) -> FieldResult<Vec<Post>> {
944//!         // Check if the query includes the author
945//!         if let Some(_) = trail.author().walk() {
946//!             // Somehow preload the users to avoid N+1 query bugs
947//!             // Exactly how to do this depends on your setup
948//!         }
949//!
950//!         // Normally this would come from the database
951//!         let post = Post {
952//!             id: 1,
953//!             author: User { id: 1 },
954//!         };
955//!
956//!         Ok(vec![post])
957//!     }
958//! }
959//!
960//! pub struct Post {
961//!     id: i32,
962//!     author: User,
963//! }
964//!
965//! impl PostFields for Post {
966//!     fn field_id(&self, executor: &Executor<'_, Context>) -> FieldResult<&i32> {
967//!         Ok(&self.id)
968//!     }
969//!
970//!     fn field_author(
971//!         &self,
972//!         executor: &Executor<'_, Context>,
973//!         trail: &QueryTrail<'_, User, juniper_from_schema::Walked>,
974//!     ) -> FieldResult<&User> {
975//!         Ok(&self.author)
976//!     }
977//! }
978//!
979//! pub struct User {
980//!     id: i32,
981//! }
982//!
983//! impl UserFields for User {
984//!     fn field_id(
985//!         &self,
986//!         executor: &Executor<'_, Context>,
987//!     ) -> FieldResult<&i32> {
988//!         Ok(&self.id)
989//!     }
990//! }
991//! ```
992//!
993//! ## Types
994//!
995//! A query trail has two generic parameters: `QueryTrail<'a, T, K>`. `T` is the type the current
996//! field returns and `K` is either `Walked` or `NotWalked`.
997//!
998//! The lifetime `'a` comes from Juniper and is the lifetime of the incoming query.
999//!
1000//! ### `T`
1001//!
1002//! The `T` allows us to implement different methods for different types. For example in the
1003//! example above we implement `id` and `author` for `QueryTrail<'_, Post, K>` but only `id` for
1004//! `QueryTrail<'_, User, K>`.
1005//!
1006//! If your field returns a `Vec<T>` or `Option<T>` the given query trail will be `QueryTrail<'_,
1007//! T, _>`. So `Vec` or `Option` will be removed and you'll only be given the inner most type.
1008//! That is because in the GraphQL query syntax it doesn't matter if you're querying a `User`
1009//! or `[User]`. The fields you have access to are the same.
1010//!
1011//! ### `K`
1012//!
1013//! The `Walked` and `NotWalked` types are used to check if a given trail has been checked to
1014//! actually be part of a query. Calling any method on a `QueryTrail<'_, T, K>` will return
1015//! `QueryTrail<'_, T, NotWalked>`, and to check if the trail is actually part of the query you have
1016//! to call `.walk()` which returns `Option<QueryTrail<'_, T, Walked>>`. If that is a `Some(_)`
1017//! you'll know the trail is part of the query and you can do whatever preloading is necessary.
1018//!
1019//! Example:
1020//!
1021//! ```ignore
1022//! if let Some(walked_trail) = trail
1023//!     .some_field()
1024//!     .some_other_field()
1025//!     .third_field()
1026//!     .walk()
1027//! {
1028//!     // preload stuff
1029//! }
1030//! ```
1031//!
1032//! You can always run `cargo doc` and inspect all the methods on `QueryTrail` and in which
1033//! contexts you can call them.
1034//!
1035//! ## Downcasting for interface and union `QueryTrail`s
1036//!
1037//! _This section is mostly relevant if you're using
1038//! [juniper-eager-loading](https://crates.io/crates/juniper-eager-loading) however it isn't
1039//! specific to that library._
1040//!
1041//! If you have a `QueryTrail<'a, T, Walked>` where `T` is an interface or union type you can use
1042//! `.downcast()` to convert that `QueryTrail` into one of the implementors of the interface or
1043//! union.
1044//!
1045//! Example:
1046//!
1047//! ```
1048//! # #[macro_use]
1049//! # extern crate juniper;
1050//! # use juniper::*;
1051//! # use juniper_from_schema::graphql_schema;
1052//! # fn main() {}
1053//! # pub struct Context;
1054//! # impl juniper::Context for Context {}
1055//! # pub struct Article { id: ID }
1056//! # impl ArticleFields for Article {
1057//! #     fn field_id(
1058//! #         &self,
1059//! #         executor: &Executor<'_, Context>,
1060//! #     ) -> FieldResult<&ID> { unimplemented!() }
1061//! # }
1062//! # pub struct Tweet { id: ID, text: String }
1063//! # impl TweetFields for Tweet {
1064//! #     fn field_id(
1065//! #         &self,
1066//! #         executor: &Executor<'_, Context>,
1067//! #     ) -> FieldResult<&ID> { unimplemented!() }
1068//! # }
1069//! #
1070//! graphql_schema! {
1071//!     schema {
1072//!         query: Query
1073//!     }
1074//!
1075//!     type Query {
1076//!         search(query: String!): [SearchResult!]!
1077//!     }
1078//!
1079//!     interface SearchResult {
1080//!         id: ID!
1081//!     }
1082//!
1083//!     type Article implements SearchResult {
1084//!         id: ID!
1085//!     }
1086//!
1087//!     type Tweet implements SearchResult {
1088//!         id: ID!
1089//!     }
1090//! }
1091//!
1092//! pub struct Query;
1093//!
1094//! impl QueryFields for Query {
1095//!     fn field_search(
1096//!         &self,
1097//!         executor: &Executor<'_, Context>,
1098//!         trail: &QueryTrail<'_, SearchResult, juniper_from_schema::Walked>,
1099//!         query: String,
1100//!     ) -> FieldResult<&Vec<SearchResult>> {
1101//!         let article_trail: QueryTrail<'_, Article, Walked> = trail.downcast();
1102//!         let tweet_trail: QueryTrail<'_, Tweet, Walked> = trail.downcast();
1103//!
1104//!         // ...
1105//!         # unimplemented!()
1106//!     }
1107//! }
1108//! ```
1109//!
1110//! ### Why is this useful?
1111//!
1112//! If you were do perform some kind of preloading of data you might have a function that inspects
1113//! a `QueryTrail` and loads the necessary data from a database. Such a function could look like
1114//! this:
1115//!
1116//! ```ignore
1117//! fn preload_users(
1118//!     mut users: Vec<User>,
1119//!     query_trail: &QueryTrail<'_, User, Walked>,
1120//!     db: &Database,
1121//! ) -> Vec<User> {
1122//!     // ...
1123//! }
1124//! ```
1125//!
1126//! This function works well when we have field that returns `[User!]!`. That field is going to get
1127//! a `QueryTrail<'a, User, Walked>` which is exactly what `preload_users` needs.
1128//!
1129//! However, now imagine you have a schema like this:
1130//!
1131//! ```graphql
1132//! type Query {
1133//!     search(query: String!): [SearchResult!]!
1134//! }
1135//!
1136//! union SearchResult = User | City | Country
1137//!
1138//! type User {
1139//!     id: ID!
1140//!     city: City!
1141//! }
1142//!
1143//! type City {
1144//!     id: ID!
1145//!     country: Country!
1146//! }
1147//!
1148//! type Country {
1149//!     id: ID!
1150//! }
1151//! ```
1152//!
1153//! The method `QueryFields::field_search` will receive a `QueryTrail<'a, SearchResult, Walked>`.
1154//! That type doesn't work with `preload_users`. So we have to convert our `QueryTrail<'a,
1155//! SearchResult, Walked>` into `QueryTrail<'a, User, Walked>`.
1156//!
1157//! This can be done by calling `.downcast()` which automatically gets implemented for interface and
1158//! union query trails. See above for an example.
1159//!
1160//! ## `QueryTrail`s for fields that take arguments
1161//!
1162//! Sometimes you have GraphQL fields that take arguments that impact which things your resolvers
1163//! should return. `QueryTrail` therefore also allows you inspect arguments to fields.
1164//!
1165//! Abbreviated example:
1166//!
1167//! ```
1168//! # #[macro_use]
1169//! # extern crate juniper;
1170//! # use juniper_from_schema::*;
1171//! # pub struct Context;
1172//! # impl juniper::Context for Context {}
1173//! # fn main() {}
1174//! # pub struct Country {}
1175//! # impl CountryFields for Country {
1176//! #     fn field_users<'a>(
1177//! #         &self,
1178//! #         executor: &juniper::Executor<'a, Context>,
1179//! #         trail: &QueryTrail<'a, User, Walked>,
1180//! #         active_since: DateTime<Utc>,
1181//! #     ) -> juniper::FieldResult<Vec<User>> {
1182//! #         unimplemented!()
1183//! #     }
1184//! # }
1185//! # pub struct User {}
1186//! # impl UserFields for User {
1187//! #     fn field_id<'a>(
1188//! #         &self,
1189//! #         executor: &juniper::Executor<'a, Context>,
1190//! #     ) -> juniper::FieldResult<&juniper::ID> {
1191//! #         unimplemented!()
1192//! #     }
1193//! # }
1194//! use chrono::prelude::*;
1195//!
1196//! graphql_schema! {
1197//!     schema {
1198//!         query: Query
1199//!     }
1200//!
1201//!     type Query {
1202//!         countries: [Country!]! @juniper(ownership: "owned")
1203//!     }
1204//!
1205//!     type Country {
1206//!         users(activeSince: DateTimeUtc!): [User!]! @juniper(ownership: "owned")
1207//!     }
1208//!
1209//!     type User {
1210//!         id: ID!
1211//!     }
1212//!
1213//!     scalar DateTimeUtc
1214//! }
1215//!
1216//! pub struct Query;
1217//!
1218//! impl QueryFields for Query {
1219//!     fn field_countries<'a>(
1220//!         &self,
1221//!         executor: &'a juniper::Executor<'a, Context>,
1222//!         trail: &'a QueryTrail<'a, Country, Walked>
1223//!     ) -> juniper::FieldResult<Vec<Country>> {
1224//!         // Get struct that has all arguments passed to `Country.users`
1225//!         let args: CountryUsersArgs<'a> = trail.users_args();
1226//!
1227//!         // The struct has methods for each argument, e.g. `active_since`.
1228//!         //
1229//!         // Notice that it automatically converts the incoming value to
1230//!         // a `DateTime<Utc>`.
1231//!         let _: DateTime<Utc> = args.active_since();
1232//!
1233//!         # unimplemented!()
1234//!         // ...
1235//!     }
1236//! }
1237//! ```
1238//!
1239//! You can also elide the `'a` lifetime:
1240//!
1241//! ```
1242//! # #[macro_use]
1243//! # extern crate juniper;
1244//! # use juniper_from_schema::*;
1245//! # pub struct Context;
1246//! # impl juniper::Context for Context {}
1247//! # fn main() {}
1248//! # pub struct Country {}
1249//! # impl CountryFields for Country {
1250//! #     fn field_users<'a>(
1251//! #         &self,
1252//! #         executor: &juniper::Executor<'a, Context>,
1253//! #         trail: &QueryTrail<'a, User, Walked>,
1254//! #         active_since: DateTime<Utc>,
1255//! #     ) -> juniper::FieldResult<Vec<User>> {
1256//! #         unimplemented!()
1257//! #     }
1258//! # }
1259//! # pub struct User {}
1260//! # impl UserFields for User {
1261//! #     fn field_id<'a>(
1262//! #         &self,
1263//! #         executor: &juniper::Executor<'a, Context>,
1264//! #     ) -> juniper::FieldResult<&juniper::ID> {
1265//! #         unimplemented!()
1266//! #     }
1267//! # }
1268//! # use chrono::prelude::*;
1269//! # graphql_schema! {
1270//! #     schema {
1271//! #         query: Query
1272//! #     }
1273//! #     type Query {
1274//! #         countries: [Country!]! @juniper(ownership: "owned")
1275//! #     }
1276//! #     type Country {
1277//! #         users(activeSince: DateTimeUtc!): [User!]! @juniper(ownership: "owned")
1278//! #     }
1279//! #     type User {
1280//! #         id: ID!
1281//! #     }
1282//! #     scalar DateTimeUtc
1283//! # }
1284//! # pub struct Query;
1285//! #
1286//! impl QueryFields for Query {
1287//!     fn field_countries(
1288//!         &self,
1289//!         executor: &juniper::Executor<'_, Context>,
1290//!         trail: &QueryTrail<'_, Country, Walked>
1291//!     ) -> juniper::FieldResult<Vec<Country>> {
1292//!         let args: CountryUsersArgs = trail.users_args();
1293//!
1294//!         # unimplemented!()
1295//!         // ...
1296//!     }
1297//! }
1298//! ```
1299//!
1300//! The name of the arguments struct will always be `{name of type}{name of field}Args` (e.g.
1301//! `CountryUsersArgs`). The method names will always be the name of the arguments in snake case.
1302//!
1303//! The `*_args` method is only defined on `Walked` query trails so if you get an error like:
1304//!
1305//! ```text
1306//! ---- src/lib.rs -  (line 10) stdout ----
1307//! error[E0599]: no method named `users_args` found for type `&QueryTrail<'_, Country, Walked>` in the current
1308//!  scope
1309//!   --> src/lib.rs:10:1
1310//!    |
1311//! 10 |         trail.users_args();
1312//!    |               ^^^^^^^^^^^^ method not found in `&QueryTrail<'_, Country, Walked>`
1313//! ```
1314//!
1315//! It is likely because you've forgotten to call [`.walk()`][] on `trail`.
1316//!
1317//! [`.walk()`]: struct.QueryTrail.html#method.walk
1318//!
1319//! Remember that you can always run `cargo doc` to get a high level overview of the generated
1320//! code.
1321//!
1322//! # Customizing the error type
1323//!
1324//! By default the return type of the generated field methods will be [`juniper::FieldResult<T>`].
1325//! That is just a type alias for `std::result::Result<T, juniper::FieldError>`. Should you want to
1326//! use a different error type than [`juniper::FieldError`] that can be done by passing `,
1327//! error_type: YourType` to [`graphql_schema_from_file!`].
1328//!
1329//! Just keep in that your custom error type must implement [`juniper::IntoFieldError`] to
1330//! type check.
1331//!
1332//! Example:
1333//!
1334//! ```
1335//! # #[macro_use]
1336//! # extern crate juniper;
1337//! # use juniper::*;
1338//! # use juniper_from_schema::graphql_schema_from_file;
1339//! # fn main() {}
1340//! # pub struct Context;
1341//! # impl juniper::Context for Context {}
1342//! # pub struct Mutation;
1343//! # impl MutationFields for Mutation {
1344//! #     fn field_noop(&self, executor: &Executor<'_, Context>) -> Result<&bool, MyError> {
1345//! #         Ok(&true)
1346//! #     }
1347//! # }
1348//! graphql_schema_from_file!("tests/schemas/doc_schema.graphql", error_type: MyError);
1349//!
1350//! pub struct MyError(String);
1351//!
1352//! impl juniper::IntoFieldError for MyError {
1353//!     fn into_field_error(self) -> juniper::FieldError {
1354//!         // Perform custom error handling
1355//!         juniper::FieldError::from(self.0)
1356//!     }
1357//! }
1358//!
1359//! pub struct Query;
1360//!
1361//! impl QueryFields for Query {
1362//!     fn field_hello_world(
1363//!         &self,
1364//!         executor: &Executor<'_, Context>,
1365//!         name: String,
1366//!     ) -> Result<String, MyError> {
1367//!         Ok(format!("Hello, {}!", name))
1368//!     }
1369//! }
1370//! ```
1371//!
1372//! [`graphql_schema!`] does not support changing the error type.
1373//!
1374//! [`graphql_schema!`]: macro.graphql_schema.html
1375//! [`graphql_schema_from_file!`]: macro.graphql_schema_from_file.html
1376//! [`juniper::IntoFieldError`]: https://docs.rs/juniper/0.11.1/juniper/trait.IntoFieldError.html
1377//! [`juniper::FieldError`]: https://docs.rs/juniper/0.11.1/juniper/struct.FieldError.html
1378//! [`juniper::FieldResult<T>`]: https://docs.rs/juniper/0.11.1/juniper/type.FieldResult.html
1379//!
1380//! # Customizing the context type
1381//!
1382//! By default the generate code will assume your context type is called `Context`. If that is not
1383//! the case you can customize it by calling [`graphql_schema_from_file!`] with `context_type: NewName`.
1384//!
1385//! Example:
1386//!
1387//! ```
1388//! # #[macro_use]
1389//! # extern crate juniper;
1390//! # use juniper::*;
1391//! # use juniper_from_schema::graphql_schema_from_file;
1392//! # fn main() {}
1393//! # pub struct Mutation;
1394//! # impl MutationFields for Mutation {
1395//! #     fn field_noop(&self, executor: &Executor<'_, MyContext>) -> juniper::FieldResult<&bool> {
1396//! #         Ok(&true)
1397//! #     }
1398//! # }
1399//! graphql_schema_from_file!("tests/schemas/doc_schema.graphql", context_type: MyContext);
1400//!
1401//! pub struct MyContext;
1402//! impl juniper::Context for MyContext {}
1403//!
1404//! pub struct Query;
1405//!
1406//! impl QueryFields for Query {
1407//!     fn field_hello_world(
1408//!         &self,
1409//!         executor: &Executor<'_, MyContext>,
1410//!         name: String,
1411//!     ) -> juniper::FieldResult<String> {
1412//!         Ok(format!("Hello, {}!", name))
1413//!     }
1414//! }
1415//! ```
1416//!
1417//! [`graphql_schema!`] does not support changing the context type.
1418//!
1419//! [`graphql_schema!`]: macro.graphql_schema.html
1420//! [`graphql_schema_from_file!`]: macro.graphql_schema_from_file.html
1421//!
1422//! # Inspecting the generated code
1423//!
1424//! If you wish to see exactly what code gets generated you can set the env var
1425//! `JUNIPER_FROM_SCHEMA_DEBUG` to `1` when compiling. For example:
1426//!
1427//! ```bash
1428//! JUNIPER_FROM_SCHEMA_DEBUG=1 cargo build
1429//! ```
1430//!
1431//! The code will not be formatted so it might be tricky to read. The easiest way to fix this is to
1432//! copy the printed code to a file and run it through [rustfmt].
1433//!
1434//! Alternatively you can include the [feature] called `"format-debug-output"`. This will run the
1435//! output through [rustfmt] before printing it. That way you don't have to do that manually.
1436//! Example `Cargo.toml`:
1437//!
1438//! ```toml
1439//! [dependencies]
1440//! juniper-from-schema = { version = "x.y.z", features = ["format-debug-output"] }
1441//! ```
1442//!
1443//! Unfortunately this requires that you're using nightly, because [rustfmt requires
1444//! nightly](https://github.com/rust-lang/rustfmt#installing-from-source). It might also break your
1445//! build because [rustfmt] doesn't always compile for some reason ¯\\\_(ツ)\_/¯. If you experience
1446//! this just remove the `"format-debug-output"` feature and format the output manually.
1447//!
1448//! [feature]: https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#choosing-features
1449//! [rustfmt]: https://github.com/rust-lang/rustfmt
1450
1451#![deny(
1452    missing_docs,
1453    unused_imports,
1454    dead_code,
1455    unused_variables,
1456    unused_must_use
1457)]
1458#![doc(html_root_url = "https://docs.rs/juniper-from-schema/0.5.2")]
1459
1460use juniper::{DefaultScalarValue, LookAheadSelection};
1461use std::marker::PhantomData;
1462
1463pub use juniper_from_schema_code_gen::{graphql_schema, graphql_schema_from_file};
1464
1465/// A type used to parameterize `QueryTrail` to know that `walk` has been called.
1466pub struct Walked;
1467
1468/// A type used to parameterize `QueryTrail` to know that `walk` has *not* been called.
1469pub struct NotWalked;
1470
1471/// A wrapper around a `juniper::LookAheadSelection` with methods for each possible child.
1472pub struct QueryTrail<'a, T, K> {
1473    #[doc(hidden)]
1474    pub look_ahead: Option<&'a LookAheadSelection<'a, DefaultScalarValue>>,
1475    #[doc(hidden)]
1476    pub node_type: PhantomData<T>,
1477    #[doc(hidden)]
1478    pub walked: K,
1479}
1480
1481impl<'a, T> QueryTrail<'a, T, NotWalked> {
1482    /// Check if the trail is present in the query being executed
1483    pub fn walk(self) -> Option<QueryTrail<'a, T, Walked>> {
1484        match self.look_ahead {
1485            Some(inner) => Some(QueryTrail {
1486                look_ahead: Some(inner),
1487                node_type: self.node_type,
1488                walked: Walked,
1489            }),
1490            None => None,
1491        }
1492    }
1493}
1494
1495impl<'a, T, K> QueryTrail<'a, T, K> {
1496    #[allow(clippy::new_ret_no_self)]
1497    #[doc(hidden)]
1498    #[allow(missing_docs)]
1499    pub fn new(lh: &'a LookAheadSelection<'a, DefaultScalarValue>) -> QueryTrail<'a, T, Walked> {
1500        QueryTrail {
1501            look_ahead: Some(lh),
1502            node_type: PhantomData,
1503            walked: Walked,
1504        }
1505    }
1506}
1507
1508#[cfg(test)]
1509mod test {
1510    #[allow(unused_imports)]
1511    use super::*;
1512
1513    #[rustversion::nightly]
1514    #[test]
1515    fn test_compile_pass() {
1516        let t = trybuild::TestCases::new();
1517        t.pass("tests/compile_pass/*.rs");
1518        t.compile_fail("tests/compile_fail/*.rs");
1519    }
1520}