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}