Impl codegen for scalars (resolve::ToInputValue
trait), vol.5
This commit is contained in:
parent
740aa9061e
commit
97d2da581a
17 changed files with 265 additions and 40 deletions
|
@ -256,13 +256,17 @@ impl<S> InputValue<S> {
|
|||
Self::Variable(v.as_ref().to_owned())
|
||||
}
|
||||
|
||||
/// Construct a [`Spanning::unlocated`] list.
|
||||
/// Constructs a [`Spanning::unlocated`] [`InputValue::List`].
|
||||
///
|
||||
/// Convenience function to make each [`InputValue`] in the input vector
|
||||
/// not contain any location information. Can be used from [`ToInputValue`]
|
||||
/// implementations, where no source code position information is available.
|
||||
pub fn list(l: Vec<Self>) -> Self {
|
||||
Self::List(l.into_iter().map(Spanning::unlocated).collect())
|
||||
/// Convenience function to make each [`InputValue`] in the input `list` to
|
||||
/// not contain any location information.
|
||||
///
|
||||
/// Intended for [`resolve::ToInputValue`] implementations, where no source
|
||||
/// code position information is available.
|
||||
///
|
||||
/// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
|
||||
pub fn list(list: impl IntoIterator<Item = Self>) -> Self {
|
||||
Self::List(list.into_iter().map(Spanning::unlocated).collect())
|
||||
}
|
||||
|
||||
/// Construct a located list.
|
||||
|
@ -270,16 +274,25 @@ impl<S> InputValue<S> {
|
|||
Self::List(l)
|
||||
}
|
||||
|
||||
/// Construct aa [`Spanning::unlocated`] object.
|
||||
/// Construct a [`Spanning::unlocated`] [`InputValue::Onject`].
|
||||
///
|
||||
/// Similarly to [`InputValue::list`] it makes each key and value in the
|
||||
/// given hash map not contain any location information.
|
||||
pub fn object<K>(o: IndexMap<K, Self>) -> Self
|
||||
/// Similarly to [`InputValue::list()`] it makes each key and value in the
|
||||
/// given `obj`ect to not contain any location information.
|
||||
///
|
||||
/// Intended for [`resolve::ToInputValue`] implementations, where no source
|
||||
/// code position information is available.
|
||||
///
|
||||
/// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
|
||||
// TODO: Use `impl IntoIterator<Item = (K, Self)>` argument once feature
|
||||
// `explicit_generic_args_with_impl_trait` hits stable:
|
||||
// https://github.com/rust-lang/rust/issues/83701
|
||||
pub fn object<K, O>(obj: O) -> Self
|
||||
where
|
||||
K: AsRef<str> + Eq + Hash,
|
||||
O: IntoIterator<Item = (K, Self)>,
|
||||
{
|
||||
Self::Object(
|
||||
o.into_iter()
|
||||
obj.into_iter()
|
||||
.map(|(k, v)| {
|
||||
(
|
||||
Spanning::unlocated(k.as_ref().to_owned()),
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
use futures::future::BoxFuture;
|
||||
|
||||
use crate::{
|
||||
Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, Nullable, ScalarValue,
|
||||
};
|
||||
use crate::{Arguments as FieldArguments, ExecutionResult, Executor, GraphQLValue, ScalarValue};
|
||||
|
||||
/// Alias for a [GraphQL object][1], [scalar][2] or [interface][3] type's name
|
||||
/// in a GraphQL schema.
|
||||
|
|
|
@ -101,3 +101,7 @@ pub trait InputValue<'input, S: 'input = DefaultScalarValue>: Sized {
|
|||
pub trait InputValueOwned<S = DefaultScalarValue>: for<'i> InputValue<'i, S> {}
|
||||
|
||||
impl<T, S> InputValueOwned<S> for T where T: for<'i> InputValue<'i, S> {}
|
||||
|
||||
pub trait ToInputValue<S> {
|
||||
fn to_input_value(&self) -> graphql::InputValue<S>;
|
||||
}
|
||||
|
|
|
@ -143,12 +143,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ScalarToken<S> for Arc<T>
|
||||
impl<T, S> resolve::ToInputValue<S> for Arc<T>
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
T: resolve::ToInputValue<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
(**self).to_input_value()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ScalarToken<S> for Arc<T>
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> graphql::InputType<S> for Arc<T>
|
||||
where
|
||||
T: graphql::InputType<S> + ?Sized,
|
||||
|
|
|
@ -64,6 +64,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S, const N: usize> resolve::ToInputValue<S> for [T; N]
|
||||
where
|
||||
T: resolve::ToInputValue<S>,
|
||||
{
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
graphql::InputValue::list(self.iter().map(T::to_input_value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S, const N: usize> graphql::InputType<S> for [T; N]
|
||||
where
|
||||
T: graphql::InputType<S>,
|
||||
|
|
|
@ -141,12 +141,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ScalarToken<S> for Box<T>
|
||||
impl<T, S> resolve::ToInputValue<S> for Box<T>
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
T: resolve::ToInputValue<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
(**self).to_input_value()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,6 +192,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ScalarToken<S> for Box<T>
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> graphql::InputType<S> for Box<T>
|
||||
where
|
||||
T: graphql::InputType<S> + ?Sized,
|
||||
|
|
|
@ -183,7 +183,7 @@ where
|
|||
S: ScalarValue,
|
||||
{
|
||||
fn to_input_value(&self) -> InputValue<S> {
|
||||
InputValue::list(self.iter().map(T::to_input_value).collect())
|
||||
InputValue::list(self.iter().map(T::to_input_value))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -283,7 +283,7 @@ where
|
|||
S: ScalarValue,
|
||||
{
|
||||
fn to_input_value(&self) -> InputValue<S> {
|
||||
InputValue::list(self.iter().map(T::to_input_value).collect())
|
||||
InputValue::list(self.iter().map(T::to_input_value))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -481,7 +481,7 @@ where
|
|||
S: ScalarValue,
|
||||
{
|
||||
fn to_input_value(&self) -> InputValue<S> {
|
||||
InputValue::list(self.iter().map(T::to_input_value).collect())
|
||||
InputValue::list(self.iter().map(T::to_input_value))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -324,6 +324,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ToInputValue<S> for Nullable<T>
|
||||
where
|
||||
T: resolve::ToInputValue<S>,
|
||||
{
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
match self {
|
||||
Self::Some(v) => v.to_input_value(),
|
||||
Self::ExplicitNull | Self::ImplicitNull => graphql::InputValue::Null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Nullable<T>
|
||||
where
|
||||
T: resolve::InputValue<'inp, S>,
|
||||
|
|
|
@ -61,6 +61,18 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ToInputValue<S> for Option<T>
|
||||
where
|
||||
T: resolve::ToInputValue<S>,
|
||||
{
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
match self {
|
||||
Some(v) => v.to_input_value(),
|
||||
None => graphql::InputValue::Null,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'inp, T, S: 'inp> resolve::InputValue<'inp, S> for Option<T>
|
||||
where
|
||||
T: resolve::InputValue<'inp, S>,
|
||||
|
|
|
@ -143,12 +143,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ScalarToken<S> for Rc<T>
|
||||
impl<T, S> resolve::ToInputValue<S> for Rc<T>
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
T: resolve::ToInputValue<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
(**self).to_input_value()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -194,6 +194,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ScalarToken<S> for Rc<T>
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> graphql::InputType<S> for Rc<T>
|
||||
where
|
||||
T: graphql::InputType<S> + ?Sized,
|
||||
|
|
|
@ -143,12 +143,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'me, T, S> resolve::ScalarToken<S> for &'me T
|
||||
impl<'me, T, S> resolve::ToInputValue<S> for &'me T
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
T: resolve::ToInputValue<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
(**self).to_input_value()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,6 +180,15 @@ pub trait TryFromInputValue<S = DefaultScalarValue> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'me, T, S> resolve::ScalarToken<S> for &'me T
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
T::parse_scalar_token(token)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'me, T, S> graphql::InputType<S> for &'me T
|
||||
where
|
||||
T: graphql::InputType<S> + ?Sized,
|
||||
|
|
|
@ -142,6 +142,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'me, T, S> resolve::ToInputValue<S> for &'me mut T
|
||||
where
|
||||
T: resolve::ToInputValue<S> + ?Sized,
|
||||
{
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
(**self).to_input_value()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'me, T, S> resolve::ScalarToken<S> for &'me mut T
|
||||
where
|
||||
T: resolve::ScalarToken<S> + ?Sized,
|
||||
|
|
|
@ -62,6 +62,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ToInputValue<S> for [T]
|
||||
where
|
||||
T: resolve::ToInputValue<S>,
|
||||
{
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
graphql::InputValue::list(self.iter().map(T::to_input_value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> graphql::InputType<S> for [T]
|
||||
where
|
||||
T: graphql::InputType<S>,
|
||||
|
|
|
@ -66,12 +66,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<S> resolve::ScalarToken<S> for str
|
||||
impl<S> resolve::ToInputValue<S> for str
|
||||
where
|
||||
String: resolve::ScalarToken<S>,
|
||||
S: From<String>,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
<String as resolve::ScalarToken<S>>::parse_scalar_token(token)
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
graphql::InputValue::scalar(self.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,15 @@ impl<'inp, S: ScalarValue> resolve::InputValueAsRc<'inp, S> for str {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S> resolve::ScalarToken<S> for str
|
||||
where
|
||||
String: resolve::ScalarToken<S>,
|
||||
{
|
||||
fn parse_scalar_token(token: ScalarToken<'_>) -> Result<S, ParseError<'_>> {
|
||||
<String as resolve::ScalarToken<S>>::parse_scalar_token(token)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> graphql::InputType<S> for str {
|
||||
fn assert_input_type() {}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,15 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<T, S> resolve::ToInputValue<S> for Vec<T>
|
||||
where
|
||||
T: resolve::ToInputValue<S>,
|
||||
{
|
||||
fn to_input_value(&self) -> graphql::InputValue<S> {
|
||||
graphql::InputValue::list(self.iter().map(T::to_input_value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, S> graphql::InputType<S> for Vec<T>
|
||||
where
|
||||
T: graphql::InputType<S>,
|
||||
|
|
|
@ -6,6 +6,7 @@ use std::{any::TypeId, borrow::Cow, fmt, mem};
|
|||
use crate::{
|
||||
ast::{InputValue, ToInputValue},
|
||||
parser::Spanning,
|
||||
resolve,
|
||||
};
|
||||
|
||||
pub use self::{
|
||||
|
@ -190,6 +191,27 @@ impl<S: Clone> ToInputValue<S> for Value<S> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<S: Clone> resolve::ToInputValue<S> for Value<S> {
|
||||
fn to_input_value(&self) -> InputValue<S> {
|
||||
// TODO: Simplify recursive calls syntax, once old `ToInputValue` trait
|
||||
// is removed.
|
||||
match self {
|
||||
Self::Null => InputValue::Null,
|
||||
Self::Scalar(s) => InputValue::Scalar(s.clone()),
|
||||
Self::List(l) => InputValue::list(
|
||||
l.iter()
|
||||
.map(<Self as resolve::ToInputValue<S>>::to_input_value),
|
||||
),
|
||||
Self::Object(o) => InputValue::object(o.iter().map(|(k, v)| {
|
||||
(
|
||||
k.clone(),
|
||||
<Self as resolve::ToInputValue<S>>::to_input_value(v),
|
||||
)
|
||||
})),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ScalarValue> fmt::Display for Value<S> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
|
|
|
@ -334,6 +334,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_resolve_to_input_value().to_tokens(into);
|
||||
self.impl_resolve_input_value().to_tokens(into);
|
||||
self.impl_resolve_scalar_token().to_tokens(into);
|
||||
self.impl_input_and_output_type().to_tokens(into);
|
||||
|
@ -680,7 +681,7 @@ impl Definition {
|
|||
fn impl_to_input_value_tokens(&self) -> TokenStream {
|
||||
let scalar = &self.scalar;
|
||||
|
||||
let to_input_value = self.methods.expand_to_input_value(scalar);
|
||||
let to_input_value = self.methods.expand_old_to_input_value(scalar);
|
||||
|
||||
let (ty, generics) = self.impl_self_and_generics(false);
|
||||
let (impl_gens, _, where_clause) = generics.split_for_impl();
|
||||
|
@ -697,6 +698,34 @@ impl Definition {
|
|||
}
|
||||
}
|
||||
|
||||
/// Returns generated code implementing [`resolve::ToInputValue`] trait for
|
||||
/// this [GraphQL scalar][0].
|
||||
///
|
||||
/// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
|
||||
/// [0]: https://spec.graphql.org/October2021#sec-Scalars
|
||||
fn impl_resolve_to_input_value(&self) -> TokenStream {
|
||||
let (ty, generics) = self.ty_and_generics();
|
||||
let (sv, mut generics) = self.mix_scalar_value(generics);
|
||||
generics
|
||||
.make_where_clause()
|
||||
.predicates
|
||||
.push(self.methods.bound_to_input_value(sv));
|
||||
let (impl_gens, _, where_clause) = generics.split_for_impl();
|
||||
|
||||
let body = self.methods.expand_to_input_value(sv);
|
||||
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
impl#impl_gens ::juniper::resolve::ToInputValue<#sv> for #ty
|
||||
#where_clause
|
||||
{
|
||||
fn to_input_value(&self) -> ::juniper::graphql::InputValue<#sv> {
|
||||
#body
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns generated code implementing [`FromInputValue`] trait for this
|
||||
/// [GraphQL scalar][1].
|
||||
///
|
||||
|
@ -1084,7 +1113,7 @@ impl Methods {
|
|||
}
|
||||
}
|
||||
|
||||
/// Expands [`resolve::Value::resolve_value()`][0] method.
|
||||
/// Expands body of [`resolve::Value::resolve_value()`][0] method.
|
||||
///
|
||||
/// [0]: juniper::resolve::Value::resolve_value
|
||||
fn expand_resolve_value(
|
||||
|
@ -1152,7 +1181,7 @@ impl Methods {
|
|||
/// Expands [`ToInputValue::to_input_value`] method.
|
||||
///
|
||||
/// [`ToInputValue::to_input_value`]: juniper::ToInputValue::to_input_value
|
||||
fn expand_to_input_value(&self, scalar: &scalar::Type) -> TokenStream {
|
||||
fn expand_old_to_input_value(&self, scalar: &scalar::Type) -> TokenStream {
|
||||
match self {
|
||||
Self::Custom { to_output, .. }
|
||||
| Self::Delegated {
|
||||
|
@ -1172,6 +1201,60 @@ impl Methods {
|
|||
}
|
||||
}
|
||||
|
||||
/// Expands body of [`resolve::ToInputValue::to_input_value()`][0] method.
|
||||
///
|
||||
/// [0]: juniper::resolve::ToInputValue::to_input_value
|
||||
fn expand_to_input_value(&self, sv: &scalar::Type) -> TokenStream {
|
||||
match self {
|
||||
Self::Custom { to_output, .. }
|
||||
| Self::Delegated {
|
||||
to_output: Some(to_output),
|
||||
..
|
||||
} => {
|
||||
quote! {
|
||||
let v = #to_output(self);
|
||||
::juniper::resolve::ToInputValue::<#sv>::to_input_value(&v)
|
||||
}
|
||||
}
|
||||
|
||||
Self::Delegated { field, .. } => {
|
||||
let field_ty = field.ty();
|
||||
|
||||
quote! {
|
||||
<#field_ty as ::juniper::resolve::ToInputValue<#sv>>
|
||||
::to_input_value(&self.#field)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates additional trait bounds for [`resolve::ToInputValue`]
|
||||
/// implementation allowing to execute
|
||||
/// [`resolve::ToInputValue::to_input_value()`][0] method.
|
||||
///
|
||||
/// [`resolve::ToInputValue`]: juniper::resolve::ToInputValue
|
||||
/// [0]: juniper::resolve::ToInputValue::to_input_value
|
||||
fn bound_to_input_value(&self, sv: &scalar::Type) -> syn::WherePredicate {
|
||||
match self {
|
||||
Self::Custom { .. }
|
||||
| Self::Delegated {
|
||||
to_output: Some(_), ..
|
||||
} => {
|
||||
parse_quote! {
|
||||
#sv: ::juniper::ScalarValue
|
||||
}
|
||||
}
|
||||
|
||||
Self::Delegated { field, .. } => {
|
||||
let field_ty = field.ty();
|
||||
|
||||
parse_quote! {
|
||||
#field_ty: ::juniper::resolve::ToInputValue<#sv>>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Expands [`FromInputValue::from_input_value`][1] method.
|
||||
///
|
||||
/// [1]: juniper::FromInputValue::from_input_value
|
||||
|
|
Loading…
Reference in a new issue