Skip to content

Commit 919c6c8

Browse files
modified: juniper/src/lib.rs
modified: juniper/src/schema/model.rs# modified: juniper/src/schema/translate/graphql_parser.rs Added new function to create a schema with custom directives Added doctest Added directives to be included in the schema output
1 parent 8b85532 commit 919c6c8

File tree

3 files changed

+193
-4
lines changed

3 files changed

+193
-4
lines changed

juniper/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ pub use crate::{
8888
parser::{ParseError, ScalarToken, Span, Spanning},
8989
schema::{
9090
meta,
91-
model::{RootNode, SchemaType},
91+
model::{RootNode, SchemaType, DirectiveType, DirectiveLocation},
9292
},
9393
types::{
9494
async_await::{GraphQLTypeAsync, GraphQLValueAsync},

juniper/src/schema/model.rs

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::ptr;
33
use arcstr::ArcStr;
44
use derive_more::with_trait::Display;
55
use fnv::FnvHashMap;
6+
67
#[cfg(feature = "schema-language")]
78
use graphql_parser::schema::Document;
89

@@ -54,7 +55,7 @@ where
5455
SubscriptionT: GraphQLType<DefaultScalarValue, TypeInfo = ()>,
5556
{
5657
/// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
57-
/// parametrizing it with a [`DefaultScalarValue`].
58+
/// parametrizing it with a [`DefaultScalarValue`] .
5859
pub fn new(query: QueryT, mutation: MutationT, subscription: SubscriptionT) -> Self {
5960
Self::new_with_info(query, mutation, subscription, (), (), ())
6061
}
@@ -68,14 +69,67 @@ where
6869
SubscriptionT: GraphQLType<S, TypeInfo = ()>,
6970
{
7071
/// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
71-
/// parametrizing it with the provided [`ScalarValue`].
72+
/// parametrized it with the provided [`ScalarValue`].
7273
pub fn new_with_scalar_value(
7374
query: QueryT,
7475
mutation: MutationT,
7576
subscription: SubscriptionT,
7677
) -> Self {
7778
RootNode::new_with_info(query, mutation, subscription, (), (), ())
7879
}
80+
81+
/// Constructs a new [`RootNode`] from `query`, `mutation` and `subscription` nodes,
82+
/// parametrized it with a [`ScalarValue`] and directives
83+
/// ```rust
84+
/// use juniper::{
85+
/// graphql_object, graphql_vars, EmptyMutation, EmptySubscription, GraphQLError,
86+
/// RootNode, DirectiveLocation , DirectiveType
87+
/// };
88+
///
89+
/// struct Query{}
90+
///
91+
/// #[graphql_object]
92+
/// impl Query {
93+
/// pub fn hello() -> String {
94+
/// "Hello".to_string()
95+
/// }
96+
/// }
97+
///
98+
/// type Schema = RootNode<'static, Query, EmptyMutation, EmptySubscription>;
99+
///
100+
/// let schema = Schema::new_with_directives(Query {}, EmptyMutation::new(), EmptySubscription::new()
101+
/// ,vec![ DirectiveType::new("my_directive", &[DirectiveLocation::Query] , &[] , false )]);
102+
///
103+
/// let query = "query @my_directive { hello }";
104+
///
105+
/// match juniper::execute_sync(query, None, &schema, &graphql_vars! {}, &()) {
106+
/// Err(GraphQLError::ValidationError(errs)) => { panic!("should not give an error"); }
107+
/// res => {}
108+
/// }
109+
///
110+
/// let query = "query @non_existing_directive { hello }";
111+
///
112+
/// match juniper::execute_sync(query, None, &schema, &graphql_vars! {}, &()) {
113+
/// Err(GraphQLError::ValidationError(errs)) => { }
114+
/// res => { panic!("should give an error"); }
115+
/// }
116+
/// ```
117+
pub fn new_with_directives(
118+
query: QueryT,
119+
mutation: MutationT,
120+
subscription: SubscriptionT,
121+
custom_directives: Vec<DirectiveType<S>>,
122+
) -> Self {
123+
Self::new_with_directives_and_info(
124+
query,
125+
mutation,
126+
subscription,
127+
custom_directives,
128+
(),
129+
(),
130+
(),
131+
)
132+
}
79133
}
80134

81135
impl<S, QueryT, MutationT, SubscriptionT> RootNode<QueryT, MutationT, SubscriptionT, S>
@@ -112,6 +166,34 @@ where
112166
}
113167
}
114168

169+
/// Construct a new root node with default meta types
170+
/// and with custom directives
171+
pub fn new_with_directives_and_info(
172+
query_obj: QueryT,
173+
mutation_obj: MutationT,
174+
subscription_obj: SubscriptionT,
175+
custom_directives: Vec<DirectiveType<S>>,
176+
query_info: QueryT::TypeInfo,
177+
mutation_info: MutationT::TypeInfo,
178+
subscription_info: SubscriptionT::TypeInfo,
179+
) -> Self {
180+
Self {
181+
query_type: query_obj,
182+
mutation_type: mutation_obj,
183+
subscription_type: subscription_obj,
184+
schema: SchemaType::new_with_directives::<QueryT, MutationT, SubscriptionT>(
185+
&query_info,
186+
&mutation_info,
187+
&subscription_info,
188+
custom_directives.into(),
189+
),
190+
query_info,
191+
mutation_info,
192+
subscription_info,
193+
introspection_disabled: false,
194+
}
195+
}
196+
115197
/// Disables introspection for this [`RootNode`], making it to return a [`FieldError`] whenever
116198
/// its `__schema` or `__type` field is resolved.
117199
///
@@ -214,7 +296,7 @@ pub struct SchemaType<S> {
214296
pub(crate) query_type_name: String,
215297
pub(crate) mutation_type_name: Option<String>,
216298
pub(crate) subscription_type_name: Option<String>,
217-
directives: FnvHashMap<ArcStr, DirectiveType<S>>,
299+
pub(crate) directives: FnvHashMap<ArcStr, DirectiveType<S>>,
218300
}
219301

220302
impl<S> Context for SchemaType<S> {}
@@ -226,6 +308,22 @@ impl<S> SchemaType<S> {
226308
mutation_info: &MutationT::TypeInfo,
227309
subscription_info: &SubscriptionT::TypeInfo,
228310
) -> Self
311+
where
312+
S: ScalarValue,
313+
QueryT: GraphQLType<S>,
314+
MutationT: GraphQLType<S>,
315+
SubscriptionT: GraphQLType<S>,
316+
{
317+
Self::new_with_directives::<QueryT,MutationT,SubscriptionT>(query_info, mutation_info, subscription_info, None)
318+
}
319+
320+
/// Create a new schema with custom directives
321+
pub fn new_with_directives<QueryT, MutationT, SubscriptionT>(
322+
query_info: &QueryT::TypeInfo,
323+
mutation_info: &MutationT::TypeInfo,
324+
subscription_info: &SubscriptionT::TypeInfo,
325+
custom_directives: Option<Vec<DirectiveType<S>>>,
326+
) -> Self
229327
where
230328
S: ScalarValue,
231329
QueryT: GraphQLType<S>,
@@ -259,6 +357,12 @@ impl<S> SchemaType<S> {
259357
directives.insert(deprecated_directive.name.clone(), deprecated_directive);
260358
directives.insert(specified_by_directive.name.clone(), specified_by_directive);
261359

360+
if let Some(custom_directives) = custom_directives {
361+
for custom_directive in custom_directives.into_iter() {
362+
directives.insert(custom_directive.name.clone(), custom_directive);
363+
}
364+
}
365+
262366
let mut meta_fields = vec![
263367
registry.field::<SchemaType<S>>(arcstr::literal!("__schema"), &()),
264368
registry
@@ -601,6 +705,15 @@ impl<S> DirectiveType<S> {
601705
)
602706
}
603707

708+
/// skip,include,deprecated,specifiedBy are standard graphQL directive
709+
/// wiil not show up in generated scheme
710+
pub fn is_builtin(&self) -> bool {
711+
match self.name.as_str() {
712+
"skip" | "include" | "deprecated" | "specifiedBy" => true,
713+
_ => false,
714+
}
715+
}
716+
604717
fn new_skip(registry: &mut Registry<S>) -> Self
605718
where
606719
S: ScalarValue,

juniper/src/schema/translate/graphql_parser.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ use graphql_parser::{Pos, schema};
55
use crate::{
66
ast,
77
schema::{meta, model::SchemaType, translate::SchemaTranslator},
8+
};
9+
10+
use graphql_parser::{
11+
query::{Directive as ExternalDirective, Number as ExternalNumber, Type as ExternalType},
12+
schema::{
13+
Definition, DirectiveDefinition as ExternalDirectiveDefinition,
14+
DirectiveLocation as ExternalDirectiveLocation, Document, EnumType as ExternalEnum,
15+
EnumValue as ExternalEnumValue, Field as ExternalField,
16+
InputObjectType as ExternalInputObjectType, InputValue as ExternalInputValue,
17+
InterfaceType as ExternalInterfaceType, ObjectType as ExternalObjectType,
18+
ScalarType as ExternalScalarType, SchemaDefinition, Text,
19+
TypeDefinition as ExternalTypeDefinition, UnionType as ExternalUnionType,
20+
Value as ExternalValue,
21+
},
22+
};
23+
24+
use crate::{
25+
DirectiveLocation,
26+
ast::{InputValue, Type},
27+
schema::{
28+
meta::{Argument, DeprecationStatus, EnumValue, Field, MetaType},
29+
},
830
value::ScalarValue,
931
};
1032

@@ -58,11 +80,65 @@ where
5880
},
5981
));
6082

