diff --git a/integration_tests/juniper_tests/src/codegen/derive_input_object.rs b/integration_tests/juniper_tests/src/codegen/derive_input_object.rs index 664473cba..85604a847 100644 --- a/integration_tests/juniper_tests/src/codegen/derive_input_object.rs +++ b/integration_tests/juniper_tests/src/codegen/derive_input_object.rs @@ -1,7 +1,7 @@ use fnv::FnvHashMap; use juniper::{ - self, DefaultScalarValue, FromInputValue, GraphQLInputObject, GraphQLType, InputValue, + DefaultScalarValue, FromInputValue, GraphQLInputObject, GraphQLType, GraphQLValue, InputValue, ToInputValue, }; @@ -63,9 +63,6 @@ impl<'a> ToInputValue for &'a Fake { } impl<'a> GraphQLType for &'a Fake { - type Context = (); - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { None } @@ -85,6 +82,15 @@ impl<'a> GraphQLType for &'a Fake { } } +impl<'a> GraphQLValue for &'a Fake { + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + #[derive(GraphQLInputObject, Debug, PartialEq)] #[graphql(scalar = DefaultScalarValue)] struct WithLifetime<'a> { diff --git a/juniper/CHANGELOG.md b/juniper/CHANGELOG.md index 25e4cb267..496bbe0dc 100644 --- a/juniper/CHANGELOG.md +++ b/juniper/CHANGELOG.md @@ -72,6 +72,10 @@ ## Breaking Changes +- `GraphQLType` trait was split into 2 traits: ([#685](https://github.com/graphql-rust/juniper/pull/685)) + - object safe `GraphQLValue` trait containing resolving logic; + - static `GraphQLType` trait containing GraphQL type information. + - `juniper::graphiql` has moved to `juniper::http::graphiql`. - `juniper::http::graphiql::graphiql_source()` now requires a second parameter for subscriptions. diff --git a/juniper/src/executor/mod.rs b/juniper/src/executor/mod.rs index 998c7d50f..f3c25606d 100644 --- a/juniper/src/executor/mod.rs +++ b/juniper/src/executor/mod.rs @@ -22,7 +22,12 @@ use crate::{ }, model::{RootNode, SchemaType, TypeType}, }, - types::{base::GraphQLType, name::Name}, + types::{ + async_await::{GraphQLTypeAsync, GraphQLValueAsync}, + base::{GraphQLType, GraphQLValue}, + name::Name, + subscriptions::{GraphQLSubscriptionType, GraphQLSubscriptionValue}, + }, value::{DefaultScalarValue, ParseScalarValue, ScalarValue, Value}, GraphQLError, }; @@ -244,7 +249,7 @@ impl IntoFieldError for FieldError { #[doc(hidden)] pub trait IntoResolvable<'a, S, T, C> where - T: GraphQLType, + T: GraphQLValue, S: ScalarValue, { #[doc(hidden)] @@ -253,7 +258,7 @@ where impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for T where - T: GraphQLType, + T: GraphQLValue, S: ScalarValue, T::Context: FromContext, { @@ -265,7 +270,7 @@ where impl<'a, S, T, C, E: IntoFieldError> IntoResolvable<'a, S, T, C> for Result where S: ScalarValue, - T: GraphQLType, + T: GraphQLValue, T::Context: FromContext, { fn into(self, ctx: &'a C) -> FieldResult, S> { @@ -277,7 +282,7 @@ where impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for (&'a T::Context, T) where S: ScalarValue, - T: GraphQLType, + T: GraphQLValue, { fn into(self, _: &'a C) -> FieldResult, S> { Ok(Some(self)) @@ -287,7 +292,7 @@ where impl<'a, S, T, C> IntoResolvable<'a, S, Option, C> for Option<(&'a T::Context, T)> where S: ScalarValue, - T: GraphQLType, + T: GraphQLValue, { fn into(self, _: &'a C) -> FieldResult)>, S> { Ok(self.map(|(ctx, v)| (ctx, Some(v)))) @@ -297,7 +302,7 @@ where impl<'a, S, T, C> IntoResolvable<'a, S, T, C> for FieldResult<(&'a T::Context, T), S> where S: ScalarValue, - T: GraphQLType, + T: GraphQLValue, { fn into(self, _: &'a C) -> FieldResult, S> { self.map(Some) @@ -308,7 +313,7 @@ impl<'a, S, T, C> IntoResolvable<'a, S, Option, C> for FieldResult, S> where S: ScalarValue, - T: GraphQLType, + T: GraphQLValue, { fn into(self, _: &'a C) -> FieldResult)>, S> { self.map(|o| o.map(|(ctx, v)| (ctx, Some(v)))) @@ -369,7 +374,7 @@ where 'i: 'res, 'v: 'res, 'a: 'res, - T: crate::GraphQLSubscriptionType + Send + Sync, + T: GraphQLSubscriptionValue + Send + Sync, T::TypeInfo: Send + Sync, CtxT: Send + Sync, S: Send + Sync, @@ -393,7 +398,7 @@ where where 't: 'res, 'a: 'res, - T: crate::GraphQLSubscriptionType, + T: GraphQLSubscriptionValue, T::TypeInfo: Send + Sync, CtxT: Send + Sync, S: Send + Sync, @@ -405,7 +410,7 @@ where pub fn resolve_with_ctx(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult where NewCtxT: FromContext, - T: GraphQLType + ?Sized, + T: GraphQLValue + ?Sized, { self.replaced_context(>::from(self.context)) .resolve(info, value) @@ -414,7 +419,7 @@ where /// Resolve a single arbitrary value into an `ExecutionResult` pub fn resolve(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult where - T: GraphQLType + ?Sized, + T: GraphQLValue + ?Sized, { value.resolve(info, self.current_selection_set, self) } @@ -422,7 +427,7 @@ where /// Resolve a single arbitrary value into an `ExecutionResult` pub async fn resolve_async(&self, info: &T::TypeInfo, value: &T) -> ExecutionResult where - T: crate::GraphQLTypeAsync + Send + Sync + ?Sized, + T: GraphQLValueAsync + Send + Sync + ?Sized, T::TypeInfo: Send + Sync, CtxT: Send + Sync, S: Send + Sync, @@ -439,7 +444,7 @@ where value: &T, ) -> ExecutionResult where - T: crate::GraphQLTypeAsync + Send + Sync, + T: GraphQLValueAsync + Send + Sync, T::TypeInfo: Send + Sync, S: Send + Sync, NewCtxT: FromContext + Send + Sync, @@ -453,15 +458,12 @@ where /// If the field fails to resolve, `null` will be returned. pub fn resolve_into_value(&self, info: &T::TypeInfo, value: &T) -> Value where - T: GraphQLType, + T: GraphQLValue, { - match self.resolve(info, value) { - Ok(v) => v, - Err(e) => { - self.push_error(e); - Value::null() - } - } + self.resolve(info, value).unwrap_or_else(|e| { + self.push_error(e); + Value::null() + }) } /// Resolve a single arbitrary value into a return value @@ -469,7 +471,7 @@ where /// If the field fails to resolve, `null` will be returned. pub async fn resolve_into_value_async(&self, info: &T::TypeInfo, value: &T) -> Value where - T: crate::GraphQLTypeAsync + Send + Sync + ?Sized, + T: GraphQLValueAsync + Send + Sync + ?Sized, T::TypeInfo: Send + Sync, CtxT: Send + Sync, S: Send + Sync, @@ -851,9 +853,9 @@ pub async fn execute_validated_query_async<'a, 'b, QueryT, MutationT, Subscripti ) -> Result<(Value, Vec>), GraphQLError<'a>> where S: ScalarValue + Send + Sync, - QueryT: crate::GraphQLTypeAsync + Send + Sync, + QueryT: GraphQLTypeAsync + Send + Sync, QueryT::TypeInfo: Send + Sync, - MutationT: crate::GraphQLTypeAsync + Send + Sync, + MutationT: GraphQLTypeAsync + Send + Sync, MutationT::TypeInfo: Send + Sync, SubscriptionT: GraphQLType + Send + Sync, SubscriptionT::TypeInfo: Send + Sync, @@ -998,11 +1000,11 @@ where 'd: 'r, 'op: 'd, S: ScalarValue + Send + Sync, - QueryT: crate::GraphQLTypeAsync + Send + Sync, + QueryT: GraphQLTypeAsync + Send + Sync, QueryT::TypeInfo: Send + Sync, - MutationT: crate::GraphQLTypeAsync + Send + Sync, + MutationT: GraphQLTypeAsync + Send + Sync, MutationT::TypeInfo: Send + Sync, - SubscriptionT: crate::GraphQLSubscriptionType + Send + Sync, + SubscriptionT: GraphQLSubscriptionType + Send + Sync, SubscriptionT::TypeInfo: Send + Sync, CtxT: Send + Sync + 'r, { diff --git a/juniper/src/http/mod.rs b/juniper/src/http/mod.rs index 7d6de6a76..182bc2fe5 100644 --- a/juniper/src/http/mod.rs +++ b/juniper/src/http/mod.rs @@ -106,9 +106,9 @@ where ) -> GraphQLResponse<'a, S> where S: ScalarValue + Send + Sync, - QueryT: crate::GraphQLTypeAsync + Send + Sync, + QueryT: GraphQLTypeAsync + Send + Sync, QueryT::TypeInfo: Send + Sync, - MutationT: crate::GraphQLTypeAsync + Send + Sync, + MutationT: GraphQLTypeAsync + Send + Sync, MutationT::TypeInfo: Send + Sync, SubscriptionT: GraphQLType + Send + Sync, SubscriptionT::TypeInfo: Send + Sync, @@ -259,13 +259,13 @@ where /// This is a simple wrapper around the `execute_sync` function exposed in GraphQLRequest. pub fn execute_sync<'a, CtxT, QueryT, MutationT, SubscriptionT>( &'a self, - root_node: &'a crate::RootNode, + root_node: &'a RootNode, context: &CtxT, ) -> GraphQLBatchResponse<'a, S> where - QueryT: crate::GraphQLType, - MutationT: crate::GraphQLType, - SubscriptionT: crate::GraphQLType, + QueryT: GraphQLType, + MutationT: GraphQLType, + SubscriptionT: GraphQLType, { match *self { Self::Single(ref req) => { @@ -285,15 +285,15 @@ where /// GraphQLRequest pub async fn execute<'a, CtxT, QueryT, MutationT, SubscriptionT>( &'a self, - root_node: &'a crate::RootNode<'a, QueryT, MutationT, SubscriptionT, S>, + root_node: &'a RootNode<'a, QueryT, MutationT, SubscriptionT, S>, context: &'a CtxT, ) -> GraphQLBatchResponse<'a, S> where - QueryT: crate::GraphQLTypeAsync + Send + Sync, + QueryT: GraphQLTypeAsync + Send + Sync, QueryT::TypeInfo: Send + Sync, - MutationT: crate::GraphQLTypeAsync + Send + Sync, + MutationT: GraphQLTypeAsync + Send + Sync, MutationT::TypeInfo: Send + Sync, - SubscriptionT: crate::GraphQLSubscriptionType + Send + Sync, + SubscriptionT: GraphQLSubscriptionType + Send + Sync, SubscriptionT::TypeInfo: Send + Sync, CtxT: Send + Sync, S: Send + Sync, diff --git a/juniper/src/integrations/mod.rs b/juniper/src/integrations/mod.rs index f285a3b51..b1017ccff 100644 --- a/juniper/src/integrations/mod.rs +++ b/juniper/src/integrations/mod.rs @@ -1,4 +1,5 @@ //! Provides GraphQLType implementations for some external types + #[doc(hidden)] pub mod serde; diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs index 14bf1fa52..1c40e2bbc 100644 --- a/juniper/src/lib.rs +++ b/juniper/src/lib.rs @@ -185,11 +185,14 @@ pub use crate::{ model::{RootNode, SchemaType}, }, types::{ - async_await::GraphQLTypeAsync, - base::{Arguments, GraphQLType, TypeKind}, + async_await::{GraphQLTypeAsync, GraphQLValueAsync}, + base::{Arguments, GraphQLType, GraphQLValue, TypeKind}, marker::{self, GraphQLUnion}, scalars::{EmptyMutation, EmptySubscription, ID}, - subscriptions::{GraphQLSubscriptionType, SubscriptionConnection, SubscriptionCoordinator}, + subscriptions::{ + GraphQLSubscriptionType, GraphQLSubscriptionValue, SubscriptionConnection, + SubscriptionCoordinator, + }, }, validation::RuleError, value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value}, diff --git a/juniper/src/macros/interface.rs b/juniper/src/macros/interface.rs index e0c399f54..d23c63cd2 100644 --- a/juniper/src/macros/interface.rs +++ b/juniper/src/macros/interface.rs @@ -134,10 +134,7 @@ macro_rules! graphql_interface { ) => { $crate::__juniper_impl_trait!( impl<$($scalar)* $(, $lifetimes)* > GraphQLType for $name { - type Context = $ctx; - type TypeInfo = (); - - fn name(_ : &Self::TypeInfo) -> Option<&str> { + fn name(_ : &Self::TypeInfo) -> Option<&'static str> { Some($($outname)*) } @@ -178,7 +175,17 @@ macro_rules! graphql_interface { $(.description($desciption))* .into_meta() } + } + ); + $crate::__juniper_impl_trait!( + impl<$($scalar)* $(, $lifetimes)* > GraphQLValue for $name { + type Context = $ctx; + type TypeInfo = (); + + fn type_name(&self, _ : &Self::TypeInfo) -> Option<&'static str> { + Some($($outname)*) + } #[allow(unused_variables)] fn resolve_field( diff --git a/juniper/src/macros/subscription_helpers.rs b/juniper/src/macros/subscription_helpers.rs index 6ca55f459..406cc3ece 100644 --- a/juniper/src/macros/subscription_helpers.rs +++ b/juniper/src/macros/subscription_helpers.rs @@ -5,7 +5,7 @@ use futures::Stream; -use crate::{FieldError, GraphQLType, ScalarValue}; +use crate::{FieldError, GraphQLValue, ScalarValue}; /// Trait for converting `T` to `Ok(T)` if T is not Result. /// This is useful in subscription macros when user can provide type alias for @@ -50,7 +50,7 @@ pub struct ResultStreamItem; pub struct ResultStreamResult; /// This trait is used in `juniper::graphql_subscription` macro to get stream's -/// item type that implements `GraphQLType` from type alias provided +/// item type that implements `GraphQLValue` from type alias provided /// by user. pub trait ExtractTypeFromStream where @@ -59,13 +59,13 @@ where /// Stream's return Value that will be returned if /// no errors occured. Is used to determine field type in /// `#[juniper::graphql_subscription]` - type Item: GraphQLType; + type Item: GraphQLValue; } impl ExtractTypeFromStream for T where T: futures::Stream, - I: GraphQLType, + I: GraphQLValue, S: ScalarValue, { type Item = I; @@ -74,7 +74,7 @@ where impl ExtractTypeFromStream for Ty where Ty: futures::Stream>, - T: GraphQLType, + T: GraphQLValue, S: ScalarValue, { type Item = T; @@ -83,7 +83,7 @@ where impl ExtractTypeFromStream for Result where T: futures::Stream, - I: GraphQLType, + I: GraphQLValue, S: ScalarValue, { type Item = I; @@ -92,7 +92,7 @@ where impl ExtractTypeFromStream for Result where T: futures::Stream>, - I: GraphQLType, + I: GraphQLValue, S: ScalarValue, { type Item = I; diff --git a/juniper/src/macros/tests/util.rs b/juniper/src/macros/tests/util.rs index 058317285..041883711 100644 --- a/juniper/src/macros/tests/util.rs +++ b/juniper/src/macros/tests/util.rs @@ -1,14 +1,11 @@ -use crate::{DefaultScalarValue, GraphQLTypeAsync, RootNode, Value, Variables}; -use std::default::Default; +use crate::{DefaultScalarValue, GraphQLType, GraphQLTypeAsync, RootNode, Value, Variables}; pub async fn run_query(query: &str) -> Value where Query: GraphQLTypeAsync + Default, Mutation: GraphQLTypeAsync + Default, - Subscription: crate::GraphQLType - + Default - + Sync - + Send, + Subscription: + GraphQLType + Default + Sync + Send, Context: Default + Send + Sync, { let schema = RootNode::new( @@ -29,10 +26,8 @@ pub async fn run_info_query(type_name: & where Query: GraphQLTypeAsync + Default, Mutation: GraphQLTypeAsync + Default, - Subscription: crate::GraphQLType - + Default - + Sync - + Send, + Subscription: + GraphQLType + Default + Sync + Send, Context: Default + Send + Sync, { let query = format!( diff --git a/juniper/src/schema/schema.rs b/juniper/src/schema/schema.rs index 39a155732..2d20a94c6 100644 --- a/juniper/src/schema/schema.rs +++ b/juniper/src/schema/schema.rs @@ -1,7 +1,10 @@ use crate::{ ast::Selection, executor::{ExecutionResult, Executor, Registry}, - types::base::{Arguments, GraphQLType, TypeKind}, + types::{ + async_await::{GraphQLTypeAsync, GraphQLValueAsync}, + base::{Arguments, GraphQLType, GraphQLValue, TypeKind}, + }, value::{ScalarValue, Value}, }; @@ -21,9 +24,6 @@ where MutationT: GraphQLType, SubscriptionT: GraphQLType, { - type Context = CtxT; - type TypeInfo = QueryT::TypeInfo; - fn name(info: &QueryT::TypeInfo) -> Option<&str> { QueryT::name(info) } @@ -34,6 +34,22 @@ where { QueryT::meta(info, registry) } +} + +impl<'a, CtxT, S, QueryT, MutationT, SubscriptionT> GraphQLValue + for RootNode<'a, QueryT, MutationT, SubscriptionT, S> +where + S: ScalarValue, + QueryT: GraphQLType, + MutationT: GraphQLType, + SubscriptionT: GraphQLType, +{ + type Context = CtxT; + type TypeInfo = QueryT::TypeInfo; + + fn type_name<'i>(&self, info: &'i QueryT::TypeInfo) -> Option<&'i str> { + QueryT::name(info) + } fn resolve_field( &self, @@ -77,13 +93,13 @@ where } } -impl<'a, CtxT, S, QueryT, MutationT, SubscriptionT> crate::GraphQLTypeAsync +impl<'a, CtxT, S, QueryT, MutationT, SubscriptionT> GraphQLValueAsync for RootNode<'a, QueryT, MutationT, SubscriptionT, S> where S: ScalarValue + Send + Sync, - QueryT: crate::GraphQLTypeAsync, + QueryT: GraphQLTypeAsync, QueryT::TypeInfo: Send + Sync, - MutationT: crate::GraphQLTypeAsync, + MutationT: GraphQLTypeAsync, MutationT::TypeInfo: Send + Sync, SubscriptionT: GraphQLType + Send + Sync, SubscriptionT::TypeInfo: Send + Sync, diff --git a/juniper/src/schema/translate/graphql_parser.rs b/juniper/src/schema/translate/graphql_parser.rs index de7da1d9f..67f0ae848 100644 --- a/juniper/src/schema/translate/graphql_parser.rs +++ b/juniper/src/schema/translate/graphql_parser.rs @@ -1,25 +1,27 @@ -use std::boxed::Box; -use std::collections::BTreeMap; +use std::{boxed::Box, collections::BTreeMap}; -use graphql_parser::query::{ - Directive as ExternalDirective, Number as ExternalNumber, Type as ExternalType, +use graphql_parser::{ + query::{Directive as ExternalDirective, Number as ExternalNumber, Type as ExternalType}, + schema::{ + Definition, Document, EnumType as ExternalEnum, EnumValue as ExternalEnumValue, + Field as ExternalField, InputObjectType as ExternalInputObjectType, + InputValue as ExternalInputValue, InterfaceType as ExternalInterfaceType, + ObjectType as ExternalObjectType, ScalarType as ExternalScalarType, SchemaDefinition, Text, + TypeDefinition as ExternalTypeDefinition, UnionType as ExternalUnionType, + Value as ExternalValue, + }, + Pos, }; -use graphql_parser::schema::{Definition, Document, SchemaDefinition, Text}; -use graphql_parser::schema::{ - EnumType as ExternalEnum, EnumValue as ExternalEnumValue, Field as ExternalField, - InputObjectType as ExternalInputObjectType, InputValue as ExternalInputValue, - InterfaceType as ExternalInterfaceType, ObjectType as ExternalObjectType, - ScalarType as ExternalScalarType, TypeDefinition as ExternalTypeDefinition, - UnionType as ExternalUnionType, Value as ExternalValue, -}; -use graphql_parser::Pos; -use crate::ast::{InputValue, Type}; -use crate::schema::meta::DeprecationStatus; -use crate::schema::meta::{Argument, EnumValue, Field, MetaType}; -use crate::schema::model::SchemaType; -use crate::schema::translate::SchemaTranslator; -use crate::value::ScalarValue; +use crate::{ + ast::{InputValue, Type}, + schema::{ + meta::{Argument, DeprecationStatus, EnumValue, Field, MetaType}, + model::SchemaType, + translate::SchemaTranslator, + }, + value::ScalarValue, +}; pub struct GraphQLParserTranslator; diff --git a/juniper/src/tests/model.rs b/juniper/src/tests/model.rs index 645ede185..2c992aa4e 100644 --- a/juniper/src/tests/model.rs +++ b/juniper/src/tests/model.rs @@ -1,8 +1,9 @@ #![allow(missing_docs)] -use juniper_codegen::GraphQLEnumInternal as GraphQLEnum; use std::collections::HashMap; +use juniper_codegen::GraphQLEnumInternal as GraphQLEnum; + #[derive(GraphQLEnum, Copy, Clone, Eq, PartialEq, Debug)] pub enum Episode { #[graphql(name = "NEW_HOPE")] @@ -107,16 +108,16 @@ pub struct Database { } use crate::{ - executor::Registry, schema::meta::MetaType, types::base::GraphQLType, value::ScalarValue, + executor::Registry, + schema::meta::MetaType, + types::base::{GraphQLType, GraphQLValue}, + value::ScalarValue, }; impl GraphQLType for Database where S: ScalarValue, { - type Context = Self; - type TypeInfo = (); - fn name(_: &()) -> Option<&str> { Some("_Database") } @@ -129,6 +130,18 @@ where } } +impl GraphQLValue for Database +where + S: ScalarValue, +{ + type Context = Self; + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + >::name(info) + } +} + impl HumanData { pub fn new( id: &str, diff --git a/juniper/src/tests/type_info_tests.rs b/juniper/src/tests/type_info_tests.rs index 87208fd8c..fdacbc611 100644 --- a/juniper/src/tests/type_info_tests.rs +++ b/juniper/src/tests/type_info_tests.rs @@ -4,7 +4,7 @@ use crate::{ executor::{ExecutionResult, Executor, Registry, Variables}, schema::{meta::MetaType, model::RootNode}, types::{ - base::{Arguments, GraphQLType}, + base::{Arguments, GraphQLType, GraphQLValue}, scalars::{EmptyMutation, EmptySubscription}, }, value::{ScalarValue, Value}, @@ -23,9 +23,6 @@ impl GraphQLType for Node where S: ScalarValue, { - type Context = (); - type TypeInfo = NodeTypeInfo; - fn name(info: &Self::TypeInfo) -> Option<&str> { Some(&info.name) } @@ -44,6 +41,18 @@ where .build_object_type::(info, &fields) .into_meta() } +} + +impl GraphQLValue for Node +where + S: ScalarValue, +{ + type Context = (); + type TypeInfo = NodeTypeInfo; + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + >::name(info) + } fn resolve_field( &self, diff --git a/juniper/src/types/async_await.rs b/juniper/src/types/async_await.rs index 156c2ab52..159a52fbc 100644 --- a/juniper/src/types/async_await.rs +++ b/juniper/src/types/async_await.rs @@ -2,33 +2,35 @@ use crate::{ ast::Selection, executor::{ExecutionResult, Executor}, parser::Spanning, - value::{Object, ScalarValue, Value}, + value::{DefaultScalarValue, Object, ScalarValue, Value}, }; use crate::BoxFuture; -use super::base::{is_excluded, merge_key_into, Arguments, GraphQLType}; +use super::base::{is_excluded, merge_key_into, Arguments, GraphQLType, GraphQLValue}; -/** -This trait extends `GraphQLType` with asynchronous queries/mutations resolvers. - -Convenience macros related to asynchronous queries/mutations expand into an -implementation of this trait and `GraphQLType` for the given type. -*/ -pub trait GraphQLTypeAsync: GraphQLType + Send + Sync +/// Extension of [`GraphQLValue`] trait with asynchronous queries/mutations resolvers. +/// +/// Convenience macros related to asynchronous queries/mutations expand into an implementation of +/// this trait and [`GraphQLValue`] for the given type. +pub trait GraphQLValueAsync: GraphQLValue + Send + Sync where Self::Context: Send + Sync, Self::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, { - /// Resolve the value of a single field on this type. + /// Resolves the value of a single field on this [`GraphQLValueAsync`]. + /// + /// The `arguments` object contains all the specified arguments, with default values being + /// substituted for the ones not provided by the query. /// - /// The arguments object contain all specified arguments, with default - /// values substituted for the ones not provided by the query. + /// The `executor` can be used to drive selections into sub-[objects][3]. /// - /// The executor can be used to drive selections into sub-objects. + /// # Panics /// /// The default implementation panics. + /// + /// [3]: https://spec.graphql.org/June2018/#sec-Objects fn resolve_field_async<'a>( &'a self, _info: &'a Self::TypeInfo, @@ -36,59 +38,102 @@ where _arguments: &'a Arguments, _executor: &'a Executor, ) -> BoxFuture<'a, ExecutionResult> { - panic!("resolve_field must be implemented by object types"); + panic!( + "GraphQLValueAsync::resolve_field_async() must be implemented by objects and \ + interfaces", + ); } - /// Resolve the provided selection set against the current object. + /// Resolves this [`GraphQLValueAsync`] (being an [interface][1] or an [union][2]) into a + /// concrete downstream [object][3] type. /// - /// For non-object types, the selection set will be `None` and the value - /// of the object should simply be returned. + /// Tries to resolve this [`GraphQLValueAsync`] into the provided `type_name`. If the type + /// matches, then passes the instance along to [`Executor::resolve`]. /// - /// For objects, all fields in the selection set should be resolved. - /// The default implementation uses `resolve_field` to resolve all fields, - /// including those through fragment expansion. + /// # Panics /// - /// Since the GraphQL spec specificies that errors during field processing - /// should result in a null-value, this might return Ok(Null) in case of - /// failure. Errors are recorded internally. - fn resolve_async<'a>( + /// The default implementation panics. + /// + /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces + /// [2]: https://spec.graphql.org/June2018/#sec-Unions + /// [3]: https://spec.graphql.org/June2018/#sec-Objects + fn resolve_into_type_async<'a>( &'a self, info: &'a Self::TypeInfo, - selection_set: Option<&'a [Selection]>, - executor: &'a Executor, + type_name: &str, + selection_set: Option<&'a [Selection<'a, S>]>, + executor: &'a Executor<'a, 'a, Self::Context, S>, ) -> BoxFuture<'a, ExecutionResult> { - if let Some(selection_set) = selection_set { - Box::pin(async move { - let value = - resolve_selection_set_into_async(self, info, selection_set, executor).await; - Ok(value) - }) + if self.type_name(info).unwrap() == type_name { + self.resolve_async(info, selection_set, executor) } else { - panic!("resolve() must be implemented by non-object output types"); + panic!( + "GraphQLValueAsync::resolve_into_type_async() must be implemented by unions and \ + interfaces", + ); } } - /// Resolve this interface or union into a concrete type + /// Resolves the provided `selection_set` against this [`GraphQLValueAsync`]. /// - /// Try to resolve the current type into the type name provided. If the - /// type matches, pass the instance along to `executor.resolve`. + /// For non-[object][3] types, the `selection_set` will be [`None`] and the value should simply + /// be returned. /// - /// The default implementation panics. - fn resolve_into_type_async<'a>( + /// For [objects][3], all fields in the `selection_set` should be resolved. The default + /// implementation uses [`GraphQLValueAsync::resolve_field_async`] to resolve all fields, + /// including those through a fragment expansion. + /// + /// Since the [GraphQL spec specifies][0] that errors during field processing should result in + /// a null-value, this might return `Ok(Null)` in case of a failure. Errors are recorded + /// internally. + /// + /// # Panics + /// + /// The default implementation panics, if `selection_set` is [`None`]. + /// + /// [0]: https://spec.graphql.org/June2018/#sec-Errors-and-Non-Nullability + /// [3]: https://spec.graphql.org/June2018/#sec-Objects + fn resolve_async<'a>( &'a self, info: &'a Self::TypeInfo, - type_name: &str, - selection_set: Option<&'a [Selection<'a, S>]>, - executor: &'a Executor<'a, 'a, Self::Context, S>, + selection_set: Option<&'a [Selection]>, + executor: &'a Executor, ) -> BoxFuture<'a, ExecutionResult> { - if Self::name(info).unwrap() == type_name { - self.resolve_async(info, selection_set, executor) + if let Some(sel) = selection_set { + Box::pin(async move { + Ok(resolve_selection_set_into_async(self, info, sel, executor).await) + }) } else { - panic!("resolve_into_type_async must be implemented by unions and interfaces"); + panic!( + "GraphQLValueAsync::resolve_async() must be implemented by non-object output types", + ); } } } +crate::sa::assert_obj_safe!(GraphQLValueAsync); + +/// Extension of [`GraphQLType`] trait with asynchronous queries/mutations resolvers. +/// +/// It's automatically implemented for [`GraphQLValueAsync`] and [`GraphQLType`] implementors, so +/// doesn't require manual or code-generated implementation. +pub trait GraphQLTypeAsync: GraphQLValueAsync + GraphQLType +where + Self::Context: Send + Sync, + Self::TypeInfo: Send + Sync, + S: ScalarValue + Send + Sync, +{ +} + +impl GraphQLTypeAsync for T +where + T: GraphQLValueAsync + GraphQLType, + T::Context: Send + Sync, + T::TypeInfo: Send + Sync, + S: ScalarValue + Send + Sync, +{ +} + // Wrapper function around resolve_selection_set_into_async_recursive. // This wrapper is necessary because async fns can not be recursive. fn resolve_selection_set_into_async<'a, 'e, T, CtxT, S>( @@ -98,7 +143,7 @@ fn resolve_selection_set_into_async<'a, 'e, T, CtxT, S>( executor: &'e Executor<'e, 'e, CtxT, S>, ) -> BoxFuture<'a, Value> where - T: GraphQLTypeAsync + ?Sized, + T: GraphQLValueAsync + ?Sized, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -129,7 +174,7 @@ pub(crate) async fn resolve_selection_set_into_async_recursive<'a, T, CtxT, S>( executor: &'a Executor<'a, 'a, CtxT, S>, ) -> Value where - T: GraphQLTypeAsync + Send + Sync + ?Sized, + T: GraphQLValueAsync + Send + Sync + ?Sized, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -143,7 +188,8 @@ where let meta_type = executor .schema() .concrete_type_by_name( - T::name(info) + instance + .type_name(info) .expect("Resolving named type's selection set") .as_ref(), ) diff --git a/juniper/src/types/base.rs b/juniper/src/types/base.rs index c80188ed0..b1f4d0f03 100644 --- a/juniper/src/types/base.rs +++ b/juniper/src/types/base.rs @@ -113,179 +113,108 @@ where where T: FromInputValue, { - match self.args { - Some(ref args) => match args.get(key) { - Some(v) => v.convert(), - None => None, - }, - None => None, - } - } -} - -/** -Primary trait used to expose Rust types in a GraphQL schema - -All of the convenience macros ultimately expand into an implementation of -this trait for the given type. The macros remove duplicated definitions of -fields and arguments, and add type checks on all resolve functions -automatically. This can all be done manually. - -`GraphQLType` provides _some_ convenience methods for you, in the form of -optional trait methods. The `name` and `meta` methods are mandatory, but -other than that, it depends on what type you're exposing: - -* Scalars, enums, lists and non null wrappers only require `resolve`, -* Interfaces and objects require `resolve_field` _or_ `resolve` if you want - to implement custom resolution logic (probably not), -* Interfaces and unions require `resolve_into_type` and `concrete_type_name`. -* Input objects do not require anything - -## Example - -Manually deriving an object is straightforward but tedious. This is the -equivalent of the `User` object as shown in the example in the documentation -root: - -```rust -use juniper::{GraphQLType, Registry, FieldResult, Context, - Arguments, Executor, ExecutionResult, - DefaultScalarValue}; -use juniper::meta::MetaType; -# use std::collections::HashMap; - -#[derive(Debug)] -struct User { id: String, name: String, friend_ids: Vec } -#[derive(Debug)] -struct Database { users: HashMap } - -impl Context for Database {} - -impl GraphQLType for User -{ - type Context = Database; - type TypeInfo = (); - - fn name(_: &()) -> Option<&'static str> { - Some("User") - } - - fn meta<'r>(_: &(), registry: &mut Registry<'r>) -> MetaType<'r> - where DefaultScalarValue: 'r, - { - // First, we need to define all fields and their types on this type. - // - // If we need arguments, want to implement interfaces, or want to add - // documentation strings, we can do it here. - let fields = &[ - registry.field::<&String>("id", &()), - registry.field::<&String>("name", &()), - registry.field::>("friends", &()), - ]; - - registry.build_object_type::(&(), fields).into_meta() - } - - fn resolve_field( - &self, - info: &(), - field_name: &str, - args: &Arguments, - executor: &Executor - ) - -> ExecutionResult - { - // Next, we need to match the queried field name. All arms of this - // match statement return `ExecutionResult`, which makes it hard to - // statically verify that the type you pass on to `executor.resolve*` - // actually matches the one that you defined in `meta()` above. - let database = executor.context(); - match field_name { - // Because scalars are defined with another `Context` associated - // type, you must use resolve_with_ctx here to make the executor - // perform automatic type conversion of its argument. - "id" => executor.resolve_with_ctx(info, &self.id), - "name" => executor.resolve_with_ctx(info, &self.name), - - // You pass a vector of User objects to `executor.resolve`, and it - // will determine which fields of the sub-objects to actually - // resolve based on the query. The executor instance keeps track - // of its current position in the query. - "friends" => executor.resolve(info, - &self.friend_ids.iter() - .filter_map(|id| database.users.get(id)) - .collect::>() - ), - - // We can only reach this panic in two cases; either a mismatch - // between the defined schema in `meta()` above, or a validation - // in this library failed because of a bug. - // - // In either of those two cases, the only reasonable way out is - // to panic the thread. - _ => panic!("Field {} not found on type User", field_name), - } + self.args + .as_ref() + .and_then(|args| args.get(key)) + .and_then(InputValue::convert) } } -``` -*/ -pub trait GraphQLType +/// Primary trait used to resolve GraphQL values. +/// +/// All the convenience macros ultimately expand into an implementation of this trait for the given +/// type. The macros remove duplicated definitions of fields and arguments, and add type checks on +/// all resolving functions automatically. This can all be done manually too. +/// +/// [`GraphQLValue`] provides _some_ convenience methods for you, in the form of optional trait +/// methods. The `type_name` method is mandatory, but other than that, it depends on what type +/// you're exposing: +/// - [Scalars][4], [enums][5], [lists][6] and [non-null wrappers][7] only require `resolve`. +/// - [Interfaces][1] and [objects][3] require `resolve_field` _or_ `resolve` if you want to +/// implement a custom resolution logic (probably not). +/// - [Interfaces][1] and [unions][2] require `resolve_into_type` and `concrete_type_name`. +/// - [Input objects][8] do not require anything. +/// +/// # Object safety +/// +/// This trait is [object safe][11], therefore may be turned into a [trait object][12] and used for +/// resolving GraphQL values even when a concrete Rust type is erased. +/// +/// # Example +/// +/// This trait is intended to be used in a conjunction with a [`GraphQLType`] trait. See the example +/// in the documentation of a [`GraphQLType`] trait. +/// +/// [1]: https://spec.graphql.org/June2018/#sec-Interfaces +/// [2]: https://spec.graphql.org/June2018/#sec-Unions +/// [3]: https://spec.graphql.org/June2018/#sec-Objects +/// [4]: https://spec.graphql.org/June2018/#sec-Scalars +/// [5]: https://spec.graphql.org/June2018/#sec-Enums +/// [6]: https://spec.graphql.org/June2018/#sec-Type-System.List +/// [7]: https://spec.graphql.org/June2018/#sec-Type-System.Non-Null +/// [8]: https://spec.graphql.org/June2018/#sec-Input-Objects +/// [11]: https://doc.rust-lang.org/reference/items/traits.html#object-safety +/// [12]: https://doc.rust-lang.org/reference/types/trait-object.html +pub trait GraphQLValue where S: ScalarValue, { - /// The expected context type for this GraphQL type + /// Context type for this [`GraphQLValue`]. /// - /// The context is threaded through query execution to all affected nodes, - /// and can be used to hold common data, e.g. database connections or - /// request session information. + /// It's threaded through a query execution to all affected nodes, and can be used to hold + /// common data, e.g. database connections or request session information. type Context; - /// Type that may carry additional schema information + /// Type that may carry additional schema information for this [`GraphQLValue`]. /// - /// This can be used to implement a schema that is partly dynamic, - /// meaning that it can use information that is not known at compile time, - /// for instance by reading it from a configuration file at start-up. + /// It can be used to implement a schema that is partly dynamic, meaning that it can use + /// information that is not known at compile time, for instance by reading it from a + /// configuration file at startup. type TypeInfo; - /// The name of the GraphQL type to expose. + /// Returns name of the [`GraphQLType`] exposed by this [`GraphQLValue`]. /// - /// This function will be called multiple times during schema construction. - /// It must _not_ perform any calculation and _always_ return the same - /// value. - fn name(info: &Self::TypeInfo) -> Option<&str>; - - /// The meta type representing this GraphQL type. - fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> - where - S: 'r; + /// This function will be called multiple times during a query execution. It must _not_ perform + /// any calculation and _always_ return the same value. + /// + /// Usually, it should just call a [`GraphQLType::name`] inside. + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str>; - /// Resolve the value of a single field on this type. + /// Resolves the value of a single field on this [`GraphQLValue`]. + /// + /// The `arguments` object contains all the specified arguments, with default values being + /// substituted for the ones not provided by the query. /// - /// The arguments object contain all specified arguments, with default - /// values substituted for the ones not provided by the query. + /// The `executor` can be used to drive selections into sub-[objects][3]. /// - /// The executor can be used to drive selections into sub-objects. + /// # Panics /// /// The default implementation panics. - #[allow(unused_variables)] + /// + /// [3]: https://spec.graphql.org/June2018/#sec-Objects fn resolve_field( &self, - info: &Self::TypeInfo, - field_name: &str, - arguments: &Arguments, - executor: &Executor, + _info: &Self::TypeInfo, + _field_name: &str, + _arguments: &Arguments, + _executor: &Executor, ) -> ExecutionResult { - panic!("resolve_field must be implemented by object types"); + panic!("GraphQLValue::resolve_field() must be implemented by objects and interfaces"); } - /// Resolve this interface or union into a concrete type + /// Resolves this [`GraphQLValue`] (being an [interface][1] or an [union][2]) into a concrete + /// downstream [object][3] type. + /// + /// Tries to resolve this [`GraphQLValue`] into the provided `type_name`. If the type matches, + /// then passes the instance along to [`Executor::resolve`]. /// - /// Try to resolve the current type into the type name provided. If the - /// type matches, pass the instance along to `executor.resolve`. + /// # Panics /// /// The default implementation panics. - #[allow(unused_variables)] + /// + /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces + /// [2]: https://spec.graphql.org/June2018/#sec-Unions + /// [3]: https://spec.graphql.org/June2018/#sec-Objects fn resolve_into_type( &self, info: &Self::TypeInfo, @@ -293,54 +222,181 @@ where selection_set: Option<&[Selection]>, executor: &Executor, ) -> ExecutionResult { - if Self::name(info).unwrap() == type_name { + if self.type_name(info).unwrap() == type_name { self.resolve(info, selection_set, executor) } else { - panic!("resolve_into_type must be implemented by unions and interfaces"); + panic!( + "GraphQLValue::resolve_into_type() must be implemented by unions and interfaces" + ); } } - /// Return the concrete type name for this instance/union. + /// Returns the concrete [`GraphQLType`] name for this [`GraphQLValue`] being an [interface][1], + /// an [union][2] or an [object][3]. + /// + /// # Panics /// /// The default implementation panics. + /// + /// [1]: https://spec.graphql.org/June2018/#sec-Interfaces + /// [2]: https://spec.graphql.org/June2018/#sec-Unions + /// [3]: https://spec.graphql.org/June2018/#sec-Objects #[allow(unused_variables)] fn concrete_type_name(&self, context: &Self::Context, info: &Self::TypeInfo) -> String { - panic!("concrete_type_name must be implemented by unions and interfaces"); + panic!( + "GraphQLValue::concrete_type_name() must be implemented by unions, interfaces \ + and objects", + ); } - /// Resolve the provided selection set against the current object. + /// Resolves the provided `selection_set` against this [`GraphQLValue`]. + /// + /// For non-[object][3] types, the `selection_set` will be [`None`] and the value should simply + /// be returned. + /// + /// For [objects][3], all fields in the `selection_set` should be resolved. The default + /// implementation uses [`GraphQLValue::resolve_field`] to resolve all fields, including those + /// through a fragment expansion. /// - /// For non-object types, the selection set will be `None` and the value - /// of the object should simply be returned. + /// Since the [GraphQL spec specifies][0] that errors during field processing should result in + /// a null-value, this might return `Ok(Null)` in case of a failure. Errors are recorded + /// internally. /// - /// For objects, all fields in the selection set should be resolved. - /// The default implementation uses `resolve_field` to resolve all fields, - /// including those through fragment expansion. + /// # Panics /// - /// Since the GraphQL spec specificies that errors during field processing - /// should result in a null-value, this might return Ok(Null) in case of - /// failure. Errors are recorded internally. + /// The default implementation panics, if `selection_set` is [`None`]. + /// + /// [0]: https://spec.graphql.org/June2018/#sec-Errors-and-Non-Nullability + /// [3]: https://spec.graphql.org/June2018/#sec-Objects fn resolve( &self, info: &Self::TypeInfo, selection_set: Option<&[Selection]>, executor: &Executor, ) -> ExecutionResult { - if let Some(selection_set) = selection_set { - let mut result = Object::with_capacity(selection_set.len()); - let out = - if resolve_selection_set_into(self, info, selection_set, executor, &mut result) { - Value::Object(result) + if let Some(sel) = selection_set { + let mut res = Object::with_capacity(sel.len()); + Ok( + if resolve_selection_set_into(self, info, sel, executor, &mut res) { + Value::Object(res) } else { Value::null() - }; - Ok(out) + }, + ) } else { - panic!("resolve() must be implemented by non-object output types"); + panic!("GraphQLValue::resolve() must be implemented by non-object output types"); } } } +crate::sa::assert_obj_safe!(GraphQLValue); + +/// Primary trait used to expose Rust types in a GraphQL schema. +/// +/// All of the convenience macros ultimately expand into an implementation of +/// this trait for the given type. This can all be done manually. +/// +/// # Example +/// +/// Manually deriving an [object][3] is straightforward, but tedious. This is the equivalent of the +/// `User` object as shown in the example in the documentation root: +/// ``` +/// # use std::collections::HashMap; +/// use juniper::{ +/// meta::MetaType, Arguments, Context, DefaultScalarValue, Executor, ExecutionResult, +/// FieldResult, GraphQLType, GraphQLValue, Registry, +/// }; +/// +/// #[derive(Debug)] +/// struct Database { users: HashMap } +/// impl Context for Database {} +/// +/// #[derive(Debug)] +/// struct User { id: String, name: String, friend_ids: Vec } +/// +/// impl GraphQLType for User { +/// fn name(_: &()) -> Option<&'static str> { +/// Some("User") +/// } +/// +/// fn meta<'r>(_: &(), registry: &mut Registry<'r>) -> MetaType<'r> +/// where DefaultScalarValue: 'r, +/// { +/// // First, we need to define all fields and their types on this type. +/// // +/// // If we need arguments, want to implement interfaces, or want to add documentation +/// // strings, we can do it here. +/// let fields = &[ +/// registry.field::<&String>("id", &()), +/// registry.field::<&String>("name", &()), +/// registry.field::>("friends", &()), +/// ]; +/// registry.build_object_type::(&(), fields).into_meta() +/// } +/// } +/// +/// impl GraphQLValue for User { +/// type Context = Database; +/// type TypeInfo = (); +/// +/// fn type_name(&self, _: &()) -> Option<&'static str> { +/// ::name(&()) +/// } +/// +/// fn resolve_field( +/// &self, +/// info: &(), +/// field_name: &str, +/// args: &Arguments, +/// executor: &Executor +/// ) -> ExecutionResult +/// { +/// // Next, we need to match the queried field name. All arms of this match statement +/// // return `ExecutionResult`, which makes it hard to statically verify that the type you +/// // pass on to `executor.resolve*` actually matches the one that you defined in `meta()` +/// // above. +/// let database = executor.context(); +/// match field_name { +/// // Because scalars are defined with another `Context` associated type, you must use +/// // `resolve_with_ctx` here to make the `executor` perform automatic type conversion +/// // of its argument. +/// "id" => executor.resolve_with_ctx(info, &self.id), +/// "name" => executor.resolve_with_ctx(info, &self.name), +/// +/// // You pass a vector of `User` objects to `executor.resolve`, and it will determine +/// // which fields of the sub-objects to actually resolve based on the query. +/// // The `executor` instance keeps track of its current position in the query. +/// "friends" => executor.resolve(info, +/// &self.friend_ids.iter() +/// .filter_map(|id| database.users.get(id)) +/// .collect::>() +/// ), +/// +/// // We can only reach this panic in two cases: either a mismatch between the defined +/// // schema in `meta()` above, or a validation failed because of a this library bug. +/// // +/// // In either of those two cases, the only reasonable way out is to panic the thread. +/// _ => panic!("Field {} not found on type User", field_name), +/// } +/// } +/// } +/// ``` +pub trait GraphQLType: GraphQLValue +where + S: ScalarValue, +{ + /// Returns name of this [`GraphQLType`] to expose. + /// + /// This function will be called multiple times during schema construction. It must _not_ + /// perform any calculation and _always_ return the same value. + fn name(info: &Self::TypeInfo) -> Option<&str>; + + /// Returns [`MetaType`] representing this [`GraphQLType`]. + fn meta<'r>(info: &Self::TypeInfo, registry: &mut Registry<'r, S>) -> MetaType<'r, S> + where + S: 'r; +} + /// Resolver logic for queries'/mutations' selection set. /// Calls appropriate resolver method for each field or fragment found /// and then merges returned values into `result` or pushes errors to @@ -355,13 +411,14 @@ pub(crate) fn resolve_selection_set_into( result: &mut Object, ) -> bool where - T: GraphQLType + ?Sized, + T: GraphQLValue + ?Sized, S: ScalarValue, { let meta_type = executor .schema() .concrete_type_by_name( - T::name(info) + instance + .type_name(info) .expect("Resolving named type's selection set") .as_ref(), ) diff --git a/juniper/src/types/containers.rs b/juniper/src/types/containers.rs index 589624028..330bdb199 100644 --- a/juniper/src/types/containers.rs +++ b/juniper/src/types/containers.rs @@ -2,7 +2,10 @@ use crate::{ ast::{FromInputValue, InputValue, Selection, ToInputValue}, executor::{ExecutionResult, Executor, Registry}, schema::meta::MetaType, - types::{async_await::GraphQLTypeAsync, base::GraphQLType}, + types::{ + async_await::GraphQLValueAsync, + base::{GraphQLType, GraphQLValue}, + }, value::{ScalarValue, Value}, }; @@ -11,10 +14,7 @@ where S: ScalarValue, T: GraphQLType, { - type Context = CtxT; - type TypeInfo = T::TypeInfo; - - fn name(_: &T::TypeInfo) -> Option<&str> { + fn name(_: &T::TypeInfo) -> Option<&'static str> { None } @@ -24,6 +24,19 @@ where { registry.build_nullable_type::(info).into_meta() } +} + +impl GraphQLValue for Option +where + S: ScalarValue, + T: GraphQLValue, +{ + type Context = CtxT; + type TypeInfo = T::TypeInfo; + + fn type_name(&self, _: &T::TypeInfo) -> Option<&'static str> { + None + } fn resolve( &self, @@ -38,9 +51,9 @@ where } } -impl GraphQLTypeAsync for Option +impl GraphQLValueAsync for Option where - T: GraphQLTypeAsync, + T: GraphQLValueAsync, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -48,7 +61,7 @@ where fn resolve_async<'a>( &'a self, info: &'a Self::TypeInfo, - _selection_set: Option<&'a [Selection]>, + _: Option<&'a [Selection]>, executor: &'a Executor, ) -> crate::BoxFuture<'a, ExecutionResult> { let f = async move { @@ -93,10 +106,7 @@ where T: GraphQLType, S: ScalarValue, { - type Context = CtxT; - type TypeInfo = T::TypeInfo; - - fn name(_: &T::TypeInfo) -> Option<&str> { + fn name(_: &T::TypeInfo) -> Option<&'static str> { None } @@ -106,6 +116,19 @@ where { registry.build_list_type::(info).into_meta() } +} + +impl GraphQLValue for Vec +where + T: GraphQLValue, + S: ScalarValue, +{ + type Context = CtxT; + type TypeInfo = T::TypeInfo; + + fn type_name(&self, _: &T::TypeInfo) -> Option<&'static str> { + None + } fn resolve( &self, @@ -117,9 +140,9 @@ where } } -impl GraphQLTypeAsync for Vec +impl GraphQLValueAsync for Vec where - T: GraphQLTypeAsync, + T: GraphQLValueAsync, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -127,7 +150,7 @@ where fn resolve_async<'a>( &'a self, info: &'a Self::TypeInfo, - _selection_set: Option<&'a [Selection]>, + _: Option<&'a [Selection]>, executor: &'a Executor, ) -> crate::BoxFuture<'a, ExecutionResult> { let f = resolve_into_list_async(executor, info, self.iter()); @@ -172,10 +195,7 @@ where S: ScalarValue, T: GraphQLType, { - type Context = CtxT; - type TypeInfo = T::TypeInfo; - - fn name(_: &T::TypeInfo) -> Option<&str> { + fn name(_: &T::TypeInfo) -> Option<&'static str> { None } @@ -185,6 +205,19 @@ where { registry.build_list_type::(info).into_meta() } +} + +impl GraphQLValue for [T] +where + S: ScalarValue, + T: GraphQLValue, +{ + type Context = CtxT; + type TypeInfo = T::TypeInfo; + + fn type_name(&self, _: &T::TypeInfo) -> Option<&'static str> { + None + } fn resolve( &self, @@ -196,9 +229,9 @@ where } } -impl GraphQLTypeAsync for [T] +impl GraphQLValueAsync for [T] where - T: GraphQLTypeAsync, + T: GraphQLValueAsync, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -206,7 +239,7 @@ where fn resolve_async<'a>( &'a self, info: &'a Self::TypeInfo, - _selection_set: Option<&'a [Selection]>, + _: Option<&'a [Selection]>, executor: &'a Executor, ) -> crate::BoxFuture<'a, ExecutionResult> { let f = resolve_into_list_async(executor, info, self.iter()); @@ -232,7 +265,7 @@ fn resolve_into_list<'t, S, T, I>( where S: ScalarValue, I: Iterator + ExactSizeIterator, - T: GraphQLType + ?Sized + 't, + T: GraphQLValue + ?Sized + 't, { let stop_on_null = executor .current_type() @@ -261,7 +294,7 @@ async fn resolve_into_list_async<'a, 't, S, T, I>( where S: ScalarValue + Send + Sync, I: Iterator + ExactSizeIterator, - T: GraphQLTypeAsync + ?Sized + 't, + T: GraphQLValueAsync + ?Sized + 't, T::TypeInfo: Send + Sync, T::Context: Send + Sync, { diff --git a/juniper/src/types/pointers.rs b/juniper/src/types/pointers.rs index 68274fad3..6cf6ca84b 100644 --- a/juniper/src/types/pointers.rs +++ b/juniper/src/types/pointers.rs @@ -1,12 +1,12 @@ -use std::{fmt::Debug, sync::Arc}; +use std::{fmt, sync::Arc}; use crate::{ ast::{FromInputValue, InputValue, Selection, ToInputValue}, executor::{ExecutionResult, Executor, Registry}, schema::meta::MetaType, types::{ - async_await::GraphQLTypeAsync, - base::{Arguments, GraphQLType}, + async_await::GraphQLValueAsync, + base::{Arguments, GraphQLType, GraphQLValue}, }, value::ScalarValue, BoxFuture, @@ -17,9 +17,6 @@ where S: ScalarValue, T: GraphQLType + ?Sized, { - type Context = CtxT; - type TypeInfo = T::TypeInfo; - fn name(info: &T::TypeInfo) -> Option<&str> { T::name(info) } @@ -30,6 +27,19 @@ where { T::meta(info, registry) } +} + +impl GraphQLValue for Box +where + S: ScalarValue, + T: GraphQLValue + ?Sized, +{ + type Context = CtxT; + type TypeInfo = T::TypeInfo; + + fn type_name<'i>(&self, info: &'i T::TypeInfo) -> Option<&'i str> { + (**self).type_name(info) + } fn resolve_into_type( &self, @@ -61,9 +71,9 @@ where } } -impl crate::GraphQLTypeAsync for Box +impl GraphQLValueAsync for Box where - T: GraphQLTypeAsync + ?Sized, + T: GraphQLValueAsync + ?Sized, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -93,7 +103,7 @@ where impl ToInputValue for Box where - S: Debug, + S: fmt::Debug, T: ToInputValue, { fn to_input_value(&self) -> InputValue { @@ -106,9 +116,6 @@ where S: ScalarValue, T: GraphQLType + ?Sized, { - type Context = CtxT; - type TypeInfo = T::TypeInfo; - fn name(info: &T::TypeInfo) -> Option<&str> { T::name(info) } @@ -119,6 +126,19 @@ where { T::meta(info, registry) } +} + +impl<'e, S, T, CtxT> GraphQLValue for &'e T +where + S: ScalarValue, + T: GraphQLValue + ?Sized, +{ + type Context = CtxT; + type TypeInfo = T::TypeInfo; + + fn type_name<'i>(&self, info: &'i T::TypeInfo) -> Option<&'i str> { + (**self).type_name(info) + } fn resolve_into_type( &self, @@ -150,10 +170,10 @@ where } } -impl<'e, S, T> GraphQLTypeAsync for &'e T +impl<'e, S, T> GraphQLValueAsync for &'e T where S: ScalarValue + Send + Sync, - T: GraphQLTypeAsync + ?Sized, + T: GraphQLValueAsync + ?Sized, T::TypeInfo: Send + Sync, T::Context: Send + Sync, { @@ -164,7 +184,7 @@ where arguments: &'b Arguments, executor: &'b Executor, ) -> BoxFuture<'b, ExecutionResult> { - GraphQLTypeAsync::resolve_field_async(&**self, info, field_name, arguments, executor) + (**self).resolve_field_async(info, field_name, arguments, executor) } fn resolve_async<'a>( @@ -173,13 +193,13 @@ where selection_set: Option<&'a [Selection]>, executor: &'a Executor, ) -> BoxFuture<'a, ExecutionResult> { - GraphQLTypeAsync::resolve_async(&**self, info, selection_set, executor) + (**self).resolve_async(info, selection_set, executor) } } impl<'a, T, S> ToInputValue for &'a T where - S: Debug, + S: fmt::Debug, T: ToInputValue, { fn to_input_value(&self) -> InputValue { @@ -192,9 +212,6 @@ where S: ScalarValue, T: GraphQLType + ?Sized, { - type Context = T::Context; - type TypeInfo = T::TypeInfo; - fn name(info: &T::TypeInfo) -> Option<&str> { T::name(info) } @@ -205,6 +222,19 @@ where { T::meta(info, registry) } +} + +impl GraphQLValue for Arc +where + S: ScalarValue, + T: GraphQLValue + ?Sized, +{ + type Context = T::Context; + type TypeInfo = T::TypeInfo; + + fn type_name<'i>(&self, info: &'i T::TypeInfo) -> Option<&'i str> { + (**self).type_name(info) + } fn resolve_into_type( &self, @@ -236,12 +266,12 @@ where } } -impl<'e, S, T> GraphQLTypeAsync for Arc +impl<'e, S, T> GraphQLValueAsync for Arc where S: ScalarValue + Send + Sync, - T: GraphQLTypeAsync + ?Sized, - >::TypeInfo: Send + Sync, - >::Context: Send + Sync, + T: GraphQLValueAsync + ?Sized, + >::TypeInfo: Send + Sync, + >::Context: Send + Sync, { fn resolve_async<'a>( &'a self, @@ -255,7 +285,7 @@ where impl ToInputValue for Arc where - S: Debug, + S: fmt::Debug, T: ToInputValue, { fn to_input_value(&self) -> InputValue { diff --git a/juniper/src/types/scalars.rs b/juniper/src/types/scalars.rs index a2963c935..95157169a 100644 --- a/juniper/src/types/scalars.rs +++ b/juniper/src/types/scalars.rs @@ -1,12 +1,17 @@ +use std::{char, convert::From, marker::PhantomData, ops::Deref, rc::Rc, thread::JoinHandle, u32}; + use serde::{Deserialize, Serialize}; -use std::{char, convert::From, marker::PhantomData, ops::Deref, u32}; use crate::{ ast::{InputValue, Selection, ToInputValue}, executor::{ExecutionResult, Executor, Registry}, parser::{LexerError, ParseError, ScalarToken, Token}, schema::meta::MetaType, - types::base::GraphQLType, + types::{ + async_await::GraphQLValueAsync, + base::{GraphQLType, GraphQLValue}, + subscriptions::GraphQLSubscriptionValue, + }, value::{ParseScalarResult, ScalarValue, Value}, }; @@ -196,10 +201,7 @@ impl GraphQLType for str where S: ScalarValue, { - type Context = (); - type TypeInfo = (); - - fn name(_: &()) -> Option<&str> { + fn name(_: &()) -> Option<&'static str> { Some("String") } @@ -209,6 +211,18 @@ where { registry.build_scalar_type::(&()).into_meta() } +} + +impl GraphQLValue for str +where + S: ScalarValue, +{ + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + >::name(info) + } fn resolve( &self, @@ -220,7 +234,7 @@ where } } -impl crate::GraphQLTypeAsync for str +impl GraphQLValueAsync for str where S: ScalarValue + Send + Sync, { @@ -325,30 +339,24 @@ where /// If you instantiate `RootNode` with this as the mutation, no mutation will be /// generated for the schema. #[derive(Debug)] -pub struct EmptyMutation { - phantom: PhantomData, -} +pub struct EmptyMutation(PhantomData>>); + +// `EmptyMutation` doesn't use `T`, so should be `Send` and `Sync` even when `T` is not. +crate::sa::assert_impl_all!(EmptyMutation>: Send, Sync); impl EmptyMutation { /// Construct a new empty mutation - pub fn new() -> EmptyMutation { - EmptyMutation { - phantom: PhantomData, - } + #[inline] + pub fn new() -> Self { + Self(PhantomData) } } -// This is safe because `T` is never used. -unsafe impl Send for EmptyMutation {} - impl GraphQLType for EmptyMutation where S: ScalarValue, { - type Context = T; - type TypeInfo = (); - - fn name(_: &()) -> Option<&str> { + fn name(_: &()) -> Option<&'static str> { Some("_EmptyMutation") } @@ -360,21 +368,30 @@ where } } -impl crate::GraphQLTypeAsync for EmptyMutation +impl GraphQLValue for EmptyMutation +where + S: ScalarValue, +{ + type Context = T; + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + >::name(info) + } +} + +impl GraphQLValueAsync for EmptyMutation where S: ScalarValue + Send + Sync, - Self: GraphQLType + Send + Sync, Self::TypeInfo: Send + Sync, Self::Context: Send + Sync, - T: Send + Sync, { } impl Default for EmptyMutation { + #[inline] fn default() -> Self { - Self { - phantom: PhantomData, - } + Self::new() } } @@ -382,19 +399,16 @@ impl Default for EmptyMutation { /// /// If you instantiate `RootNode` with this as the subscription, /// no subscriptions will be generated for the schema. -pub struct EmptySubscription { - phantom: PhantomData, -} +pub struct EmptySubscription(PhantomData>>); -// This is safe due to never using `T`. -unsafe impl Send for EmptySubscription {} +// `EmptySubscription` doesn't use `T`, so should be `Send` and `Sync` even when `T` is not. +crate::sa::assert_impl_all!(EmptySubscription>: Send, Sync); impl EmptySubscription { /// Construct a new empty subscription + #[inline] pub fn new() -> Self { - EmptySubscription { - phantom: PhantomData, - } + Self(PhantomData) } } @@ -402,10 +416,7 @@ impl GraphQLType for EmptySubscription where S: ScalarValue, { - type Context = T; - type TypeInfo = (); - - fn name(_: &()) -> Option<&str> { + fn name(_: &()) -> Option<&'static str> { Some("_EmptySubscription") } @@ -417,21 +428,30 @@ where } } -impl crate::GraphQLSubscriptionType for EmptySubscription +impl GraphQLValue for EmptySubscription +where + S: ScalarValue, +{ + type Context = T; + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + >::name(info) + } +} + +impl GraphQLSubscriptionValue for EmptySubscription where S: ScalarValue + Send + Sync + 'static, - Self: GraphQLType + Send + Sync, Self::TypeInfo: Send + Sync, Self::Context: Send + Sync, - T: Send + Sync, { } impl Default for EmptySubscription { + #[inline] fn default() -> Self { - Self { - phantom: PhantomData, - } + Self::new() } } diff --git a/juniper/src/types/subscriptions.rs b/juniper/src/types/subscriptions.rs index 050769cd9..362f2f1ad 100644 --- a/juniper/src/types/subscriptions.rs +++ b/juniper/src/types/subscriptions.rs @@ -1,9 +1,9 @@ use crate::{ http::{GraphQLRequest, GraphQLResponse}, parser::Spanning, - types::base::{is_excluded, merge_key_into}, - Arguments, BoxFuture, Executor, FieldError, GraphQLType, Object, ScalarValue, Selection, Value, - ValuesStream, + types::base::{is_excluded, merge_key_into, GraphQLType, GraphQLValue}, + Arguments, BoxFuture, DefaultScalarValue, Executor, FieldError, Object, ScalarValue, Selection, + Value, ValuesStream, }; /// Global subscription coordinator trait. @@ -58,23 +58,24 @@ where /// server integration crates. pub trait SubscriptionConnection<'a, S>: futures::Stream> {} -/** - This trait adds resolver logic with asynchronous subscription execution logic - on GraphQL types. It should be used with `GraphQLType` in order to implement - subscription resolvers on GraphQL objects. - - Subscription-related convenience macros expand into an implementation of this - trait and `GraphQLType` for the given type. - - See trait methods for more detailed explanation on how this trait works. -*/ -pub trait GraphQLSubscriptionType: GraphQLType + Send + Sync +/// Extension of [`GraphQLValue`] trait with asynchronous [subscription][1] execution logic. +/// It should be used with [`GraphQLValue`] in order to implement [subscription][1] resolvers on +/// [GraphQL objects][2]. +/// +/// [Subscription][1]-related convenience macros expand into an implementation of this trait and +/// [`GraphQLValue`] for the given type. +/// +/// See trait methods for more detailed explanation on how this trait works. +/// +/// [1]: https://spec.graphql.org/June2018/#sec-Subscription +/// [2]: https://spec.graphql.org/June2018/#sec-Objects +pub trait GraphQLSubscriptionValue: GraphQLValue + Send + Sync where Self::Context: Send + Sync, Self::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, { - /// Resolve into `Value` + /// Resolves into `Value`. /// /// ## Default implementation /// @@ -109,7 +110,7 @@ where /// This method is called by Self's `resolve_into_stream` default /// implementation every time any field is found in selection set. /// - /// It replaces `GraphQLType::resolve_field`. + /// It replaces `GraphQLValue::resolve_field`. /// Unlike `resolve_field`, which resolves each field into a single /// `Value`, this method resolves each field into /// `Value>`. @@ -138,7 +139,7 @@ where /// This method is called by Self's `resolve_into_stream` default /// implementation every time any fragment is found in selection set. /// - /// It replaces `GraphQLType::resolve_into_type`. + /// It replaces `GraphQLValue::resolve_into_type`. /// Unlike `resolve_into_type`, which resolves each fragment /// a single `Value`, this method resolves each fragment into /// `Value>`. @@ -160,7 +161,7 @@ where 'res: 'f, { Box::pin(async move { - if Self::name(info) == Some(type_name) { + if self.type_name(info) == Some(type_name) { self.resolve_into_stream(info, executor).await } else { panic!("resolve_into_type_stream must be implemented"); @@ -169,6 +170,32 @@ where } } +crate::sa::assert_obj_safe!(GraphQLSubscriptionValue); + +/// Extension of [`GraphQLType`] trait with asynchronous [subscription][1] execution logic. +/// +/// It's automatically implemented for [`GraphQLSubscriptionValue`] and [`GraphQLType`] +/// implementors, so doesn't require manual or code-generated implementation. +/// +/// [1]: https://spec.graphql.org/June2018/#sec-Subscription +pub trait GraphQLSubscriptionType: + GraphQLSubscriptionValue + GraphQLType +where + Self::Context: Send + Sync, + Self::TypeInfo: Send + Sync, + S: ScalarValue + Send + Sync, +{ +} + +impl GraphQLSubscriptionType for T +where + T: GraphQLSubscriptionValue + GraphQLType, + T::Context: Send + Sync, + T::TypeInfo: Send + Sync, + S: ScalarValue + Send + Sync, +{ +} + /// Wrapper function around `resolve_selection_set_into_stream_recursive`. /// This wrapper is necessary because async fns can not be recursive. /// Panics if executor's current selection set is None. @@ -184,7 +211,7 @@ where 'e: 'fut, 'ref_e: 'fut, 'res: 'fut, - T: GraphQLSubscriptionType + ?Sized, + T: GraphQLSubscriptionValue + ?Sized, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -203,7 +230,7 @@ async fn resolve_selection_set_into_stream_recursive<'i, 'inf, 'ref_e, 'e, 'res, executor: &'ref_e Executor<'ref_e, 'e, CtxT, S>, ) -> Value> where - T: GraphQLSubscriptionType + Send + Sync + ?Sized, + T: GraphQLSubscriptionValue + Send + Sync + ?Sized, T::TypeInfo: Send + Sync, S: ScalarValue + Send + Sync, CtxT: Send + Sync, @@ -218,7 +245,8 @@ where let meta_type = executor .schema() .concrete_type_by_name( - T::name(info) + instance + .type_name(info) .expect("Resolving named type's selection set") .as_ref(), ) diff --git a/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs b/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs index 549375513..b693ad287 100644 --- a/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs +++ b/juniper/src/validation/rules/overlapping_fields_can_be_merged.rs @@ -1,3 +1,5 @@ +use std::{borrow::Borrow, cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash}; + use crate::{ ast::{Arguments, Definition, Document, Field, Fragment, FragmentSpread, Selection, Type}, parser::{SourcePosition, Spanning}, @@ -5,7 +7,6 @@ use crate::{ validation::{ValidatorContext, Visitor}, value::ScalarValue, }; -use std::{borrow::Borrow, cell::RefCell, collections::HashMap, fmt::Debug, hash::Hash}; #[derive(Debug)] struct Conflict(ConflictReason, Vec, Vec); @@ -741,7 +742,7 @@ mod tests { executor::Registry, schema::meta::MetaType, types::{ - base::GraphQLType, + base::{GraphQLType, GraphQLValue}, scalars::{EmptyMutation, EmptySubscription, ID}, }, }; @@ -1380,9 +1381,6 @@ mod tests { where S: ScalarValue, { - type Context = (); - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { Some("SomeBox") } @@ -1401,13 +1399,22 @@ mod tests { } } - impl GraphQLType for StringBox + impl GraphQLValue for SomeBox where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for StringBox + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("StringBox") } @@ -1432,13 +1439,22 @@ mod tests { } } - impl GraphQLType for IntBox + impl GraphQLValue for StringBox where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for IntBox + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("IntBox") } @@ -1463,13 +1479,22 @@ mod tests { } } - impl GraphQLType for NonNullStringBox1 + impl GraphQLValue for IntBox where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for NonNullStringBox1 + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("NonNullStringBox1") } @@ -1484,13 +1509,22 @@ mod tests { } } - impl GraphQLType for NonNullStringBox1Impl + impl GraphQLValue for NonNullStringBox1 where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for NonNullStringBox1Impl + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("NonNullStringBox1Impl") } @@ -1515,13 +1549,22 @@ mod tests { } } - impl GraphQLType for NonNullStringBox2 + impl GraphQLValue for NonNullStringBox1Impl where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for NonNullStringBox2 + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("NonNullStringBox2") } @@ -1536,13 +1579,22 @@ mod tests { } } - impl GraphQLType for NonNullStringBox2Impl + impl GraphQLValue for NonNullStringBox2 where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for NonNullStringBox2Impl + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("NonNullStringBox2Impl") } @@ -1567,13 +1619,22 @@ mod tests { } } - impl GraphQLType for Node + impl GraphQLValue for NonNullStringBox2Impl where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for Node + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("Node") } @@ -1591,13 +1652,22 @@ mod tests { } } - impl GraphQLType for Edge + impl GraphQLValue for Node where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for Edge + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("Edge") } @@ -1612,13 +1682,22 @@ mod tests { } } - impl GraphQLType for Connection + impl GraphQLValue for Edge where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for Connection + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("Connection") } @@ -1633,13 +1712,22 @@ mod tests { } } - impl GraphQLType for QueryRoot + impl GraphQLValue for Connection where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + + impl GraphQLType for QueryRoot + where + S: ScalarValue, + { fn name(_: &()) -> Option<&'static str> { Some("QueryRoot") } @@ -1661,6 +1749,18 @@ mod tests { } } + impl GraphQLValue for QueryRoot + where + S: ScalarValue, + { + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } + } + #[test] fn conflicting_return_types_which_potentially_overlap() { expect_fails_rule_with_schema::<_, EmptyMutation<()>, _, _, DefaultScalarValue>( diff --git a/juniper/src/validation/test_harness.rs b/juniper/src/validation/test_harness.rs index 07e87d781..53c3b53a4 100644 --- a/juniper/src/validation/test_harness.rs +++ b/juniper/src/validation/test_harness.rs @@ -8,7 +8,10 @@ use crate::{ meta::{EnumValue, MetaType}, model::{DirectiveLocation, DirectiveType, RootNode}, }, - types::{base::GraphQLType, scalars::ID}, + types::{ + base::{GraphQLType, GraphQLValue}, + scalars::ID, + }, validation::{visit, MultiVisitorNil, RuleError, ValidatorContext, Visitor}, value::ScalarValue, }; @@ -71,9 +74,6 @@ impl GraphQLType for Being where S: ScalarValue, { - type Context = (); - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { Some("Being") } @@ -90,13 +90,22 @@ where } } -impl GraphQLType for Pet +impl GraphQLValue for Being where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for Pet +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("Pet") } @@ -113,13 +122,22 @@ where } } -impl GraphQLType for Canine +impl GraphQLValue for Pet where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for Canine +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("Canine") } @@ -136,13 +154,22 @@ where } } -impl GraphQLType for DogCommand +impl GraphQLValue for Canine where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for DogCommand +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("DogCommand") } @@ -164,6 +191,18 @@ where } } +impl GraphQLValue for DogCommand +where + S: ScalarValue, +{ + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + impl FromInputValue for DogCommand where S: ScalarValue, @@ -182,9 +221,6 @@ impl GraphQLType for Dog where S: ScalarValue, { - type Context = (); - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { Some("Dog") } @@ -223,13 +259,22 @@ where } } -impl GraphQLType for FurColor +impl GraphQLValue for Dog where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for FurColor +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("FurColor") } @@ -252,6 +297,18 @@ where } } +impl GraphQLValue for FurColor +where + S: ScalarValue, +{ + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + impl FromInputValue for FurColor where S: ScalarValue, @@ -271,9 +328,6 @@ impl GraphQLType for Cat where S: ScalarValue, { - type Context = (); - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { Some("Cat") } @@ -299,13 +353,22 @@ where } } -impl GraphQLType for CatOrDog +impl GraphQLValue for Cat where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for CatOrDog +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("CatOrDog") } @@ -320,13 +383,22 @@ where } } -impl GraphQLType for Intelligent +impl GraphQLValue for CatOrDog where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for Intelligent +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("Intelligent") } @@ -341,13 +413,22 @@ where } } -impl GraphQLType for Human +impl GraphQLValue for Intelligent where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for Human +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("Human") } @@ -374,13 +455,22 @@ where } } -impl GraphQLType for Alien +impl GraphQLValue for Human where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for Alien +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("Alien") } @@ -407,13 +497,22 @@ where } } -impl GraphQLType for DogOrHuman +impl GraphQLValue for Alien where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for DogOrHuman +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("DogOrHuman") } @@ -428,13 +527,22 @@ where } } -impl GraphQLType for HumanOrAlien +impl GraphQLValue for DogOrHuman where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for HumanOrAlien +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("HumanOrAlien") } @@ -449,13 +557,22 @@ where } } -impl GraphQLType for ComplexInput +impl GraphQLValue for HumanOrAlien where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for ComplexInput +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("ComplexInput") } @@ -478,6 +595,18 @@ where } } +impl GraphQLValue for ComplexInput +where + S: ScalarValue, +{ + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + impl FromInputValue for ComplexInput where S: ScalarValue, @@ -505,9 +634,6 @@ impl GraphQLType for ComplicatedArgs where S: ScalarValue, { - type Context = (); - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { Some("ComplicatedArgs") } @@ -564,13 +690,22 @@ where } } -impl GraphQLType for QueryRoot +impl GraphQLValue for ComplicatedArgs where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for QueryRoot +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&'static str> { Some("QueryRoot") } @@ -597,13 +732,22 @@ where } } -impl GraphQLType for MutationRoot +impl GraphQLValue for QueryRoot where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for MutationRoot +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&str> { Some("MutationRoot") } @@ -627,13 +771,22 @@ where } } -impl GraphQLType for SubscriptionRoot +impl GraphQLValue for MutationRoot where S: ScalarValue, { type Context = (); type TypeInfo = (); + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + +impl GraphQLType for SubscriptionRoot +where + S: ScalarValue, +{ fn name(_: &()) -> Option<&str> { Some("SubscriptionRoot") } @@ -648,6 +801,18 @@ where } } +impl GraphQLValue for SubscriptionRoot +where + S: ScalarValue, +{ + type Context = (); + type TypeInfo = (); + + fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> { + ::name(info) + } +} + pub fn validate<'a, Q, M, Sub, V, F, S>( r: Q, m: M, diff --git a/juniper/src/value/scalar.rs b/juniper/src/value/scalar.rs index f198983c1..12a532155 100644 --- a/juniper/src/value/scalar.rs +++ b/juniper/src/value/scalar.rs @@ -190,26 +190,26 @@ pub trait ScalarValue: /// Convert the given scalar value into an integer value /// - /// This function is used for implementing `GraphQLType` for `i32` for all + /// This function is used for implementing `GraphQLValue` for `i32` for all /// scalar values. Implementations should convert all supported integer /// types with 32 bit or less to an integer if requested. fn as_int(&self) -> Option; /// Convert the given scalar value into a string value /// - /// This function is used for implementing `GraphQLType` for `String` for all + /// This function is used for implementing `GraphQLValue` for `String` for all /// scalar values fn as_string(&self) -> Option; /// Convert the given scalar value into a string value /// - /// This function is used for implementing `GraphQLType` for `String` for all + /// This function is used for implementing `GraphQLValue` for `String` for all /// scalar values fn as_str(&self) -> Option<&str>; /// Convert the given scalar value into a float value /// - /// This function is used for implementing `GraphQLType` for `f64` for all + /// This function is used for implementing `GraphQLValue` for `f64` for all /// scalar values. Implementations should convert all supported integer /// types with 64 bit or less and all floating point values with 64 bit or /// less to a float if requested. @@ -217,7 +217,7 @@ pub trait ScalarValue: /// Convert the given scalar value into a boolean value /// - /// This function is used for implementing `GraphQLType` for `bool` for all + /// This function is used for implementing `GraphQLValue` for `bool` for all /// scalar values. fn as_boolean(&self) -> Option; } diff --git a/juniper_codegen/src/derive_scalar_value.rs b/juniper_codegen/src/derive_scalar_value.rs index c951b1e5c..f7db744d5 100644 --- a/juniper_codegen/src/derive_scalar_value.rs +++ b/juniper_codegen/src/derive_scalar_value.rs @@ -112,11 +112,10 @@ fn impl_scalar_struct( }; let _async = quote!( - - impl <__S> #crate_name::GraphQLTypeAsync<__S> for #ident + impl <__S> #crate_name::GraphQLValueAsync<__S> for #ident where __S: #crate_name::ScalarValue + Send + Sync, - Self: #crate_name::GraphQLType<__S> + Send + Sync, + Self: Send + Sync, Self::Context: Send + Sync, Self::TypeInfo: Send + Sync, { @@ -126,9 +125,8 @@ fn impl_scalar_struct( selection_set: Option<&'a [#crate_name::Selection<__S>]>, executor: &'a #crate_name::Executor, ) -> #crate_name::BoxFuture<'a, #crate_name::ExecutionResult<__S>> { - use #crate_name::GraphQLType; use #crate_name::futures::future; - let v = self.resolve(info, selection_set, executor); + let v = #crate_name::GraphQLValue::resolve(self, info, selection_set, executor); Box::pin(future::ready(v)) } } @@ -141,10 +139,7 @@ fn impl_scalar_struct( where S: #crate_name::ScalarValue, { - type Context = (); - type TypeInfo = (); - - fn name(_: &Self::TypeInfo) -> Option<&str> { + fn name(_: &Self::TypeInfo) -> Option<&'static str> { Some(#name) } @@ -159,6 +154,18 @@ fn impl_scalar_struct( #description .into_meta() } + } + + impl #crate_name::GraphQLValue for #ident + where + S: #crate_name::ScalarValue, + { + type Context = (); + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } fn resolve( &self, @@ -166,7 +173,7 @@ fn impl_scalar_struct( selection: Option<&[#crate_name::Selection]>, executor: &#crate_name::Executor, ) -> #crate_name::ExecutionResult { - #crate_name::GraphQLType::resolve(&self.0, info, selection, executor) + #crate_name::GraphQLValue::resolve(&self.0, info, selection, executor) } } diff --git a/juniper_codegen/src/graphql_union/mod.rs b/juniper_codegen/src/graphql_union/mod.rs index af06d112a..10112b009 100644 --- a/juniper_codegen/src/graphql_union/mod.rs +++ b/juniper_codegen/src/graphql_union/mod.rs @@ -524,10 +524,7 @@ impl ToTokens for UnionDefinition { impl#ext_impl_generics #crate_path::GraphQLType<#scalar> for #ty_full #where_clause { - type Context = #context; - type TypeInfo = (); - - fn name(_ : &Self::TypeInfo) -> Option<&str> { + fn name(_ : &Self::TypeInfo) -> Option<&'static str> { Some(#name) } @@ -544,6 +541,20 @@ impl ToTokens for UnionDefinition { #description .into_meta() } + } + }; + + let value_impl = quote! { + #[automatically_derived] + impl#ext_impl_generics #crate_path::GraphQLValue<#scalar> for #ty_full + #where_clause + { + type Context = #context; + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } fn concrete_type_name( &self, @@ -575,9 +586,9 @@ impl ToTokens for UnionDefinition { } }; - let async_type_impl = quote! { + let value_async_impl = quote! { #[automatically_derived] - impl#ext_impl_generics #crate_path::GraphQLTypeAsync<#scalar> for #ty_full + impl#ext_impl_generics #crate_path::GraphQLValueAsync<#scalar> for #ty_full #where_async { fn resolve_into_type_async<'b>( @@ -621,7 +632,13 @@ impl ToTokens for UnionDefinition { } }; - into.append_all(&[union_impl, output_type_impl, type_impl, async_type_impl]); + into.append_all(&[ + union_impl, + output_type_impl, + type_impl, + value_impl, + value_async_impl, + ]); } } diff --git a/juniper_codegen/src/impl_scalar.rs b/juniper_codegen/src/impl_scalar.rs index fc449aa8a..2b6ad6d37 100644 --- a/juniper_codegen/src/impl_scalar.rs +++ b/juniper_codegen/src/impl_scalar.rs @@ -250,10 +250,10 @@ pub fn build_scalar( }; let _async = quote!( - impl#async_generic_type_decl #crate_name::GraphQLTypeAsync<#async_generic_type> for #impl_for_type + impl#async_generic_type_decl #crate_name::GraphQLValueAsync<#async_generic_type> for #impl_for_type where #async_generic_type: #crate_name::ScalarValue + Send + Sync, - Self: #crate_name::GraphQLType<#async_generic_type> + Send + Sync, + Self: Send + Sync, Self::Context: Send + Sync, Self::TypeInfo: Send + Sync, { @@ -263,9 +263,8 @@ pub fn build_scalar( selection_set: Option<&'a [#crate_name::Selection<#async_generic_type>]>, executor: &'a #crate_name::Executor, ) -> #crate_name::BoxFuture<'a, #crate_name::ExecutionResult<#async_generic_type>> { - use #crate_name::GraphQLType; use #crate_name::futures::future; - let v = self.resolve(info, selection_set, executor); + let v = #crate_name::GraphQLValue::resolve(self, info, selection_set, executor); Box::pin(future::ready(v)) } } @@ -283,10 +282,7 @@ pub fn build_scalar( impl#generic_type_decl #crate_name::GraphQLType<#generic_type> for #impl_for_type #generic_type_bound { - type Context = (); - type TypeInfo = (); - - fn name(_: &Self::TypeInfo) -> Option<&str> { + fn name(_: &Self::TypeInfo) -> Option<&'static str> { Some(#name) } @@ -301,6 +297,17 @@ pub fn build_scalar( #description .into_meta() } + } + + impl#generic_type_decl #crate_name::GraphQLValue<#generic_type> for #impl_for_type + #generic_type_bound + { + type Context = (); + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } fn resolve( &self, diff --git a/juniper_codegen/src/util/mod.rs b/juniper_codegen/src/util/mod.rs index 03395b262..7869a1072 100644 --- a/juniper_codegen/src/util/mod.rs +++ b/juniper_codegen/src/util/mod.rs @@ -949,7 +949,7 @@ impl GraphQLTypeDefiniton { // FIXME: add where clause for interfaces. quote!( - impl#impl_generics #juniper_crate_name::GraphQLTypeAsync<#scalar> for #ty #type_generics_tokens + impl#impl_generics #juniper_crate_name::GraphQLValueAsync<#scalar> for #ty #type_generics_tokens #where_async { fn resolve_field_async<'b>( @@ -1006,10 +1006,7 @@ impl GraphQLTypeDefiniton { impl#impl_generics #juniper_crate_name::GraphQLType<#scalar> for #ty #type_generics_tokens #where_clause { - type Context = #context; - type TypeInfo = (); - - fn name(_: &Self::TypeInfo) -> Option<&str> { + fn name(_: &Self::TypeInfo) -> Option<&'static str> { Some(#name) } @@ -1027,6 +1024,17 @@ impl GraphQLTypeDefiniton { #interfaces; meta.into_meta() } + } + + impl#impl_generics #juniper_crate_name::GraphQLValue<#scalar> for #ty #type_generics_tokens + #where_clause + { + type Context = #context; + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } #[allow(unused_variables)] #[allow(unused_mut)] @@ -1241,10 +1249,7 @@ impl GraphQLTypeDefiniton { impl#impl_generics #juniper_crate_name::GraphQLType<#scalar> for #ty #type_generics_tokens #where_clause { - type Context = #context; - type TypeInfo = (); - - fn name(_: &Self::TypeInfo) -> Option<&str> { + fn name(_: &Self::TypeInfo) -> Option<&'static str> { Some(#name) } @@ -1262,6 +1267,17 @@ impl GraphQLTypeDefiniton { #interfaces; meta.into_meta() } + } + + impl#impl_generics #juniper_crate_name::GraphQLValue<#scalar> for #ty #type_generics_tokens + #where_clause + { + type Context = #context; + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } fn resolve_field( &self, @@ -1281,7 +1297,7 @@ impl GraphQLTypeDefiniton { ); let subscription_implementation = quote!( - impl#impl_generics #juniper_crate_name::GraphQLSubscriptionType<#scalar> for #ty #type_generics_tokens + impl#impl_generics #juniper_crate_name::GraphQLSubscriptionValue<#scalar> for #ty #type_generics_tokens #where_clause { #[allow(unused_variables)] @@ -1316,7 +1332,7 @@ impl GraphQLTypeDefiniton { match field_name { #( #resolve_matches_async )* _ => { - panic!("Field {} not found on type {}", field_name, "GraphQLSubscriptionType"); + panic!("Field {} not found on type {}", field_name, "GraphQLSubscriptionValue"); } } } @@ -1438,7 +1454,7 @@ impl GraphQLTypeDefiniton { where_async.predicates.push(parse_quote!(Self: Send + Sync)); let _async = quote!( - impl#impl_generics #juniper_crate_name::GraphQLTypeAsync<#scalar> for #ty + impl#impl_generics #juniper_crate_name::GraphQLValueAsync<#scalar> for #ty #where_async { fn resolve_async<'a>( @@ -1447,7 +1463,7 @@ impl GraphQLTypeDefiniton { selection_set: Option<&'a [#juniper_crate_name::Selection<#scalar>]>, executor: &'a #juniper_crate_name::Executor, ) -> #juniper_crate_name::BoxFuture<'a, #juniper_crate_name::ExecutionResult<#scalar>> { - use #juniper_crate_name::GraphQLType; + use #juniper_crate_name::GraphQLValue as _; use #juniper_crate_name::futures::future; let v = self.resolve(info, selection_set, executor); future::FutureExt::boxed(future::ready(v)) @@ -1465,9 +1481,6 @@ impl GraphQLTypeDefiniton { impl#impl_generics #juniper_crate_name::GraphQLType<#scalar> for #ty #where_clause { - type Context = #context; - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { Some(#name) } @@ -1484,6 +1497,17 @@ impl GraphQLTypeDefiniton { #description .into_meta() } + } + + impl#impl_generics #juniper_crate_name::GraphQLValue<#scalar> for #ty + #where_clause + { + type Context = #context; + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } fn resolve( &self, @@ -1685,7 +1709,7 @@ impl GraphQLTypeDefiniton { where_async.predicates.push(parse_quote!(Self: Send + Sync)); let async_type = quote!( - impl#impl_generics #juniper_crate_name::GraphQLTypeAsync<#scalar> for #ty #type_generics_tokens + impl#impl_generics #juniper_crate_name::GraphQLValueAsync<#scalar> for #ty #type_generics_tokens #where_async {} ); @@ -1708,9 +1732,6 @@ impl GraphQLTypeDefiniton { impl#impl_generics #juniper_crate_name::GraphQLType<#scalar> for #ty #type_generics_tokens #where_clause { - type Context = #context; - type TypeInfo = (); - fn name(_: &()) -> Option<&'static str> { Some(#name) } @@ -1730,6 +1751,17 @@ impl GraphQLTypeDefiniton { } } + impl#impl_generics #juniper_crate_name::GraphQLValue<#scalar> for #ty #type_generics_tokens + #where_clause + { + type Context = #context; + type TypeInfo = (); + + fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> { + >::name(info) + } + } + impl#impl_generics #juniper_crate_name::FromInputValue<#scalar> for #ty #type_generics_tokens #where_clause {