Skip to content

Commit 35b804c

Browse files
authored
Decouple object safe part from GraphQLType traits (#685)
- add object safe GraphQLValue, GraphQLValueAsync and GraphQLSubscriptionValue traits containing methods for value resolution - refactor GraphQLType, GraphQLTypeAsync and GraphQLSubscriptionType traits to register and provide GraphQL type information only
1 parent ed6b257 commit 35b804c

File tree

26 files changed

+1125
-525
lines changed

26 files changed

+1125
-525
lines changed

integration_tests/juniper_tests/src/codegen/derive_input_object.rs

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use fnv::FnvHashMap;
22

33
use juniper::{
4-
self, DefaultScalarValue, FromInputValue, GraphQLInputObject, GraphQLType, InputValue,
4+
DefaultScalarValue, FromInputValue, GraphQLInputObject, GraphQLType, GraphQLValue, InputValue,
55
ToInputValue,
66
};
77

@@ -63,9 +63,6 @@ impl<'a> ToInputValue for &'a Fake {
6363
}
6464

6565
impl<'a> GraphQLType<DefaultScalarValue> for &'a Fake {
66-
type Context = ();
67-
type TypeInfo = ();
68-
6966
fn name(_: &()) -> Option<&'static str> {
7067
None
7168
}
@@ -85,6 +82,15 @@ impl<'a> GraphQLType<DefaultScalarValue> for &'a Fake {
8582
}
8683
}
8784

85+
impl<'a> GraphQLValue<DefaultScalarValue> for &'a Fake {
86+
type Context = ();
87+
type TypeInfo = ();
88+
89+
fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
90+
<Self as GraphQLType>::name(info)
91+
}
92+
}
93+
8894
#[derive(GraphQLInputObject, Debug, PartialEq)]
8995
#[graphql(scalar = DefaultScalarValue)]
9096
struct WithLifetime<'a> {

juniper/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272

7373
## Breaking Changes
7474

