1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
//! This crate supplies custom derive implementations for the
//! [juniper](https://github.com/graphql-rust/juniper) crate.
//!
//! You should not depend on juniper_codegen directly.
//! You only need the `juniper` crate.

#![doc(html_root_url = "https://docs.rs/juniper_codegen/0.12.0")]
#![recursion_limit = "1024"]

extern crate proc_macro;

mod derive_enum;
mod derive_input_object;
mod derive_object;
mod derive_scalar_value;
mod impl_object;
mod util;

use proc_macro::TokenStream;

#[proc_macro_derive(GraphQLEnum, attributes(graphql))]
pub fn derive_enum(input: TokenStream) -> TokenStream {
    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
    let gen = derive_enum::impl_enum(&ast, false);
    gen.into()
}

#[proc_macro_derive(GraphQLEnumInternal, attributes(graphql))]
#[doc(hidden)]
pub fn derive_enum_internal(input: TokenStream) -> TokenStream {
    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
    let gen = derive_enum::impl_enum(&ast, true);
    gen.into()
}

#[proc_macro_derive(GraphQLInputObject, attributes(graphql))]
pub fn derive_input_object(input: TokenStream) -> TokenStream {
    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
    let gen = derive_input_object::impl_input_object(&ast, false);
    gen.into()
}

#[proc_macro_derive(GraphQLInputObjectInternal, attributes(graphql))]
#[doc(hidden)]
pub fn derive_input_object_internal(input: TokenStream) -> TokenStream {
    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
    let gen = derive_input_object::impl_input_object(&ast, true);
    gen.into()
}

#[proc_macro_derive(GraphQLObject, attributes(graphql))]
pub fn derive_object(input: TokenStream) -> TokenStream {
    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
    let gen = derive_object::build_derive_object(ast, false);
    gen.into()
}

#[proc_macro_derive(GraphQLScalarValue)]
pub fn derive_scalar_value(input: TokenStream) -> TokenStream {
    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
    let gen = derive_scalar_value::impl_scalar_value(&ast, false);
    gen.into()
}

#[deprecated(note = "ScalarValue has been renamed to GraphQLScalarValue")]
#[proc_macro_derive(ScalarValue)]
pub fn derive_scalar_value_deprecated(input: TokenStream) -> TokenStream {
    derive_scalar_value(input)
}

#[proc_macro_derive(GraphQLScalarValueInternal)]
#[doc(hidden)]
pub fn derive_scalar_value_internal(input: TokenStream) -> TokenStream {
    let ast = syn::parse::<syn::DeriveInput>(input).unwrap();
    let gen = derive_scalar_value::impl_scalar_value(&ast, true);
    gen.into()
}

