Allow different Scalar for GraphQLScalarValue (#807)
* allow setting scalar in macro * rustfmt * added changes to changelog * added test cases
This commit is contained in:
parent
8783496c68
commit
cb6d89f4c7
4 changed files with 197 additions and 32 deletions
139
integration_tests/juniper_tests/src/codegen/derive_scalar.rs
Normal file
139
integration_tests/juniper_tests/src/codegen/derive_scalar.rs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
use crate::custom_scalar::MyScalarValue;
|
||||||
|
use juniper::{
|
||||||
|
execute, EmptyMutation, EmptySubscription, FromInputValue, InputValue, RootNode, ToInputValue,
|
||||||
|
Value, Variables,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Hash, juniper::GraphQLScalarValue)]
|
||||||
|
#[graphql(transparent, scalar = MyScalarValue)]
|
||||||
|
pub struct LargeId(i64);
|
||||||
|
|
||||||
|
#[derive(juniper::GraphQLObject)]
|
||||||
|
#[graphql(scalar = MyScalarValue)]
|
||||||
|
struct User {
|
||||||
|
id: LargeId,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Query;
|
||||||
|
|
||||||
|
#[juniper::graphql_object(scalar = MyScalarValue)]
|
||||||
|
impl Query {
|
||||||
|
fn user() -> User {
|
||||||
|
User { id: LargeId(0) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Mutation;
|
||||||
|
|
||||||
|
#[juniper::graphql_object(scalar = MyScalarValue)]
|
||||||
|
impl Mutation {
|
||||||
|
fn change_user(id: LargeId) -> User {
|
||||||
|
User { id }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_scalar_value_large_id() {
|
||||||
|
let num: i64 = 4294967297;
|
||||||
|
|
||||||
|
let input_integer: InputValue<MyScalarValue> =
|
||||||
|
serde_json::from_value(serde_json::json!(num)).unwrap();
|
||||||
|
|
||||||
|
let output: LargeId =
|
||||||
|
FromInputValue::<MyScalarValue>::from_input_value(&input_integer).unwrap();
|
||||||
|
assert_eq!(output, LargeId(num));
|
||||||
|
|
||||||
|
let id = LargeId(num);
|
||||||
|
let output = ToInputValue::<MyScalarValue>::to_input_value(&id);
|
||||||
|
assert_eq!(output, InputValue::scalar(num));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_scalar_value_large_query() {
|
||||||
|
let schema = RootNode::<'_, _, _, _, MyScalarValue>::new_with_scalar_value(
|
||||||
|
Query,
|
||||||
|
EmptyMutation::<()>::new(),
|
||||||
|
EmptySubscription::<()>::new(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let doc = r#"
|
||||||
|
query {
|
||||||
|
user { id }
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
execute(doc, None, &schema, &Variables::<MyScalarValue>::new(), &()).await,
|
||||||
|
Ok((
|
||||||
|
Value::object(
|
||||||
|
vec![(
|
||||||
|
"user",
|
||||||
|
Value::object(
|
||||||
|
vec![("id", Value::<MyScalarValue>::scalar(0_i64)),]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_scalar_value_large_mutation() {
|
||||||
|
let schema = RootNode::<'_, _, _, _, MyScalarValue>::new_with_scalar_value(
|
||||||
|
Query,
|
||||||
|
Mutation,
|
||||||
|
EmptySubscription::<()>::new(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let doc = r#"
|
||||||
|
mutation {
|
||||||
|
changeUser(id: 1) { id }
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
execute(doc, None, &schema, &Variables::<MyScalarValue>::new(), &()).await,
|
||||||
|
Ok((
|
||||||
|
Value::object(
|
||||||
|
vec![(
|
||||||
|
"changeUser",
|
||||||
|
Value::object(
|
||||||
|
vec![("id", Value::<MyScalarValue>::scalar(1_i64)),]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
|
||||||
|
let doc = r#"
|
||||||
|
mutation {
|
||||||
|
changeUser(id: 4294967297) { id }
|
||||||
|
}"#;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
execute(doc, None, &schema, &Variables::<MyScalarValue>::new(), &()).await,
|
||||||
|
Ok((
|
||||||
|
Value::object(
|
||||||
|
vec![(
|
||||||
|
"changeUser",
|
||||||
|
Value::object(
|
||||||
|
vec![("id", Value::<MyScalarValue>::scalar(4294967297_i64)),]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect()
|
||||||
|
),
|
||||||
|
vec![]
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ mod derive_enum;
|
||||||
mod derive_input_object;
|
mod derive_input_object;
|
||||||
mod derive_object;
|
mod derive_object;
|
||||||
mod derive_object_with_raw_idents;
|
mod derive_object_with_raw_idents;
|
||||||
|
mod derive_scalar;
|
||||||
mod impl_object;
|
mod impl_object;
|
||||||
mod impl_scalar;
|
mod impl_scalar;
|
||||||
mod interface_attr;
|
mod interface_attr;
|
||||||
|
|
|
@ -39,6 +39,8 @@
|
||||||
|
|
||||||
- Implement `IntoFieldError` for `std::convert::Infallible`. ([#796](https://github.com/graphql-rust/juniper/pull/796))
|
- Implement `IntoFieldError` for `std::convert::Infallible`. ([#796](https://github.com/graphql-rust/juniper/pull/796))
|
||||||
|
|
||||||
|
- Allow using `#[graphql(Scalar = DefaultScalarValue)]` for derive macro `GraphQLScalarValue` ([#807](https://github.com/graphql-rust/juniper/pull/807))
|
||||||
|
|
||||||
## Fixes
|
## Fixes
|
||||||
|
|
||||||
- Massively improved the `#[graphql_union]` proc macro. ([#666](https://github.com/graphql-rust/juniper/pull/666)):
|
- Massively improved the `#[graphql_union]` proc macro. ([#666](https://github.com/graphql-rust/juniper/pull/666)):
|
||||||
|
|
|
@ -12,6 +12,7 @@ struct TransparentAttributes {
|
||||||
transparent: Option<bool>,
|
transparent: Option<bool>,
|
||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
description: Option<String>,
|
description: Option<String>,
|
||||||
|
scalar: Option<syn::Type>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl syn::parse::Parse for TransparentAttributes {
|
impl syn::parse::Parse for TransparentAttributes {
|
||||||
|
@ -20,6 +21,7 @@ impl syn::parse::Parse for TransparentAttributes {
|
||||||
transparent: None,
|
transparent: None,
|
||||||
name: None,
|
name: None,
|
||||||
description: None,
|
description: None,
|
||||||
|
scalar: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
while !input.is_empty() {
|
while !input.is_empty() {
|
||||||
|
@ -38,6 +40,11 @@ impl syn::parse::Parse for TransparentAttributes {
|
||||||
"transparent" => {
|
"transparent" => {
|
||||||
output.transparent = Some(true);
|
output.transparent = Some(true);
|
||||||
}
|
}
|
||||||
|
"scalar" | "Scalar" => {
|
||||||
|
input.parse::<token::Eq>()?;
|
||||||
|
let val = input.parse::<syn::Type>()?;
|
||||||
|
output.scalar = Some(val);
|
||||||
|
}
|
||||||
_ => return Err(syn::Error::new(ident.span(), "unknown attribute")),
|
_ => return Err(syn::Error::new(ident.span(), "unknown attribute")),
|
||||||
}
|
}
|
||||||
input.try_parse::<token::Comma>()?;
|
input.try_parse::<token::Comma>()?;
|
||||||
|
@ -99,22 +106,34 @@ fn impl_scalar_struct(
|
||||||
None => quote!(),
|
None => quote!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let scalar = attrs
|
||||||
|
.scalar
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| quote!( #s ))
|
||||||
|
.unwrap_or_else(|| quote!(__S));
|
||||||
|
|
||||||
|
let impl_generics = attrs
|
||||||
|
.scalar
|
||||||
|
.as_ref()
|
||||||
|
.map(|_| quote!())
|
||||||
|
.unwrap_or_else(|| quote!(<__S>));
|
||||||
|
|
||||||
let _async = quote!(
|
let _async = quote!(
|
||||||
impl<__S> ::juniper::GraphQLValueAsync<__S> for #ident
|
impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ident
|
||||||
where
|
where
|
||||||
Self: Sync,
|
Self: Sync,
|
||||||
Self::TypeInfo: Sync,
|
Self::TypeInfo: Sync,
|
||||||
Self::Context: Sync,
|
Self::Context: Sync,
|
||||||
__S: ::juniper::ScalarValue + Send + Sync,
|
#scalar: ::juniper::ScalarValue + Send + Sync,
|
||||||
{
|
{
|
||||||
fn resolve_async<'a>(
|
fn resolve_async<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
info: &'a Self::TypeInfo,
|
info: &'a Self::TypeInfo,
|
||||||
selection_set: Option<&'a [::juniper::Selection<__S>]>,
|
selection_set: Option<&'a [::juniper::Selection<#scalar>]>,
|
||||||
executor: &'a ::juniper::Executor<Self::Context, __S>,
|
executor: &'a ::juniper::Executor<Self::Context, #scalar>,
|
||||||
) -> ::juniper::BoxFuture<'a, ::juniper::ExecutionResult<__S>> {
|
) -> ::juniper::BoxFuture<'a, ::juniper::ExecutionResult<#scalar>> {
|
||||||
use ::juniper::futures::future;
|
use ::juniper::futures::future;
|
||||||
let v = ::juniper::GraphQLValue::resolve(self, info, selection_set, executor);
|
let v = ::juniper::GraphQLValue::<#scalar>::resolve(self, info, selection_set, executor);
|
||||||
Box::pin(future::ready(v))
|
Box::pin(future::ready(v))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,9 +142,9 @@ fn impl_scalar_struct(
|
||||||
let content = quote!(
|
let content = quote!(
|
||||||
#_async
|
#_async
|
||||||
|
|
||||||
impl<S> ::juniper::GraphQLType<S> for #ident
|
impl#impl_generics ::juniper::GraphQLType<#scalar> for #ident
|
||||||
where
|
where
|
||||||
S: ::juniper::ScalarValue,
|
#scalar: ::juniper::ScalarValue,
|
||||||
{
|
{
|
||||||
fn name(_: &Self::TypeInfo) -> Option<&'static str> {
|
fn name(_: &Self::TypeInfo) -> Option<&'static str> {
|
||||||
Some(#name)
|
Some(#name)
|
||||||
|
@ -133,10 +152,10 @@ fn impl_scalar_struct(
|
||||||
|
|
||||||
fn meta<'r>(
|
fn meta<'r>(
|
||||||
info: &Self::TypeInfo,
|
info: &Self::TypeInfo,
|
||||||
registry: &mut ::juniper::Registry<'r, S>,
|
registry: &mut ::juniper::Registry<'r, #scalar>,
|
||||||
) -> ::juniper::meta::MetaType<'r, S>
|
) -> ::juniper::meta::MetaType<'r, #scalar>
|
||||||
where
|
where
|
||||||
S: 'r,
|
#scalar: 'r,
|
||||||
{
|
{
|
||||||
registry.build_scalar_type::<Self>(info)
|
registry.build_scalar_type::<Self>(info)
|
||||||
#description
|
#description
|
||||||
|
@ -144,59 +163,63 @@ fn impl_scalar_struct(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ::juniper::GraphQLValue<S> for #ident
|
impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ident
|
||||||
where
|
where
|
||||||
S: ::juniper::ScalarValue,
|
#scalar: ::juniper::ScalarValue,
|
||||||
{
|
{
|
||||||
type Context = ();
|
type Context = ();
|
||||||
type TypeInfo = ();
|
type TypeInfo = ();
|
||||||
|
|
||||||
fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> {
|
fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> {
|
||||||
<Self as ::juniper::GraphQLType<S>>::name(info)
|
<Self as ::juniper::GraphQLType<#scalar>>::name(info)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve(
|
fn resolve(
|
||||||
&self,
|
&self,
|
||||||
info: &(),
|
info: &(),
|
||||||
selection: Option<&[::juniper::Selection<S>]>,
|
selection: Option<&[::juniper::Selection<#scalar>]>,
|
||||||
executor: &::juniper::Executor<Self::Context, S>,
|
executor: &::juniper::Executor<Self::Context, #scalar>,
|
||||||
) -> ::juniper::ExecutionResult<S> {
|
) -> ::juniper::ExecutionResult<#scalar> {
|
||||||
::juniper::GraphQLValue::resolve(&self.0, info, selection, executor)
|
::juniper::GraphQLValue::<#scalar>::resolve(&self.0, info, selection, executor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ::juniper::ToInputValue<S> for #ident
|
impl#impl_generics ::juniper::ToInputValue<#scalar> for #ident
|
||||||
where
|
where
|
||||||
S: ::juniper::ScalarValue,
|
#scalar: ::juniper::ScalarValue,
|
||||||
{
|
{
|
||||||
fn to_input_value(&self) -> ::juniper::InputValue<S> {
|
fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
|
||||||
::juniper::ToInputValue::to_input_value(&self.0)
|
::juniper::ToInputValue::<#scalar>::to_input_value(&self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ::juniper::FromInputValue<S> for #ident
|
impl#impl_generics ::juniper::FromInputValue<#scalar> for #ident
|
||||||
where
|
where
|
||||||
S: ::juniper::ScalarValue,
|
#scalar: ::juniper::ScalarValue,
|
||||||
{
|
{
|
||||||
fn from_input_value(v: &::juniper::InputValue<S>) -> Option<#ident> {
|
fn from_input_value(v: &::juniper::InputValue<#scalar>) -> Option<#ident> {
|
||||||
let inner: #inner_ty = ::juniper::FromInputValue::from_input_value(v)?;
|
let inner: #inner_ty = ::juniper::FromInputValue::<#scalar>::from_input_value(v)?;
|
||||||
Some(#ident(inner))
|
Some(#ident(inner))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> ::juniper::ParseScalarValue<S> for #ident
|
impl#impl_generics ::juniper::ParseScalarValue<#scalar> for #ident
|
||||||
where
|
where
|
||||||
S: ::juniper::ScalarValue,
|
#scalar: ::juniper::ScalarValue,
|
||||||
{
|
{
|
||||||
fn from_str<'a>(
|
fn from_str<'a>(
|
||||||
value: ::juniper::parser::ScalarToken<'a>,
|
value: ::juniper::parser::ScalarToken<'a>,
|
||||||
) -> ::juniper::ParseScalarResult<'a, S> {
|
) -> ::juniper::ParseScalarResult<'a, #scalar> {
|
||||||
<#inner_ty as ::juniper::ParseScalarValue<S>>::from_str(value)
|
<#inner_ty as ::juniper::ParseScalarValue<#scalar>>::from_str(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: ::juniper::ScalarValue> ::juniper::marker::IsOutputType<S> for #ident { }
|
impl#impl_generics ::juniper::marker::IsOutputType<#scalar> for #ident
|
||||||
impl<S: ::juniper::ScalarValue> ::juniper::marker::IsInputType<S> for #ident { }
|
where #scalar: ::juniper::ScalarValue,
|
||||||
|
{ }
|
||||||
|
impl#impl_generics ::juniper::marker::IsInputType<#scalar> for #ident
|
||||||
|
where #scalar: ::juniper::ScalarValue,
|
||||||
|
{ }
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(content)
|
Ok(content)
|
||||||
|
|
Loading…
Reference in a new issue