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() }