11use std:: { borrow:: Cow , fmt} ;
22
33use fnv:: FnvHashMap ;
4+
45#[ cfg( feature = "schema-language" ) ]
56use graphql_parser:: schema:: Document ;
67
@@ -53,7 +54,7 @@ pub struct SchemaType<'a, S> {
5354 pub ( crate ) query_type_name : String ,
5455 pub ( crate ) mutation_type_name : Option < String > ,
5556 pub ( crate ) subscription_type_name : Option < String > ,
56- directives : FnvHashMap < String , DirectiveType < ' a , S > > ,
57+ pub ( crate ) directives : FnvHashMap < String , DirectiveType < ' a , S > > ,
5758}
5859
5960impl < S > Context for SchemaType < ' _ , S > { }
@@ -66,33 +67,51 @@ pub enum TypeType<'a, S: 'a> {
6667}
6768
6869#[ derive( Debug ) ]
70+ /// Represents a graphql directive
6971pub struct DirectiveType < ' a , S > {
72+ /// required a unique name per schema
7073 pub name : String ,
74+ /// optional a description
7175 pub description : Option < String > ,
76+ /// required atleast a location
7277 pub locations : Vec < DirectiveLocation > ,
78+ /// Optional arguments
7379 pub arguments : Vec < Argument < ' a , S > > ,
80+ /// Allow repeating a directive
7481 pub is_repeatable : bool ,
7582}
7683
7784#[ derive( Clone , PartialEq , Eq , Debug , GraphQLEnum ) ]
7885#[ graphql( name = "__DirectiveLocation" , internal) ]
86+ /// Describes the different allowed locations of a directive
7987pub enum DirectiveLocation {
88+ /// directive for query
8089 Query ,
90+ /// directive for Mutation
8191 Mutation ,
92+ /// directive for Subscription
8293 Subscription ,
94+ /// directive for Field
8395 Field ,
96+ /// directive for Scalar
8497 Scalar ,
8598 #[ graphql( name = "FRAGMENT_DEFINITION" ) ]
99+ /// directive for FragmentDefinition
86100 FragmentDefinition ,
87101 #[ graphql( name = "FIELD_DEFINITION" ) ]
102+ /// directive for FieldDefinition
88103 FieldDefinition ,
89104 #[ graphql( name = "VARIABLE_DEFINITION" ) ]
105+ /// directive for VariableDefinition
90106 VariableDefinition ,
91107 #[ graphql( name = "FRAGMENT_SPREAD" ) ]
108+ /// directive for FragmentSpread
92109 FragmentSpread ,
93110 #[ graphql( name = "INLINE_FRAGMENT" ) ]
111+ /// directive for InlineFragment
94112 InlineFragment ,
95113 #[ graphql( name = "ENUM_VALUE" ) ]
114+ /// directive for Enum
96115 EnumValue ,
97116}
98117
@@ -104,7 +123,7 @@ where
104123 SubscriptionT : GraphQLType < DefaultScalarValue , TypeInfo = ( ) > ,
105124{
106125 /// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
107- /// parametrizing it with a [`DefaultScalarValue`].
126+ /// parametrizing it with a [`DefaultScalarValue`] .
108127 pub fn new ( query : QueryT , mutation : MutationT , subscription : SubscriptionT ) -> Self {
109128 Self :: new_with_info ( query, mutation, subscription, ( ) , ( ) , ( ) )
110129 }
@@ -118,14 +137,67 @@ where
118137 SubscriptionT : GraphQLType < S , TypeInfo = ( ) > ,
119138{
120139 /// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
121- /// parametrizing it with the provided [`ScalarValue`].
140+ /// parametrized it with the provided [`ScalarValue`].
122141 pub fn new_with_scalar_value (
123142 query : QueryT ,
124143 mutation : MutationT ,
125144 subscription : SubscriptionT ,
126145 ) -> Self {
127146 RootNode :: new_with_info ( query, mutation, subscription, ( ) , ( ) , ( ) )
128147 }
148+
149+ /// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
150+ /// parametrized it with a [`ScalarValue`] and directives
151+ /// ```rust
152+ /// use juniper::{
153+ /// graphql_object, graphql_vars, EmptyMutation, EmptySubscription, GraphQLError,
154+ /// RootNode, DirectiveLocation , DirectiveType
155+ /// };
156+ ///
157+ /// struct Query{}
158+ ///
159+ /// #[graphql_object]
160+ /// impl Query {
161+ /// pub fn hello() -> String {
162+ /// "Hello".to_string()
163+ /// }
164+ /// }
165+ ///
166+ /// type Schema = RootNode<'static, Query, EmptyMutation, EmptySubscription>;
167+ ///
168+ /// let schema = Schema::new_with_directives(Query {}, EmptyMutation::new(), EmptySubscription::new()
169+ /// ,vec![ DirectiveType::new("my_directive", &[DirectiveLocation::Query] , &[] , false )]);
170+ ///
171+ /// let query = "query @my_directive { hello }";
172+ ///
173+ /// match juniper::execute_sync(query, None, &schema, &graphql_vars! {}, &()) {
174+ /// Err(GraphQLError::ValidationError(errs)) => { panic!("should not give an error"); }
175+ /// res => {}
176+ /// }
177+ ///
178+ /// let query = "query @non_existing_directive { hello }";
179+ ///
180+ /// match juniper::execute_sync(query, None, &schema, &graphql_vars! {}, &()) {
181+ /// Err(GraphQLError::ValidationError(errs)) => { }
182+ /// res => { panic!("should give an error"); }
183+ /// }
184+ /// ```
185+ pub fn new_with_directives (
186+ query : QueryT ,
187+ mutation : MutationT ,
188+ subscription : SubscriptionT ,
189+ custom_directives : Vec < DirectiveType < ' a , S > > ,
190+ ) -> Self {
191+ Self :: new_with_directives_and_info (
192+ query,
193+ mutation,
194+ subscription,
195+ custom_directives,
196+ ( ) ,
197+ ( ) ,
198+ ( ) ,
199+ )
200+ }
129201}
130202
131203impl < ' a , S , QueryT , MutationT , SubscriptionT > RootNode < ' a , QueryT , MutationT , SubscriptionT , S >
@@ -162,6 +234,34 @@ where
162234 }
163235 }
164236
237+ /// Construct a new root node with default meta types
238+ /// and with custom directives
239+ pub fn new_with_directives_and_info (
240+ query_obj : QueryT ,
241+ mutation_obj : MutationT ,
242+ subscription_obj : SubscriptionT ,
243+ custom_directives : Vec < DirectiveType < ' a , S > > ,
244+ query_info : QueryT :: TypeInfo ,
245+ mutation_info : MutationT :: TypeInfo ,
246+ subscription_info : SubscriptionT :: TypeInfo ,
247+ ) -> Self {
248+ Self {
249+ query_type : query_obj,
250+ mutation_type : mutation_obj,
251+ subscription_type : subscription_obj,
252+ schema : SchemaType :: new_with_directives :: < QueryT , MutationT , SubscriptionT > (
253+ & query_info,
254+ & mutation_info,
255+ & subscription_info,
256+ custom_directives. into ( ) ,
257+ ) ,
258+ query_info,
259+ mutation_info,
260+ subscription_info,
261+ introspection_disabled : false ,
262+ }
263+ }
264+
165265 /// Disables introspection for this [`RootNode`], making it to return a [`FieldError`] whenever
166266 /// its `__schema` or `__type` field is resolved.
167267 ///
@@ -257,12 +357,29 @@ where
257357}
258358
259359impl < ' a , S > SchemaType < ' a , S > {
360+
260361 /// Create a new schema.
261362 pub fn new < QueryT , MutationT , SubscriptionT > (
262363 query_info : & QueryT :: TypeInfo ,
263364 mutation_info : & MutationT :: TypeInfo ,
264365 subscription_info : & SubscriptionT :: TypeInfo ,
265366 ) -> Self
367+ where
368+ S : ScalarValue + ' a ,
369+ QueryT : GraphQLType < S > ,
370+ MutationT : GraphQLType < S > ,
371+ SubscriptionT : GraphQLType < S > ,
372+ {
373+ Self :: new_with_directives :: < QueryT , MutationT , SubscriptionT > ( query_info, mutation_info, subscription_info, None )
374+ }
375+
376+ /// Create a new schema with custom directives
377+ pub fn new_with_directives < QueryT , MutationT , SubscriptionT > (
378+ query_info : & QueryT :: TypeInfo ,
379+ mutation_info : & MutationT :: TypeInfo ,
380+ subscription_info : & SubscriptionT :: TypeInfo ,
381+ custom_directives : Option < Vec < DirectiveType < ' a , S > > > ,
382+ ) -> Self
266383 where
267384 S : ScalarValue + ' a ,
268385 QueryT : GraphQLType < S > ,
@@ -298,6 +415,12 @@ impl<'a, S> SchemaType<'a, S> {
298415 DirectiveType :: new_specified_by ( & mut registry) ,
299416 ) ;
300417
418+ if let Some ( custom_directives) = custom_directives {
419+ for custom_directive in custom_directives. into_iter ( ) {
420+ directives. insert ( custom_directive. name . clone ( ) , custom_directive) ;
421+ }
422+ }
423+
301424 let mut meta_fields = vec ! [
302425 registry. field:: <SchemaType <S >>( "__schema" , & ( ) ) ,
303426 registry
@@ -585,6 +708,7 @@ impl<'a, S> DirectiveType<'a, S>
585708where
586709 S : ScalarValue + ' a ,
587710{
711+ /// Create a new default directive
588712 pub fn new (
589713 name : & str ,
590714 locations : & [ DirectiveLocation ] ,
@@ -600,6 +724,15 @@ where
600724 }
601725 }
602726
727+ /// skip,include,deprecated,specifiedBy are standard graphQL directive
728+ /// wiil not show up in generated scheme
729+ pub fn is_builtin ( & self ) -> bool {
730+ match self . name . as_str ( ) {
731+ "skip" | "include" | "deprecated" | "specifiedBy" => true ,
732+ _ => false ,
733+ }
734+ }
735+
603736 fn new_skip ( registry : & mut Registry < ' a , S > ) -> DirectiveType < ' a , S >
604737 where
605738 S : ScalarValue ,
@@ -659,6 +792,7 @@ where
659792 )
660793 }
661794
795+ /// Set description of directive
662796 pub fn description ( mut self , description : & str ) -> DirectiveType < ' a , S > {
663797 self . description = Some ( description. into ( ) ) ;
664798 self
0 commit comments