75+
- `GraphQLType` trait was split into 2 traits: ([#685](https://github.com/graphql-rust/juniper/pull/685))
76+
- object safe `GraphQLValue` trait containing resolving logic;
77+
- static `GraphQLType` trait containing GraphQL type information.
78+
7579
- `juniper::graphiql` has moved to `juniper::http::graphiql`.
7680
- `juniper::http::graphiql::graphiql_source()` now requires a second parameter for subscriptions.
7781

juniper/src/executor/mod.rs

+30-28
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ use crate::{
2222
},
2323
model::{RootNode, SchemaType, TypeType},
2424
},
25-
types::{base::GraphQLType, name::Name},
25+
types::{
26+
async_await::{GraphQLTypeAsync, GraphQLValueAsync},
27+
base::{GraphQLType, GraphQLValue},
28+
name::Name,
29+
subscriptions::{GraphQLSubscriptionType, GraphQLSubscriptionValue},
30+
},
2631
value::{DefaultScalarValue, ParseScalarValue, ScalarValue, Value},
2732
GraphQLError,
2833
};
@@ -244,7 +249,7 @@ impl<S> IntoFieldError<S> for FieldError<S> {
244249
#[doc(hidden)]
245250
pub trait IntoResolvable<'a, S, T, C>
246251
where
247-
T: GraphQLType<S>,
252+
T: GraphQLValue<S>,
248253
S: ScalarValue,
249254
{
250255
#[doc(hidden)]
@@ -253,7 +258,7 @@ where
253258

254259
impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for T
255260
where
256-
T: GraphQLType<S>,
261+
T: GraphQLValue<S>,
257262
S: ScalarValue,
258263
T::Context: FromContext<C>,
259264
{
@@ -265,7 +270,7 @@ where
265270
impl<'a, S, T, C, E: IntoFieldError<S>> IntoResolvable<'a, S, T, C> for Result<T, E>
266271
where
267272
S: ScalarValue,
268-
T: GraphQLType<S>,
273+
T: GraphQLValue<S>,
269274
T::Context: FromContext<C>,
270275
{
271276
fn into(self, ctx: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
@@ -277,7 +282,7 @@ where
277282
impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for (&'a T::Context, T)
278283
where
279284
S: ScalarValue,
280-
T: GraphQLType<S>,
285+
T: GraphQLValue<S>,
281286
{
282287
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
283288
Ok(Some(self))
@@ -287,7 +292,7 @@ where
287292
impl<'a, S, T, C> IntoResolvable<'a, S, Option<T>, C> for Option<(&'a T::Context, T)>
288293
where
289294
S: ScalarValue,
290-
T: GraphQLType<S>,
295+
T: GraphQLValue<S>,
291296
{
292297
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S> {
293298
Ok(self.map(|(ctx, v)| (ctx, Some(v))))
@@ -297,7 +302,7 @@ where
297302
impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for FieldResult<(&'a T::Context, T), S>
298303
where
299304
S: ScalarValue,
300-
T: GraphQLType<S>,
305+
T: GraphQLValue<S>,
301306
{
302307
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, T)>, S> {
303308
self.map(Some)
@@ -308,7 +313,7 @@ impl<'a, S, T, C> IntoResolvable<'a, S, Option<T>, C>
308313
for FieldResult<Option<(&'a T::Context, T)>, S>
309314
where
310315
S: ScalarValue,
311-
T: GraphQLType<S>,
316+
T: GraphQLValue<S>,
312317
{
313318
fn into(self, _: &'a C) -> FieldResult<Option<(&'a T::Context, Option<T>)>, S> {
314319
self.map(|o| o.map(|(ctx, v)| (ctx, Some(v))))
@@ -369,7 +374,7 @@ where
369374
'i: 'res,
370375
'v: 'res,
371376
'a: 'res,
372-
T: crate::GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
377+
T: GraphQLSubscriptionValue<S, Context = CtxT> + Send + Sync,
373378
T::TypeInfo: Send + Sync,
374379
CtxT: Send + Sync,
375380
S: Send + Sync,
@@ -393,7 +398,7 @@ where
393398
where
394399
't: 'res,
395400
'a: 'res,
396-
T: crate::GraphQLSubscriptionType<S, Context = CtxT>,
401+
T: GraphQLSubscriptionValue<S, Context = CtxT>,
397402
T::TypeInfo: Send + Sync,
398403
CtxT: Send + Sync,
399404
S: Send + Sync,
@@ -405,7 +410,7 @@ where
405410
pub fn resolve_with_ctx<NewCtxT, T>(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult<S>
406411
where
407412
NewCtxT: FromContext<CtxT>,
408-
T: GraphQLType<S, Context = NewCtxT> + ?Sized,
413+
T: GraphQLValue<S, Context = NewCtxT> + ?Sized,
409414
{
410415
self.replaced_context(<NewCtxT as FromContext<CtxT>>::from(self.context))
411416
.resolve(info, value)
@@ -414,15 +419,15 @@ where
414419
/// Resolve a single arbitrary value into an `ExecutionResult`
415420
pub fn resolve<T>(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult<S>
416421
where
417-
T: GraphQLType<S, Context = CtxT> + ?Sized,
422+
T: GraphQLValue<S, Context = CtxT> + ?Sized,
418423
{
419424
value.resolve(info, self.current_selection_set, self)
420425
}
421426

422427
/// Resolve a single arbitrary value into an `ExecutionResult`
423428
pub async fn resolve_async<T>(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult<S>
424429
where
425-
T: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync + ?Sized,
430+
T: GraphQLValueAsync<S, Context = CtxT> + Send + Sync + ?Sized,
426431
T::TypeInfo: Send + Sync,
427432
CtxT: Send + Sync,
428433
S: Send + Sync,
@@ -439,7 +444,7 @@ where
439444
value: &T,
440445
) -> ExecutionResult<S>
441446
where
442-
T: crate::GraphQLTypeAsync<S, Context = NewCtxT> + Send + Sync,
447+
T: GraphQLValueAsync<S, Context = NewCtxT> + Send + Sync,
443448
T::TypeInfo: Send + Sync,
444449
S: Send + Sync,
445450
NewCtxT: FromContext<CtxT> + Send + Sync,
@@ -453,23 +458,20 @@ where
453458
/// If the field fails to resolve, `null` will be returned.
454459
pub fn resolve_into_value<T>(&self, info: &T::TypeInfo, value: &T) -> Value<S>
455460
where
456-
T: GraphQLType<S, Context = CtxT>,
461+
T: GraphQLValue<S, Context = CtxT>,
457462
{
458-
match self.resolve(info, value) {
459-
Ok(v) => v,
460-
Err(e) => {
461-
self.push_error(e);
462-
Value::null()
463-
}
464-
}
463+
self.resolve(info, value).unwrap_or_else(|e| {
464+
self.push_error(e);
465+
Value::null()
466+
})
465467
}
466468

467469
/// Resolve a single arbitrary value into a return value
468470
///
469471
/// If the field fails to resolve, `null` will be returned.
470472
pub async fn resolve_into_value_async<T>(&self, info: &T::TypeInfo, value: &T) -> Value<S>
471473
where
472-
T: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync + ?Sized,
474+
T: GraphQLValueAsync<S, Context = CtxT> + Send + Sync + ?Sized,
473475
T::TypeInfo: Send + Sync,
474476
CtxT: Send + Sync,
475477
S: Send + Sync,
@@ -851,9 +853,9 @@ pub async fn execute_validated_query_async<'a, 'b, QueryT, MutationT, Subscripti
851853
) -> Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>
852854
where
853855
S: ScalarValue + Send + Sync,
854-
QueryT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
856+
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
855857
QueryT::TypeInfo: Send + Sync,
856-
MutationT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
858+
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
857859
MutationT::TypeInfo: Send + Sync,
858860
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync,
859861
SubscriptionT::TypeInfo: Send + Sync,
@@ -998,11 +1000,11 @@ where
9981000
'd: 'r,
9991001
'op: 'd,
10001002
S: ScalarValue + Send + Sync,
1001-
QueryT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
1003+
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
10021004
QueryT::TypeInfo: Send + Sync,
1003-
MutationT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
1005+
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
10041006
MutationT::TypeInfo: Send + Sync,
1005-
SubscriptionT: crate::GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
1007+
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
10061008
SubscriptionT::TypeInfo: Send + Sync,
10071009
CtxT: Send + Sync + 'r,
10081010
{

juniper/src/http/mod.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ where
106106
) -> GraphQLResponse<'a, S>
107107
where
108108
S: ScalarValue + Send + Sync,
109-
QueryT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
109+
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
110110
QueryT::TypeInfo: Send + Sync,
111-
MutationT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
111+
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
112112
MutationT::TypeInfo: Send + Sync,
113113
SubscriptionT: GraphQLType<S, Context = CtxT> + Send + Sync,
114114
SubscriptionT::TypeInfo: Send + Sync,
@@ -259,13 +259,13 @@ where
259259
/// This is a simple wrapper around the `execute_sync` function exposed in GraphQLRequest.
260260
pub fn execute_sync<'a, CtxT, QueryT, MutationT, SubscriptionT>(
261261
&'a self,
262-
root_node: &'a crate::RootNode<QueryT, MutationT, SubscriptionT, S>,
262+
root_node: &'a RootNode<QueryT, MutationT, SubscriptionT, S>,
263263
context: &CtxT,
264264
) -> GraphQLBatchResponse<'a, S>
265265
where
266-
QueryT: crate::GraphQLType<S, Context = CtxT>,
267-
MutationT: crate::GraphQLType<S, Context = CtxT>,
268-
SubscriptionT: crate::GraphQLType<S, Context = CtxT>,
266+
QueryT: GraphQLType<S, Context = CtxT>,
267+
MutationT: GraphQLType<S, Context = CtxT>,
268+
SubscriptionT: GraphQLType<S, Context = CtxT>,
269269
{
270270
match *self {
271271
Self::Single(ref req) => {
@@ -285,15 +285,15 @@ where
285285
/// GraphQLRequest
286286
pub async fn execute<'a, CtxT, QueryT, MutationT, SubscriptionT>(
287287
&'a self,
288-
root_node: &'a crate::RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
288+
root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>,
289289
context: &'a CtxT,
290290
) -> GraphQLBatchResponse<'a, S>
291291
where
292-
QueryT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
292+
QueryT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
293293
QueryT::TypeInfo: Send + Sync,
294-
MutationT: crate::GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
294+
MutationT: GraphQLTypeAsync<S, Context = CtxT> + Send + Sync,
295295
MutationT::TypeInfo: Send + Sync,
296-
SubscriptionT: crate::GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
296+
SubscriptionT: GraphQLSubscriptionType<S, Context = CtxT> + Send + Sync,
297297
SubscriptionT::TypeInfo: Send + Sync,
298298
CtxT: Send + Sync,
299299
S: Send + Sync,

juniper/src/integrations/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! Provides GraphQLType implementations for some external types
2+
23
#[doc(hidden)]
34
pub mod serde;
45

juniper/src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -185,11 +185,14 @@ pub use crate::{
185185
model::{RootNode, SchemaType},
186186
},
187187
types::{
188-
async_await::GraphQLTypeAsync,
189-
base::{Arguments, GraphQLType, TypeKind},
188+
async_await::{GraphQLTypeAsync, GraphQLValueAsync},
189+
base::{Arguments, GraphQLType, GraphQLValue, TypeKind},
190190
marker::{self, GraphQLUnion},
191191
scalars::{EmptyMutation, EmptySubscription, ID},
192-
subscriptions::{GraphQLSubscriptionType, SubscriptionConnection, SubscriptionCoordinator},
192+
subscriptions::{
193+
GraphQLSubscriptionType, GraphQLSubscriptionValue, SubscriptionConnection,
194+
SubscriptionCoordinator,
195+
},
193196
},
194197
validation::RuleError,
195198
value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value},

juniper/src/macros/interface.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,7 @@ macro_rules! graphql_interface {
134134
) => {
135135
$crate::__juniper_impl_trait!(
136136
impl<$($scalar)* $(, $lifetimes)* > GraphQLType for $name {
137-
type Context = $ctx;
138-
type TypeInfo = ();
139-
140-
fn name(_ : &Self::TypeInfo) -> Option<&str> {
137+
fn name(_ : &Self::TypeInfo) -> Option<&'static str> {
141138
Some($($outname)*)
142139
}
143140

@@ -178,7 +175,17 @@ macro_rules! graphql_interface {
178175
$(.description($desciption))*
179176
.into_meta()
180177
}
178+
}
179+
);
181180

181+
$crate::__juniper_impl_trait!(
182+
impl<$($scalar)* $(, $lifetimes)* > GraphQLValue for $name {
183+
type Context = $ctx;
184+
type TypeInfo = ();
185+
186+
fn type_name(&self, _ : &Self::TypeInfo) -> Option<&'static str> {
187+
Some($($outname)*)
188+
}
182189

183190
#[allow(unused_variables)]
184191
fn resolve_field(

juniper/src/macros/subscription_helpers.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
use futures::Stream;
77

8-
use crate::{FieldError, GraphQLType, ScalarValue};
8+
use crate::{FieldError, GraphQLValue, ScalarValue};
99

1010
/// Trait for converting `T` to `Ok(T)` if T is not Result.
1111
/// This is useful in subscription macros when user can provide type alias for
@@ -50,7 +50,7 @@ pub struct ResultStreamItem;
5050
pub struct ResultStreamResult;
5151

5252
/// This trait is used in `juniper::graphql_subscription` macro to get stream's
53-
/// item type that implements `GraphQLType` from type alias provided
53+
/// item type that implements `GraphQLValue` from type alias provided
5454
/// by user.
5555
pub trait ExtractTypeFromStream<T, S>
5656
where
@@ -59,13 +59,13 @@ where
5959
/// Stream's return Value that will be returned if
6060
/// no errors occured. Is used to determine field type in
6161
/// `#[juniper::graphql_subscription]`
62-
type Item: GraphQLType<S>;
62+
type Item: GraphQLValue<S>;
6363
}
6464

6565
impl<T, I, S> ExtractTypeFromStream<StreamItem, S> for T
6666
where
6767
T: futures::Stream<Item = I>,
68-
I: GraphQLType<S>,
68+
I: GraphQLValue<S>,
6969
S: ScalarValue,
7070
{
7171
type Item = I;
@@ -74,7 +74,7 @@ where
7474
impl<Ty, T, E, S> ExtractTypeFromStream<StreamResult, S> for Ty
7575
where
7676
Ty: futures::Stream<Item = Result<T, E>>,
77-
T: GraphQLType<S>,
77+
T: GraphQLValue<S>,
7878
S: ScalarValue,
7979
{
8080
type Item = T;
@@ -83,7 +83,7 @@ where
8383
impl<T, I, E, S> ExtractTypeFromStream<ResultStreamItem, S> for Result<T, E>
8484
where
8585
T: futures::Stream<Item = I>,
86-
I: GraphQLType<S>,
86+
I: GraphQLValue<S>,
8787
S: ScalarValue,
8888
{
8989
type Item = I;
@@ -92,7 +92,7 @@ where
9292
impl<T, E, I, ER, S> ExtractTypeFromStream<ResultStreamResult, S> for Result<T, E>
9393
where
9494
T: futures::Stream<Item = Result<I, ER>>,
95-
I: GraphQLType<S>,
95+
I: GraphQLValue<S>,
9696
S: ScalarValue,
9797
{
9898
type Item = I;

0 commit comments

Comments
 (0)