libgraphql_macros/
lib.rs

1mod graphql_schema_token_consumer;
2mod graphql_schema_from_str_token_consumer;
3mod emittable_schema;
4mod graphql_schema_parser;
5mod graphql_parse_error;
6mod graphql_token_stream;
7mod rust_to_graphql_token_adapter;
8
9#[cfg(test)]
10mod tests;
11
12use crate::graphql_schema_token_consumer::GraphQLSchemaTokenConsumer;
13use crate::graphql_schema_from_str_token_consumer::GraphQLSchemaFromStrTokenConsumer;
14
15/// Evaluates to a [`Schema`](libgraphql_core::schema::Schema) object given
16/// direct GraphQL schema document syntax.
17///
18/// This macro is effectively a compile-time version of
19/// [`SchemaBuilder::build_from_str()`](libgraphql_core::schema::SchemaBuilder::build_from_ast()),
20/// except you write GraphQL syntax in your Rust file and the macro parses it as
21/// GraphQL for you.
22///
23/// Example usage:
24///
25/// ```rust
26/// use libgraphql::macros::graphql_schema;
27///
28/// let schema = graphql_schema! {
29///     type Query {
30///         // This field always resolves the currently-authenticated `User`.
31///         me: User,
32///     }
33///
34///     type User {
35///         firstName: String,
36///         lastName: String,
37///     }
38/// };
39///
40/// let user_type =
41///     schema.defined_types()
42///         .get("User")
43///         .unwrap()
44///         .as_object()
45///         .unwrap();
46///
47/// assert_eq!(user_type.name(), "User");
48/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
49/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
50/// assert_eq!(user_type.fields().get("doesntExist").is_some(), false);
51/// ```
52///
53/// ## **⚠️ NOTE:**
54///
55/// Due to limitations downstream of how Rust macros tokenize syntax, there
56/// are a few inline GraphQL syntax edge-cases that are not supported by this
57/// macro:
58///
59///   1) `#` cannot be used to specify GraphQL comments. Instead, you can use
60///      Rust's `//` or `/*` comment syntax.
61///
62///      So for example, this won't compile:
63///
64///      ```rust,compile_fail
65///      let schema = graphql_schema! {
66///        type Query {
67///          me: User,
68///        }
69///
70///        ## Represents a user in the system.
71///        type User {
72///          firstName: String,
73///          lastName: String,
74///        }
75///      };
76///      ```
77///
78///      But you can use rust's `//` and `/*` comment syntax instead:
79///      ```rust
80///      # use libgraphql::macros::graphql_schema;
81///      let schema = graphql_schema! {
82///        type Query {
83///          me: User,
84///        }
85///
86///        // Represents a user in the system.
87///        type User {
88///          /* The user's first name. */
89///          firstName: String,
90///
91///          /* The user's last name. */
92///          lastName: String,
93///        }
94///      };
95///      ```
96///
97///   2) Block-quoted strings (`"""`) *are* supported, but if you ever need to
98///      nest a quoted string of any kind /within/ a block-quoted string,
99///      you'll need to use Rust's `r#""#` "raw string" syntax instead.
100///
101///      So for example, this won't compile:
102///      ```rust,compile_fail
103///      let schema = graphql_schema! {
104///        type Query {
105///          me: User,
106///        }
107///
108///         type User {
109///           """
110///           The user's "primary" address.
111///           """
112///           address: String,
113///         }
114///      };
115///      ```
116///
117///      But the workaround is to use raw-string syntax instead:
118///      ```rust
119///      # use libgraphql::macros::graphql_schema;
120///      let schema = graphql_schema! {
121///        type Query {
122///          me: User,
123///        }
124///
125///        type User {
126///          r#"
127///          The user's "primary" address.
128///          "#
129///          address: String,
130///        }
131///      };
132///        ```
133#[proc_macro]
134pub fn graphql_schema(
135    input: proc_macro::TokenStream,
136) -> proc_macro::TokenStream {
137    GraphQLSchemaTokenConsumer::new(input).into()
138}
139
140/// Evaluates to a [`Schema`](libgraphql_core::schema::Schema) object given a literal
141/// Rust `str` containing GraphQL document text that represents a GraphQL
142/// schema.
143///
144/// This macro is effectively a compile-time version of
145/// [`SchemaBuilder::build_from_str()`](libgraphql_core::schema::SchemaBuilder::build_from_str()).
146///
147/// Example usage:
148///
149/// ```rust
150/// use libgraphql::macros::graphql_schema_from_str;
151///
152/// let schema = graphql_schema_from_str!(r#"
153///     type Query {
154///         me: User,
155///
156///     }
157///
158///     type User {
159///         firstName: String,
160///         lastName: String,
161///     }
162/// "#r);
163///
164/// let user_type =
165///     schema.defined_types()
166///         .get("User")
167///         .unwrap()
168///         .as_object()
169///         .unwrap();
170///
171/// assert_eq!(user_type.name(), "User");
172/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
173/// assert_eq!(user_type.fields().get("firstName").is_some(), true);
174/// assert_eq!(user_type.fields().get("doesntExist").is_some(), false);
175/// ```
176#[proc_macro]
177pub fn graphql_schema_from_str(
178    input: proc_macro::TokenStream,
179) -> proc_macro::TokenStream {
180    GraphQLSchemaFromStrTokenConsumer::new(input).into()
181}