/**
The `object` proc macro is the primary way of defining GraphQL resolvers
that can not be implemented with the GraphQLObject derive.

It enables you to write GraphQL field resolvers for a type by declaring a
regular Rust `impl` block. Under the hood, the procedural macro implements
the GraphQLType trait.

`object` comes with many features that allow customization of
your fields, all of which are detailed below.

### Getting Started

This simple example will show you the most basic use of `object`.
More advanced use cases are introduced step by step.

```
// So we can declare it as a plain struct without any members.
struct Query;

// We prefix the impl Block with the procedural macro.
#[juniper::object]
impl Query {

    // A **warning**: only GraphQL fields can be specified in this impl block.
    // If you want to define normal methods on the struct,
    // you have to do so in a separate, normal `impl` block.


    // This defines a simple, static field which does not require any context.
    // You can return any value that implements the `GraphQLType` trait.
    // This trait is implemented for:
    //  - basic scalar types like bool, &str, String, i32, f64
    //  - GraphQL compatible wrappers like Option<_>, Vec<_>.
    //  - types which use the `#derive[juniper::GraphQLObject]`
    //  - `object` structs.
    //
    // An important note regarding naming:
    // By default, field names will be converted to camel case.
    // For your GraphQL queries, the field will be available as `apiVersion`.
    //
    // You can also manually customize the field name if required. (See below)
    fn api_version() -> &'static str {
        "0.1"
    }

    // This field takes two arguments.
    // GraphQL arguments are just regular function parameters.
    // **Note**: in Juniper, arguments are non-nullable by default.
    //           for optional arguments, you have to specify them with Option<T>.
    fn add(a: f64, b: f64, c: Option<f64>) -> f64 {
        a + b + c.unwrap_or(0.0)
    }
}
```

## Accessing self

```
struct Person {
    first_name: String,
    last_name: String,
}

impl Person {
    // The full name method is useful outside of GraphQL,
    // so we define it as a normal method.
    fn build_full_name(&self) -> String {
        format!("{} {}", self.first_name, self.last_name)
    }
}

#[juniper::object]
impl Person {
    fn first_name(&self) -> &str {
        &self.first_name
    }

    fn last_name(&self) -> &str {
        &self.last_name
    }

    fn full_name(&self) -> String {
        self.build_full_name()
    }
}
```

## Context (+ Executor)

You can specify a context that will be available across
all your resolvers during query execution.

The Context can be injected into your resolvers by just
specifying an argument with the same type as the context
(but as a reference).

```

# #[derive(juniper::GraphQLObject)] struct User { id: i32 }
# struct DbPool;
# impl DbPool { fn user(&self, id: i32) -> Option<User> { unimplemented!() } }

struct Context {
    db: DbPool,
}

// Mark our struct for juniper.
impl juniper::Context for Context {}

struct Query;

#[juniper::object(
    // Here we specify the context type for this object.
    Context = Context,
)]
impl Query {
    // Context is injected by specifying a argument
    // as a reference to the Context.
    fn user(context: &Context, id: i32) -> Option<User> {
        context.db.user(id)
    }

    // You can also gain access to the executor, which
    // allows you to do look aheads.
    fn with_executor(executor: &Executor) -> bool {
        let info = executor.look_ahead();
        // ...
        true
    }
}

```

## Customization (Documentation, Renaming, ...)

```
struct InternalQuery;

// Doc comments can be used to specify graphql documentation.
/// GRAPHQL DOCUMENTATION.
/// More info for GraphQL users....
#[juniper::object(
    // You can rename the type for GraphQL by specifying the name here.
    name = "Query",
    // You can also specify a description here.
    // If present, doc comments will be ignored.
    description = "...",
)]
impl InternalQuery {
    // Documentation doc comments also work on fields.
    /// GraphQL description...
    fn field_with_description() -> bool { true }

    // Fields can also be customized with the #[graphql] attribute.
    #[graphql(
        // overwrite the public name
        name = "actualFieldName",
        // Can be used instead of doc comments.
        description = "field description",
    )]
    fn internal_name() -> bool { true }

    // Fields can be deprecated too.
    #[graphql(
        deprecated = "deprecatin info...",
        // Note: just "deprecated," without a description works too.
    )]
    fn deprecated_field_simple() -> bool { true }


    // Customizing field arguments is a little awkward right now.
    // This will improve once [RFC 2564](https://github.com/rust-lang/rust/issues/60406)
    // is implemented, which will allow attributes on function parameters.

    #[graphql(
        arguments(
            arg1(
                // You can specify default values.
                // A default can be any valid expression that yields the right type.
                default = true,
                description = "Argument description....",
            ),
            arg2(
                default = false,
                description = "arg2 description...",
            ),
        ),
    )]
    fn args(arg1: bool, arg2: bool) -> bool {
        arg1 && arg2
    }
}
```

## Lifetimes, Generics and custom Scalars

Lifetimes work just like you'd expect.


```
struct WithLifetime<'a> {
    value: &'a str,
}

#[juniper::object]
impl<'a> WithLifetime<'a> {
    fn value(&self) -> &str {
        self.value
    }
}

```

Juniper has support for custom scalars.
Mostly you will only need the default scalar type juniper::DefaultScalarValue.

You can easily specify a custom scalar though.


```

# type MyCustomScalar = juniper::DefaultScalarValue;

struct Query;

#[juniper::object(
    Scalar = MyCustomScalar,
)]
impl Query {
    // ...
}
```

*/
#[proc_macro_attribute]
pub fn object(args: TokenStream, input: TokenStream) -> TokenStream {
    let gen = impl_object::build_object(args, input, false);
    gen.into()
}

/// A proc macro for defining a GraphQL object.
#[doc(hidden)]
#[proc_macro_attribute]
pub fn object_internal(args: TokenStream, input: TokenStream) -> TokenStream {
    let gen = impl_object::build_object(args, input, true);
    gen.into()
}