83+
let mut directives = input
84+
.directives
85+
.iter()
86+
.filter(|(_, directive)| !directive.is_builtin())
87+
.map(|(_, directive)| ExternalDirectiveDefinition::<T> {
88+
position: Pos::default(),
89+
description: directive.description.as_deref().map(Into::into),
90+
name: From::from(directive.name.as_str()),
91+
arguments: directive
92+
.arguments
93+
.iter()
94+
.map(GraphQLParserTranslator::translate_argument)
95+
.collect(),
96+
repeatable: directive.is_repeatable,
97+
locations: directive
98+
.locations
99+
.iter()
100+
.map(GraphQLParserTranslator::translate_location::<S,T>)
101+
.collect(),
102+
})
103+
.map(Definition::DirectiveDefinition)
104+
.collect();
105+
106+
doc.definitions.append(&mut directives);
107+
61108
doc
62109
}
63110
}
64111

65112
impl GraphQLParserTranslator {
113+
114+
fn translate_location<'a, S, T>(location: &DirectiveLocation) -> ExternalDirectiveLocation
115+
where
116+
S: ScalarValue,
117+
T: Text<'a>,
118+
{
119+
match location {
120+
DirectiveLocation::Query => ExternalDirectiveLocation::Query,
121+
DirectiveLocation::Mutation => ExternalDirectiveLocation::Mutation,
122+
DirectiveLocation::Subscription => ExternalDirectiveLocation::Subscription,
123+
DirectiveLocation::Field => ExternalDirectiveLocation::Field,
124+
DirectiveLocation::Scalar => ExternalDirectiveLocation::Scalar,
125+
DirectiveLocation::FragmentDefinition => ExternalDirectiveLocation::FragmentDefinition,
126+
DirectiveLocation::FieldDefinition => ExternalDirectiveLocation::FieldDefinition,
127+
DirectiveLocation::VariableDefinition => ExternalDirectiveLocation::VariableDefinition,
128+
DirectiveLocation::FragmentSpread => ExternalDirectiveLocation::FragmentSpread,
129+
DirectiveLocation::InlineFragment => ExternalDirectiveLocation::InlineFragment,
130+
DirectiveLocation::EnumValue => ExternalDirectiveLocation::EnumValue,
131+
DirectiveLocation::Schema => ExternalDirectiveLocation::Schema,
132+
DirectiveLocation::Object => ExternalDirectiveLocation::Object,
133+
DirectiveLocation::ArgumentDefinition => ExternalDirectiveLocation::ArgumentDefinition,
134+
DirectiveLocation::Interface => ExternalDirectiveLocation::Interface,
135+
DirectiveLocation::Union => ExternalDirectiveLocation::Union,
136+
DirectiveLocation::Enum => ExternalDirectiveLocation::Enum,
137+
DirectiveLocation::InputObject => ExternalDirectiveLocation::InputObject,
138+
DirectiveLocation::InputFieldDefinition => ExternalDirectiveLocation::InputFieldDefinition,
139+
}
140+
}
141+
66142
fn translate_argument<'a, S, T>(input: &'a meta::Argument<S>) -> schema::InputValue<'a, T>
67143
where
68144
S: ScalarValue,

0 commit comments

Comments
 (0)