diff --git a/examples/warp_subscriptions/Cargo.toml b/examples/warp_subscriptions/Cargo.toml index da05cf99..5cdc12d6 100644 --- a/examples/warp_subscriptions/Cargo.toml +++ b/examples/warp_subscriptions/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] async-stream = "0.3" env_logger = "0.9" -futures = "0.3.1" +futures = "0.3" juniper = { path = "../../juniper" } juniper_graphql_ws = { path = "../../juniper_graphql_ws" } juniper_warp = { path = "../../juniper_warp", features = ["subscriptions"] } diff --git a/juniper/Cargo.toml b/juniper/Cargo.toml index ca5e24c6..bc0e030d 100644 --- a/juniper/Cargo.toml +++ b/juniper/Cargo.toml @@ -40,10 +40,10 @@ anyhow = { version = "1.0.32", default-features = false, optional = true } async-trait = "0.1.39" bigdecimal = { version = "0.3", optional = true } bson = { version = "2.4", features = ["chrono-0_4"], optional = true } -chrono = { version = "0.4", features = ["alloc"], default-features = false, optional = true } +chrono = { version = "0.4.20", features = ["alloc"], default-features = false, optional = true } chrono-tz = { version = "0.6", default-features = false, optional = true } fnv = "1.0.3" -futures = { version = "0.3.1", features = ["alloc"], default-features = false } +futures = { version = "0.3.22", features = ["alloc"], default-features = false } futures-enum = { version = "0.1.12", default-features = false } graphql-parser = { version = "0.4", optional = true } indexmap = { version = "1.0", features = ["serde-1"] } @@ -62,7 +62,7 @@ getrandom = { version = "0.2", features = ["js"] } [dev-dependencies] bencher = "0.1.2" -chrono = { version = "0.4", features = ["alloc"], default-features = false } +chrono = { version = "0.4.20", features = ["alloc"], default-features = false } pretty_assertions = "1.0.0" serde_json = "1.0.2" tokio = { version = "1.0", features = ["macros", "time", "rt-multi-thread"] } diff --git a/juniper/src/executor_tests/interfaces_unions.rs b/juniper/src/executor_tests/interfaces_unions.rs index 9b8ac746..c1cd3b43 100644 --- a/juniper/src/executor_tests/interfaces_unions.rs +++ b/juniper/src/executor_tests/interfaces_unions.rs @@ -96,9 +96,10 @@ mod interface { mod union { use crate::{ - graphql_object, GraphQLUnion, graphql_value, + graphql_object, graphql_value, schema::model::RootNode, types::scalars::{EmptyMutation, EmptySubscription}, + GraphQLUnion, }; #[derive(GraphQLUnion)] diff --git a/juniper/src/lib.rs b/juniper/src/lib.rs index 9271f8d4..9e54f70f 100644 --- a/juniper/src/lib.rs +++ b/juniper/src/lib.rs @@ -75,6 +75,7 @@ pub use crate::{ FromContext, IntoFieldError, IntoResolvable, LookAheadArgument, LookAheadMethods, LookAheadSelection, LookAheadValue, OwnedExecutor, Registry, ValuesStream, Variables, }, + extract::Extract, introspection::IntrospectionFormat, macros::helper::subscription::{ExtractTypeFromStream, IntoFieldResult}, parser::{ParseError, ScalarToken, Spanning}, @@ -95,7 +96,6 @@ pub use crate::{ }, validation::RuleError, value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, ScalarValue, Value}, - extract::Extract, }; /// An error that prevented query execution diff --git a/juniper/src/resolve/mod.rs b/juniper/src/resolve/mod.rs index cdab181c..3c782e92 100644 --- a/juniper/src/resolve/mod.rs +++ b/juniper/src/resolve/mod.rs @@ -5,7 +5,6 @@ use crate::{ reflect, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, IntoFieldError, Registry, Selection, }; -use juniper::resolve; pub trait Type<TypeInfo: ?Sized, ScalarValue, Behavior: ?Sized = behavior::Standard> { fn meta<'r, 'ti: 'r>( @@ -54,6 +53,12 @@ pub trait ValueAsync< ) -> BoxFuture<'r, ExecutionResult<ScalarValue>>; } +pub trait Resolvable<ScalarValue, Behavior: ?Sized = behavior::Standard> { + type Value; + + fn into_value(self) -> FieldResult<Self::Value, ScalarValue>; +} + pub trait ConcreteValue< TypeInfo: ?Sized, Context: ?Sized, @@ -204,75 +209,3 @@ pub trait InputValueAsRef<ScalarValue, Behavior: ?Sized = behavior::Standard> { pub trait ScalarToken<ScalarValue, Behavior: ?Sized = behavior::Standard> { fn parse_scalar_token(token: parser::ScalarToken<'_>) -> Result<ScalarValue, ParseError>; } - -/* -pub trait IntoResolvable< - ScalarValue, -> -{ - type Type; - - fn into_resolvable(self) -> FieldResult<Self::Type, ScalarValue>; -} - -impl<T, SV> IntoResolvable<SV> for T -where - T: crate::GraphQLValue<SV>, - SV: crate::ScalarValue, -{ - type Type = Self; - - fn into_resolvable(self) -> FieldResult<Self, SV> { - Ok(self) - } -} - -impl<T, E, SV> IntoResolvable<SV> for Result<T, E> -where - T: crate::GraphQLValue<SV>, - SV: crate::ScalarValue, - E: IntoFieldError<SV>, -{ - type Type = T; - - fn into_resolvable(self) -> FieldResult<Self::Type, SV> { - self.map_err(IntoFieldError::into_field_error) - } -} -*/ - -#[doc(hidden)] -pub trait IntoResolvable<S, T> -where - T: crate::GraphQLValue<S>, - S: crate::ScalarValue, -{ - type Type; - - #[doc(hidden)] - fn into_resolvable(self) -> FieldResult<T, S>; -} - -impl<'a, S, T> IntoResolvable<S, T> for T -where - T: crate::GraphQLValue<S>, - S: crate::ScalarValue, -{ - type Type = T; - - fn into_resolvable(self) -> FieldResult<T, S> { - Ok(self) - } -} - -impl<'a, S, T, E: IntoFieldError<S>> IntoResolvable<S, T> for Result<T, E> -where - S: crate::ScalarValue, - T: crate::GraphQLValue<S>, -{ - type Type = T; - - fn into_resolvable(self) -> FieldResult<T, S> { - self.map_err(IntoFieldError::into_field_error) - } -} diff --git a/juniper/src/types/arc.rs b/juniper/src/types/arc.rs index f8dffd7a..2d3a7500 100644 --- a/juniper/src/types/arc.rs +++ b/juniper/src/types/arc.rs @@ -6,7 +6,8 @@ use crate::{ graphql, meta::MetaType, parser::{ParseError, ScalarToken}, - reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection, + reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, Registry, + Selection, }; impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Arc<T> @@ -79,6 +80,18 @@ where } } +impl<T, SV, BH> resolve::Resolvable<SV, BH> for Arc<T> +where + T: ?Sized, + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Arc<T> where T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized, diff --git a/juniper/src/types/array.rs b/juniper/src/types/array.rs index a05a1fde..ad181251 100644 --- a/juniper/src/types/array.rs +++ b/juniper/src/types/array.rs @@ -12,7 +12,7 @@ use crate::{ executor::{ExecutionResult, Executor, Registry}, graphql, reflect, resolve, schema::meta::MetaType, - BoxFuture, FieldError, IntoFieldError, Selection, + BoxFuture, FieldError, FieldResult, IntoFieldError, Selection, }; use super::iter; @@ -71,6 +71,17 @@ where } } +impl<T, SV, BH, const N: usize> resolve::Resolvable<SV, BH> for [T; N] +where + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<T, SV, BH, const N: usize> resolve::ToInputValue<SV, BH> for [T; N] where T: resolve::ToInputValue<SV, BH>, diff --git a/juniper/src/types/async_await.rs b/juniper/src/types/async_await.rs index 562bff7c..827a1d50 100644 --- a/juniper/src/types/async_await.rs +++ b/juniper/src/types/async_await.rs @@ -1,3 +1,5 @@ +use std::future; + use crate::{ ast::Selection, executor::{ExecutionResult, Executor}, @@ -254,7 +256,7 @@ where let is_non_null = meta_field.field_type.is_non_null(); let response_name = response_name.to_string(); - async_values.push(AsyncValueFuture::Field(async move { + async_values.push_back(AsyncValueFuture::Field(async move { // TODO: implement custom future type instead of // two-level boxing. let res = instance @@ -317,12 +319,12 @@ where if let Ok(Value::Object(obj)) = sub_result { for (k, v) in obj { - async_values.push(AsyncValueFuture::FragmentSpread(async move { - AsyncValue::Field(AsyncField { + async_values.push_back(AsyncValueFuture::FragmentSpread( + future::ready(AsyncValue::Field(AsyncField { name: k, value: Some(v), - }) - })); + })), + )); } } else if let Err(e) = sub_result { sub_exec.push_error_at(e, *start_pos); @@ -362,19 +364,19 @@ where if let Ok(Value::Object(obj)) = sub_result { for (k, v) in obj { - async_values.push(AsyncValueFuture::InlineFragment1(async move { - AsyncValue::Field(AsyncField { + async_values.push_back(AsyncValueFuture::InlineFragment1( + future::ready(AsyncValue::Field(AsyncField { name: k, value: Some(v), - }) - })); + })), + )); } } else if let Err(e) = sub_result { sub_exec.push_error_at(e, *start_pos); } } } else { - async_values.push(AsyncValueFuture::InlineFragment2(async move { + async_values.push_back(AsyncValueFuture::InlineFragment2(async move { let value = resolve_selection_set_into_async( instance, info, diff --git a/juniper/src/types/box.rs b/juniper/src/types/box.rs index 848e6363..c6f2fcb4 100644 --- a/juniper/src/types/box.rs +++ b/juniper/src/types/box.rs @@ -4,7 +4,8 @@ use crate::{ graphql, meta::MetaType, parser::{ParseError, ScalarToken}, - reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection, + reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, Registry, + Selection, }; impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Box<T> @@ -77,6 +78,18 @@ where } } +impl<T, SV, BH> resolve::Resolvable<SV, BH> for Box<T> +where + T: ?Sized, + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Box<T> where T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized, diff --git a/juniper/src/types/cow.rs b/juniper/src/types/cow.rs index 0a6fbfce..0701eb31 100644 --- a/juniper/src/types/cow.rs +++ b/juniper/src/types/cow.rs @@ -6,7 +6,8 @@ use crate::{ graphql, meta::MetaType, parser::{ParseError, ScalarToken}, - reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection, + reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, Registry, + Selection, }; impl<'me, T, TI, SV, BH> resolve::Type<TI, SV, BH> for Cow<'me, T> @@ -84,6 +85,18 @@ where } } +impl<'me, T, SV, BH> resolve::Resolvable<SV, BH> for Cow<'me, T> +where + T: ToOwned + ?Sized + 'me, + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Cow<'me, T> where T: resolve::ConcreteValue<TI, CX, SV, BH> + ToOwned + ?Sized + 'me, diff --git a/juniper/src/types/nullable.rs b/juniper/src/types/nullable.rs index 31d3f848..e2e6524b 100644 --- a/juniper/src/types/nullable.rs +++ b/juniper/src/types/nullable.rs @@ -15,7 +15,7 @@ use crate::{ base::{GraphQLType, GraphQLValue}, marker::IsInputType, }, - BoxFuture, ScalarValue, Selection, + BoxFuture, FieldResult, ScalarValue, Selection, }; /// [`Nullable`] wrapper allowing to distinguish between an implicit and @@ -330,6 +330,17 @@ where } } +impl<T, SV, BH> resolve::Resolvable<SV, BH> for Nullable<T> +where + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Nullable<T> where T: resolve::ToInputValue<SV, BH>, diff --git a/juniper/src/types/option.rs b/juniper/src/types/option.rs index 3f348de9..a999802d 100644 --- a/juniper/src/types/option.rs +++ b/juniper/src/types/option.rs @@ -7,7 +7,7 @@ use crate::{ executor::{ExecutionResult, Executor, Registry}, graphql, reflect, resolve, schema::meta::MetaType, - BoxFuture, Selection, + BoxFuture, FieldResult, Selection, }; impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Option<T> @@ -65,6 +65,17 @@ where } } +impl<T, SV, BH> resolve::Resolvable<SV, BH> for Option<T> +where + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Option<T> where T: resolve::ToInputValue<SV, BH>, diff --git a/juniper/src/types/rc.rs b/juniper/src/types/rc.rs index 9adf6db9..eddffd74 100644 --- a/juniper/src/types/rc.rs +++ b/juniper/src/types/rc.rs @@ -6,7 +6,8 @@ use crate::{ graphql, meta::MetaType, parser::{ParseError, ScalarToken}, - reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection, + reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, Registry, + Selection, }; impl<T, TI, SV, BH> resolve::Type<TI, SV, BH> for Rc<T> @@ -79,6 +80,18 @@ where } } +impl<T, SV, BH> resolve::Resolvable<SV, BH> for Rc<T> +where + T: ?Sized, + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for Rc<T> where T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized, diff --git a/juniper/src/types/ref.rs b/juniper/src/types/ref.rs index eaaf9441..def629f0 100644 --- a/juniper/src/types/ref.rs +++ b/juniper/src/types/ref.rs @@ -6,7 +6,8 @@ use crate::{ graphql, meta::MetaType, parser::{ParseError, ScalarToken}, - reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection, + reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, Registry, + Selection, }; impl<'me, T, TI, SV, BH> resolve::Type<TI, SV, BH> for &'me T @@ -79,6 +80,18 @@ where } } +impl<'me, T, SV, BH> resolve::Resolvable<SV, BH> for &'me T +where + T: ?Sized, + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for &'me T where T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized, diff --git a/juniper/src/types/ref_mut.rs b/juniper/src/types/ref_mut.rs index bf5334b2..d289e8d8 100644 --- a/juniper/src/types/ref_mut.rs +++ b/juniper/src/types/ref_mut.rs @@ -6,7 +6,8 @@ use crate::{ graphql, meta::MetaType, parser::{ParseError, ScalarToken}, - reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, Registry, Selection, + reflect, resolve, Arguments, BoxFuture, ExecutionResult, Executor, FieldResult, Registry, + Selection, }; impl<'me, T, TI, SV, BH> resolve::Type<TI, SV, BH> for &'me mut T @@ -79,6 +80,18 @@ where } } +impl<'me, T, SV, BH> resolve::Resolvable<SV, BH> for &'me mut T +where + T: ?Sized, + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<'me, T, TI, CX, SV, BH> resolve::ConcreteValue<TI, CX, SV, BH> for &'me mut T where T: resolve::ConcreteValue<TI, CX, SV, BH> + ?Sized, diff --git a/juniper/src/types/result.rs b/juniper/src/types/result.rs index 62d28d10..ae47d440 100644 --- a/juniper/src/types/result.rs +++ b/juniper/src/types/result.rs @@ -1,6 +1,18 @@ //! GraphQL implementation for [`Result`]. -use crate::reflect; +use crate::{reflect, resolve, FieldResult, IntoFieldError}; + +impl<T, E, SV, BH> resolve::Resolvable<SV, BH> for Result<T, E> +where + E: IntoFieldError<SV>, + BH: ?Sized, +{ + type Value = T; + + fn into_value(self) -> FieldResult<Self::Value, SV> { + self.map_err(IntoFieldError::into_field_error) + } +} impl<T, E, BH> reflect::BaseType<BH> for Result<T, E> where diff --git a/juniper/src/types/vec.rs b/juniper/src/types/vec.rs index 0882cd51..cf01b030 100644 --- a/juniper/src/types/vec.rs +++ b/juniper/src/types/vec.rs @@ -5,7 +5,7 @@ use crate::{ executor::{ExecutionResult, Executor, Registry}, graphql, reflect, resolve, schema::meta::MetaType, - BoxFuture, FieldError, IntoFieldError, Selection, + BoxFuture, FieldError, FieldResult, IntoFieldError, Selection, }; use super::iter; @@ -64,6 +64,17 @@ where } } +impl<T, SV, BH> resolve::Resolvable<SV, BH> for Vec<T> +where + BH: ?Sized, +{ + type Value = Self; + + fn into_value(self) -> FieldResult<Self, SV> { + Ok(self) + } +} + impl<T, SV, BH> resolve::ToInputValue<SV, BH> for Vec<T> where T: resolve::ToInputValue<SV, BH>, diff --git a/juniper_actix/Cargo.toml b/juniper_actix/Cargo.toml index bb60ff5f..0bcb8d4c 100644 --- a/juniper_actix/Cargo.toml +++ b/juniper_actix/Cargo.toml @@ -27,7 +27,7 @@ actix-http = "3.0" actix-web = "4.0" actix-web-actors = "4.1.0" anyhow = "1.0" -futures = "0.3" +futures = "0.3.22" juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false } juniper_graphql_ws = { version = "0.4.0-dev", path = "../juniper_graphql_ws", optional = true } http = "0.2.4" diff --git a/juniper_codegen/Cargo.toml b/juniper_codegen/Cargo.toml index ef78a0a2..b2291658 100644 --- a/juniper_codegen/Cargo.toml +++ b/juniper_codegen/Cargo.toml @@ -30,6 +30,6 @@ url = "2.0" [dev-dependencies] derive_more = "0.99.7" -futures = "0.3" +futures = "0.3.22" juniper = { path = "../juniper" } serde = "1.0" diff --git a/juniper_codegen/src/graphql_enum/mod.rs b/juniper_codegen/src/graphql_enum/mod.rs index 6fd00a1c..2fe21f7c 100644 --- a/juniper_codegen/src/graphql_enum/mod.rs +++ b/juniper_codegen/src/graphql_enum/mod.rs @@ -417,6 +417,7 @@ impl ToTokens for Definition { self.impl_resolve_type_name().to_tokens(into); self.impl_resolve_value().to_tokens(into); self.impl_resolve_value_async().to_tokens(into); + self.impl_resolvable().to_tokens(into); self.impl_resolve_to_input_value().to_tokens(into); self.impl_resolve_input_value().to_tokens(into); self.impl_graphql_input_type().to_tokens(into); @@ -868,6 +869,31 @@ impl Definition { } } + /// Returns generated code implementing [`resolve::Resolvable`] trait for + /// this [GraphQL enum][0]. + /// + /// [`resolve::Resolvable`]: juniper::resolve::Resolvable + /// [0]: https://spec.graphql.org/October2021#sec-Enums + fn impl_resolvable(&self) -> TokenStream { + let bh = &self.behavior; + let (ty, generics) = self.ty_and_generics(); + let (sv, generics) = self.mix_scalar_value(generics); + let (impl_gens, _, where_clause) = generics.split_for_impl(); + + quote! { + #[automatically_derived] + impl #impl_gens ::juniper::resolve::Resolvable<#sv, #bh> + for #ty #where_clause + { + type Value = Self; + + fn into_value(self) -> ::juniper::FieldResult<Self, #sv> { + ::juniper::FieldResult::Ok(self) + } + } + } + } + /// Returns generated code implementing [`FromInputValue`] trait for this /// [GraphQL enum][0]. /// diff --git a/juniper_codegen/src/graphql_object/mod.rs b/juniper_codegen/src/graphql_object/mod.rs index 5e01d322..0017a0e6 100644 --- a/juniper_codegen/src/graphql_object/mod.rs +++ b/juniper_codegen/src/graphql_object/mod.rs @@ -599,108 +599,108 @@ impl<Operation: ?Sized + 'static> Definition<Operation> { }) .collect() } -/* - /// Returns generated code implementing [`resolve::StaticField`] trait for - /// each [field][1] of this [GraphQL object][0]. - /// - /// [`resolve::StaticField`]: juniper::resolve::StaticField - /// [0]: https://spec.graphql.org/October2021#sec-Objects - /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields - #[must_use] - pub(crate) fn impl_resolve_static_field(&self) -> TokenStream { - let bh = &self.behavior; - let (ty, generics) = self.ty_and_generics(); - let (inf, generics) = self.mix_type_info(generics); - let (cx, generics) = self.mix_context(generics); - let (sv, generics) = self.mix_scalar_value(generics); + /* + /// Returns generated code implementing [`resolve::StaticField`] trait for + /// each [field][1] of this [GraphQL object][0]. + /// + /// [`resolve::StaticField`]: juniper::resolve::StaticField + /// [0]: https://spec.graphql.org/October2021#sec-Objects + /// [1]: https://spec.graphql.org/October2021#sec-Language.Fields + #[must_use] + pub(crate) fn impl_resolve_static_field(&self) -> TokenStream { + let bh = &self.behavior; + let (ty, generics) = self.ty_and_generics(); + let (inf, generics) = self.mix_type_info(generics); + let (cx, generics) = self.mix_context(generics); + let (sv, generics) = self.mix_scalar_value(generics); - self.fields - .iter() - .map(|field| { - let mut generics = generics.clone(); - let (f_name, f_bh) = (&field.name, &field.behavior); - let (f_ident, f_ty) = (&field.ident, &field.ty); + self.fields + .iter() + .map(|field| { + let mut generics = generics.clone(); + let (f_name, f_bh) = (&field.name, &field.behavior); + let (f_ident, f_ty) = (&field.ident, &field.ty); - let body = if !field.is_async { - generics.make_where_clause().predicates.push(parse_quote! { - #f_ty: ::juniper::resolve::Value<#inf, #cx, #sv, #f_bh> - }); + let body = if !field.is_async { + generics.make_where_clause().predicates.push(parse_quote! { + #f_ty: ::juniper::resolve::Value<#inf, #cx, #sv, #f_bh> + }); - let res = if field.is_method() { - let args = field.arguments.as_ref().unwrap().iter().map(|arg| { - match arg { - field::MethodArgument::Regular(arg) => { - let (a_ty, a_bh) = (&arg.ty, &arg.behavior); - generics.make_where_clause().predicates.push(parse_quote! { - #a_ty: ::juniper::resolve::InputValueOwned<#sv, #a_bh> - }); - quote! { - args.resolve::<#a_ty, #a_bh>(#name)? - } - } - field::MethodArgument::Context(cx_ty) => { - generics.make_where_clause().predicates.push(parse_quote! { - #cx: ::juniper::Extract<#cx_ty> - }); - quote! { - <#cx as ::juniper::Extract<#cx_ty>> - ::extract(executor.context()) - } - } - field::MethodArgument::Executor => { - quote! { - executor + let res = if field.is_method() { + let args = field.arguments.as_ref().unwrap().iter().map(|arg| { + match arg { + field::MethodArgument::Regular(arg) => { + let (a_ty, a_bh) = (&arg.ty, &arg.behavior); + generics.make_where_clause().predicates.push(parse_quote! { + #a_ty: ::juniper::resolve::InputValueOwned<#sv, #a_bh> + }); + quote! { + args.resolve::<#a_ty, #a_bh>(#name)? + } + } + field::MethodArgument::Context(cx_ty) => { + generics.make_where_clause().predicates.push(parse_quote! { + #cx: ::juniper::Extract<#cx_ty> + }); + quote! { + <#cx as ::juniper::Extract<#cx_ty>> + ::extract(executor.context()) + } + } + field::MethodArgument::Executor => { + quote! { + executor + } } } + }); + + let rcv = field.has_receiver.then(|| { + quote! { self, } + }); + + quote! { Self::#ident(#rcv #( #args ),*) } + } else { + quote! { + &self.#f_ident } - }); + }; - let rcv = field.has_receiver.then(|| { - quote! { self, } - }); - - quote! { Self::#ident(#rcv #( #args ),*) } + quote! { + executor.resolve_value::<#f_bh, _, _>(#res, type_info) + } } else { quote! { - &self.#f_ident + ::std::panic!( + "Tried to resolve async field `{}` on type `{}` with a sync resolver", + #f_name, + <Self as ::juniper::reflect::BaseType<#bh>>::NAME, + ); } }; - quote! { - executor.resolve_value::<#f_bh, _, _>(#res, type_info) - } - } else { - quote! { - ::std::panic!( - "Tried to resolve async field `{}` on type `{}` with a sync resolver", - #f_name, - <Self as ::juniper::reflect::BaseType<#bh>>::NAME, - ); - } - }; + let (impl_gens, _, where_clause) = generics.split_for_impl(); - let (impl_gens, _, where_clause) = generics.split_for_impl(); - - quote! { - #[automatically_derived] - impl #impl_gens ::juniper::resolve::StaticField< - { ::juniper::reflect::fnv1a128(#f_name) }, - #inf, #cx, #sv, #bh, - > for #ty #where_clause { - fn resolve_static_field( - &self, - args: &::juniper::Arguments<'_, #sv>, - type_info: &#inf, - executor: &::juniper::Executor<'_, '_, #cx, #sv>, - ) -> ::juniper::ExecutionResult<#sv> { - #body + quote! { + #[automatically_derived] + impl #impl_gens ::juniper::resolve::StaticField< + { ::juniper::reflect::fnv1a128(#f_name) }, + #inf, #cx, #sv, #bh, + > for #ty #where_clause { + fn resolve_static_field( + &self, + args: &::juniper::Arguments<'_, #sv>, + type_info: &#inf, + executor: &::juniper::Executor<'_, '_, #cx, #sv>, + ) -> ::juniper::ExecutionResult<#sv> { + #body + } } } - } - }) - .collect() - } -*/ + }) + .collect() + } + */ /// Returns generated code implementing [`GraphQLType`] trait for this /// [GraphQL object][1]. /// diff --git a/juniper_codegen/src/graphql_scalar/mod.rs b/juniper_codegen/src/graphql_scalar/mod.rs index 3bde5e66..80ebefaa 100644 --- a/juniper_codegen/src/graphql_scalar/mod.rs +++ b/juniper_codegen/src/graphql_scalar/mod.rs @@ -351,6 +351,7 @@ impl ToTokens for Definition { self.impl_resolve_type_name().to_tokens(into); self.impl_resolve_value().to_tokens(into); self.impl_resolve_value_async().to_tokens(into); + self.impl_resolvable().to_tokens(into); self.impl_resolve_to_input_value().to_tokens(into); self.impl_resolve_input_value().to_tokens(into); self.impl_resolve_scalar_token().to_tokens(into); @@ -738,6 +739,31 @@ impl Definition { } } + /// Returns generated code implementing [`resolve::Resolvable`] trait for + /// this [GraphQL scalar][0]. + /// + /// [`resolve::Resolvable`]: juniper::resolve::Resolvable + /// [0]: https://spec.graphql.org/October2021#sec-Scalars + fn impl_resolvable(&self) -> TokenStream { + let bh = &self.behavior; + let (ty, generics) = self.ty_and_generics(); + let (sv, generics) = self.mix_scalar_value(generics); + let (impl_gens, _, where_clause) = generics.split_for_impl(); + + quote! { + #[automatically_derived] + impl #impl_gens ::juniper::resolve::Resolvable<#sv, #bh> + for #ty #where_clause + { + type Value = Self; + + fn into_value(self) -> ::juniper::FieldResult<Self, #sv> { + ::juniper::FieldResult::Ok(self) + } + } + } + } + /// Returns generated code implementing [`InputValue`] trait for this /// [GraphQL scalar][1]. /// diff --git a/juniper_codegen/src/graphql_union/mod.rs b/juniper_codegen/src/graphql_union/mod.rs index ff21e3c6..5b86cbe2 100644 --- a/juniper_codegen/src/graphql_union/mod.rs +++ b/juniper_codegen/src/graphql_union/mod.rs @@ -18,7 +18,7 @@ use syn::{ }; use crate::common::{ - filter_attrs, gen, behavior, + behavior, filter_attrs, gen, parse::{ attr::{err, OptionExt as _}, ParseBufferExt as _, diff --git a/juniper_hyper/Cargo.toml b/juniper_hyper/Cargo.toml index 0f2f6bb2..59f1c8a1 100644 --- a/juniper_hyper/Cargo.toml +++ b/juniper_hyper/Cargo.toml @@ -15,7 +15,7 @@ keywords = ["apollo", "graphql", "hyper", "juniper"] exclude = ["/examples/", "/release.toml"] [dependencies] -futures = "0.3.1" +futures = "0.3.22" hyper = { version = "0.14", features = ["server", "runtime"] } juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false } serde_json = "1.0" diff --git a/juniper_iron/Cargo.toml b/juniper_iron/Cargo.toml index 82c18f9c..7eef05d3 100644 --- a/juniper_iron/Cargo.toml +++ b/juniper_iron/Cargo.toml @@ -18,7 +18,7 @@ keywords = ["apollo", "graphql", "iron", "juniper"] exclude = ["/examples/", "/release.toml"] [dependencies] -futures = "0.3.1" +futures = "0.3.22" iron = ">= 0.5, < 0.7" juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false } serde_json = "1.0.2" diff --git a/juniper_rocket/Cargo.toml b/juniper_rocket/Cargo.toml index dc275ee3..e715609e 100644 --- a/juniper_rocket/Cargo.toml +++ b/juniper_rocket/Cargo.toml @@ -18,7 +18,7 @@ keywords = ["apollo", "graphql", "juniper", "rocket"] exclude = ["/examples/", "/tests/", "/release.toml"] [dependencies] -futures = "0.3.1" +futures = "0.3.22" juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false } rocket = { version = "=0.5.0-rc.2", default-features = false } serde_json = "1.0.2" diff --git a/juniper_subscriptions/Cargo.toml b/juniper_subscriptions/Cargo.toml index 8ccf40e5..8c6a14a5 100644 --- a/juniper_subscriptions/Cargo.toml +++ b/juniper_subscriptions/Cargo.toml @@ -15,7 +15,7 @@ keywords = ["graphql", "server", "subscription", "web", "websocket"] exclude = ["/release.toml"] [dependencies] -futures = "0.3.1" +futures = "0.3.22" juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false } [dev-dependencies] diff --git a/juniper_warp/Cargo.toml b/juniper_warp/Cargo.toml index bb704a20..361b00f5 100644 --- a/juniper_warp/Cargo.toml +++ b/juniper_warp/Cargo.toml @@ -23,7 +23,7 @@ subscriptions = ["juniper_graphql_ws"] [dependencies] anyhow = "1.0" -futures = "0.3.1" +futures = "0.3.22" juniper = { version = "0.16.0-dev", path = "../juniper", default-features = false } juniper_graphql_ws = { version = "0.4.0-dev", path = "../juniper_graphql_ws", optional = true } serde = { version = "1.0.75", features = ["derive"] } diff --git a/tests/codegen/Cargo.toml b/tests/codegen/Cargo.toml index 3efcfaef..eff4f4ad 100644 --- a/tests/codegen/Cargo.toml +++ b/tests/codegen/Cargo.toml @@ -8,7 +8,7 @@ publish = false rustversion = "1.0" [dev-dependencies] -futures = "0.3.1" +futures = "0.3" juniper = { path = "../../juniper" } serde_json = "1.0" tokio = { version = "1.0", features = ["rt", "time", "macros"] } diff --git a/tests/codegen/fail/interface/trait/argument_wrong_default_array.stderr b/tests/codegen/fail/interface/trait/argument_wrong_default_array.stderr index c8a00ea3..2d2feacb 100644 --- a/tests/codegen/fail/interface/trait/argument_wrong_default_array.stderr +++ b/tests/codegen/fail/interface/trait/argument_wrong_default_array.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `[bool; 2]: From<[bool; 3]>` is not satisfied - --> fail/interface/trait/argument_wrong_default_array.rs:3:1 + --> fail/interface/trait/argument_wrong_default_array.rs:5:41 | 3 | #[graphql_interface] - | ^^^^^^^^^^^^^^^^^^^^ the trait `From<[bool; 3]>` is not implemented for `[bool; 2]` + | -------------------- required by a bound introduced by this call +4 | trait Character { +5 | fn wrong(&self, #[graphql(default = [true, false, false])] input: [bool; 2]) -> bool; + | ^^^^^^^^^^^^^^^^^^^^ the trait `From<[bool; 3]>` is not implemented for `[bool; 2]` | = help: the following other types implement trait `From<T>`: <&'a [ascii::ascii_char::AsciiChar] as From<&'a ascii::ascii_str::AsciiStr>> @@ -14,5 +17,4 @@ error[E0277]: the trait bound `[bool; 2]: From<[bool; 3]>` is not satisfied <[u128; 1] as From<ppv_lite86::x86_64::vec128_storage>> <[u128; 2] as From<ppv_lite86::x86_64::vec256_storage>> and 7 others - = note: required because of the requirements on the impl of `Into<[bool; 2]>` for `[bool; 3]` - = note: this error originates in the attribute macro `graphql_interface` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: required for `[bool; 3]` to implement `Into<[bool; 2]>` diff --git a/tests/codegen/fail/object/argument_wrong_default_array.stderr b/tests/codegen/fail/object/argument_wrong_default_array.stderr index 76357529..1d92be56 100644 --- a/tests/codegen/fail/object/argument_wrong_default_array.stderr +++ b/tests/codegen/fail/object/argument_wrong_default_array.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `[bool; 2]: From<[bool; 3]>` is not satisfied - --> fail/object/argument_wrong_default_array.rs:5:1 + --> fail/object/argument_wrong_default_array.rs:7:41 | 5 | #[graphql_object] - | ^^^^^^^^^^^^^^^^^ the trait `From<[bool; 3]>` is not implemented for `[bool; 2]` + | ----------------- required by a bound introduced by this call +6 | impl ObjA { +7 | fn wrong(&self, #[graphql(default = [true, false, false])] input: [bool; 2]) -> bool { + | ^^^^^^^^^^^^^^^^^^^^ the trait `From<[bool; 3]>` is not implemented for `[bool; 2]` | = help: the following other types implement trait `From<T>`: <&'a [ascii::ascii_char::AsciiChar] as From<&'a ascii::ascii_str::AsciiStr>> @@ -14,5 +17,4 @@ error[E0277]: the trait bound `[bool; 2]: From<[bool; 3]>` is not satisfied <[u128; 1] as From<ppv_lite86::x86_64::vec128_storage>> <[u128; 2] as From<ppv_lite86::x86_64::vec256_storage>> and 7 others - = note: required because of the requirements on the impl of `Into<[bool; 2]>` for `[bool; 3]` - = note: this error originates in the attribute macro `graphql_object` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: required for `[bool; 3]` to implement `Into<[bool; 2]>` diff --git a/tests/codegen/fail/subscription/argument_wrong_default_array.stderr b/tests/codegen/fail/subscription/argument_wrong_default_array.stderr index ea5ccd3c..6b4e5257 100644 --- a/tests/codegen/fail/subscription/argument_wrong_default_array.stderr +++ b/tests/codegen/fail/subscription/argument_wrong_default_array.stderr @@ -1,8 +1,11 @@ error[E0277]: the trait bound `[bool; 2]: From<[bool; 3]>` is not satisfied - --> fail/subscription/argument_wrong_default_array.rs:10:1 + --> fail/subscription/argument_wrong_default_array.rs:14:29 | 10 | #[graphql_subscription] - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<[bool; 3]>` is not implemented for `[bool; 2]` + | ----------------------- required by a bound introduced by this call +... +14 | #[graphql(default = [true, false, false])] input: [bool; 2], + | ^^^^^^^^^^^^^^^^^^^^ the trait `From<[bool; 3]>` is not implemented for `[bool; 2]` | = help: the following other types implement trait `From<T>`: <&'a [ascii::ascii_char::AsciiChar] as From<&'a ascii::ascii_str::AsciiStr>> @@ -14,5 +17,4 @@ error[E0277]: the trait bound `[bool; 2]: From<[bool; 3]>` is not satisfied <[u128; 1] as From<ppv_lite86::x86_64::vec128_storage>> <[u128; 2] as From<ppv_lite86::x86_64::vec256_storage>> and 7 others - = note: required because of the requirements on the impl of `Into<[bool; 2]>` for `[bool; 3]` - = note: this error originates in the attribute macro `graphql_subscription` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: required for `[bool; 3]` to implement `Into<[bool; 2]>` diff --git a/tests/integration/Cargo.toml b/tests/integration/Cargo.toml index f339a718..ad25a358 100644 --- a/tests/integration/Cargo.toml +++ b/tests/integration/Cargo.toml @@ -6,7 +6,7 @@ publish = false [dev-dependencies] async-trait = "0.1.39" -chrono = "0.4" +chrono = { version = "0.4.20", default-features = false } derive_more = "0.99" fnv = "1.0" futures = "0.3"