Skip to content

Commit cb6d89f

Browse files
authored
Allow different Scalar for GraphQLScalarValue (#807)
* allow setting scalar in macro * rustfmt * added changes to changelog * added test cases
1 parent 8783496 commit cb6d89f

File tree

4 files changed

+197
-32
lines changed

4 files changed

+197
-32
lines changed
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use crate::custom_scalar::MyScalarValue;
2+
use juniper::{
3+
execute, EmptyMutation, EmptySubscription, FromInputValue, InputValue, RootNode, ToInputValue,
4+
Value, Variables,
5+
};
6+
7+
#[derive(Debug, PartialEq, Eq, Hash, juniper::GraphQLScalarValue)]
8+
#[graphql(transparent, scalar = MyScalarValue)]
9+
pub struct LargeId(i64);
10+
11+
#[derive(juniper::GraphQLObject)]
12+
#[graphql(scalar = MyScalarValue)]
13+
struct User {
14+
id: LargeId,
15+
}
16+
17+
struct Query;
18+
19+
#[juniper::graphql_object(scalar = MyScalarValue)]
20+
impl Query {
21+
fn user() -> User {
22+
User { id: LargeId(0) }
23+
}
24+
}
25+
26+
struct Mutation;
27+
28+
#[juniper::graphql_object(scalar = MyScalarValue)]
29+
impl Mutation {
30+
fn change_user(id: LargeId) -> User {
31+
User { id }
32+
}
33+
}
34+
35+
#[test]
36+
fn test_scalar_value_large_id() {
37+
let num: i64 = 4294967297;
38+
39+
let input_integer: InputValue<MyScalarValue> =
40+
serde_json::from_value(serde_json::json!(num)).unwrap();
41+
42+
let output: LargeId =
43+
FromInputValue::<MyScalarValue>::from_input_value(&input_integer).unwrap();
44+
assert_eq!(output, LargeId(num));
45+
46+
let id = LargeId(num);
47+
let output = ToInputValue::<MyScalarValue>::to_input_value(&id);
48+
assert_eq!(output, InputValue::scalar(num));
49+
}
50+
51+
#[tokio::test]
52+
async fn test_scalar_value_large_query() {
53+
let schema = RootNode::<'_, _, _, _, MyScalarValue>::new_with_scalar_value(
54+
Query,
55+
EmptyMutation::<()>::new(),
56+
EmptySubscription::<()>::new(),
57+
);
58+
59+
let doc = r#"
60+
query {
61+
user { id }
62+
}"#;
63+
64+
assert_eq!(
65+
execute(doc, None, &schema, &Variables::<MyScalarValue>::new(), &()).await,
66+
Ok((
67+
Value::object(
68+
vec![(
69+
"user",
70+
Value::object(
71+
vec![("id", Value::<MyScalarValue>::scalar(0_i64)),]
72+
.into_iter()
73+
.collect(),
74+
),
75+
)]
76+
.into_iter()
77+
.collect()
78+
),
79+
vec![]
80+
))
81+
);
82+
}
83+
84+
#[tokio::test]
85+
async fn test_scalar_value_large_mutation() {
86+
let schema = RootNode::<'_, _, _, _, MyScalarValue>::new_with_scalar_value(
87+
Query,
88+
Mutation,
89+
EmptySubscription::<()>::new(),
90+
);
91+
92+
let doc = r#"
93+
mutation {
94+
changeUser(id: 1) { id }
95+
}"#;
96+
97+
assert_eq!(
98+
execute(doc, None, &schema, &Variables::<MyScalarValue>::new(), &()).await,
99+
Ok((
100+
Value::object(
101+
vec![(
102+
"changeUser",
103+
Value::object(
104+
vec![("id", Value::<MyScalarValue>::scalar(1_i64)),]
105+
.into_iter()
106+
.collect(),
107+
),
108+
)]
109+
.into_iter()
110+
.collect()
111+
),
112+
vec![]
113+
))
114+
);
115+
116+
let doc = r#"
117+
mutation {
118+
changeUser(id: 4294967297) { id }
119+
}"#;
120+
121+
assert_eq!(
122+
execute(doc, None, &schema, &Variables::<MyScalarValue>::new(), &()).await,
123+
Ok((
124+
Value::object(
125+
vec![(
126+
"changeUser",
127+
Value::object(
128+
vec![("id", Value::<MyScalarValue>::scalar(4294967297_i64)),]
129+
.into_iter()
130+
.collect(),
131+
),
132+
)]
133+
.into_iter()
134+
.collect()
135+
),
136+
vec![]
137+
))
138+
);
139+
}

integration_tests/juniper_tests/src/codegen/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod derive_enum;
22
mod derive_input_object;
33
mod derive_object;
44
mod derive_object_with_raw_idents;
5+
mod derive_scalar;
56
mod impl_object;
67
mod impl_scalar;
78
mod interface_attr;

juniper/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939

4040
- Implement `IntoFieldError` for `std::convert::Infallible`. ([#796](https://github.com/graphql-rust/juniper/pull/796))
4141

42+
- Allow using `#[graphql(Scalar = DefaultScalarValue)]` for derive macro `GraphQLScalarValue` ([#807](https://github.com/graphql-rust/juniper/pull/807))
43+
4244
## Fixes
4345

4446
- Massively improved the `#[graphql_union]` proc macro. ([#666](https://github.com/graphql-rust/juniper/pull/666)):

juniper_codegen/src/derive_scalar_value.rs

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct TransparentAttributes {
1212
transparent: Option<bool>,
1313
name: Option<String>,
1414
description: Option<String>,
15+
scalar: Option<syn::Type>,
1516
}
1617

1718
impl syn::parse::Parse for TransparentAttributes {
@@ -20,6 +21,7 @@ impl syn::parse::Parse for TransparentAttributes {
2021
transparent: None,
2122
name: None,
2223
description: None,
24+
scalar: None,
2325
};
2426

2527
while !input.is_empty() {
@@ -38,6 +40,11 @@ impl syn::parse::Parse for TransparentAttributes {
3840
"transparent" => {
3941
output.transparent = Some(true);
4042
}
43+
"scalar" | "Scalar" => {
44+
input.parse::<token::Eq>()?;
45+
let val = input.parse::<syn::Type>()?;
46+
output.scalar = Some(val);
47+
}
4148
_ => return Err(syn::Error::new(ident.span(), "unknown attribute")),
4249
}
4350
input.try_parse::<token::Comma>()?;
@@ -99,22 +106,34 @@ fn impl_scalar_struct(
99106
None => quote!(),
100107
};
101108

109+
let scalar = attrs
110+
.scalar
111+
.as_ref()
112+
.map(|s| quote!( #s ))
113+
.unwrap_or_else(|| quote!(__S));
114+
115+
let impl_generics = attrs
116+
.scalar
117+
.as_ref()
118+
.map(|_| quote!())
119+
.unwrap_or_else(|| quote!(<__S>));
120+
102121
let _async = quote!(
103-
impl<__S> ::juniper::GraphQLValueAsync<__S> for #ident
122+
impl#impl_generics ::juniper::GraphQLValueAsync<#scalar> for #ident
104123
where
105124
Self: Sync,
106125
Self::TypeInfo: Sync,
107126
Self::Context: Sync,
108-
__S: ::juniper::ScalarValue + Send + Sync,
127+
#scalar: ::juniper::ScalarValue + Send + Sync,
109128
{
110129
fn resolve_async<'a>(
111130
&'a self,
112131
info: &'a Self::TypeInfo,
113-
selection_set: Option<&'a [::juniper::Selection<__S>]>,
114-
executor: &'a ::juniper::Executor<Self::Context, __S>,
115-
) -> ::juniper::BoxFuture<'a, ::juniper::ExecutionResult<__S>> {
132+
selection_set: Option<&'a [::juniper::Selection<#scalar>]>,
133+
executor: &'a ::juniper::Executor<Self::Context, #scalar>,
134+
) -> ::juniper::BoxFuture<'a, ::juniper::ExecutionResult<#scalar>> {
116135
use ::juniper::futures::future;
117-
let v = ::juniper::GraphQLValue::resolve(self, info, selection_set, executor);
136+
let v = ::juniper::GraphQLValue::<#scalar>::resolve(self, info, selection_set, executor);
118137
Box::pin(future::ready(v))
119138
}
120139
}
@@ -123,80 +142,84 @@ fn impl_scalar_struct(
123142
let content = quote!(
124143
#_async
125144

126-
impl<S> ::juniper::GraphQLType<S> for #ident
145+
impl#impl_generics ::juniper::GraphQLType<#scalar> for #ident
127146
where
128-
S: ::juniper::ScalarValue,
147+
#scalar: ::juniper::ScalarValue,
129148
{
130149
fn name(_: &Self::TypeInfo) -> Option<&'static str> {
131150
Some(#name)
132151
}
133152

134153
fn meta<'r>(
135154
info: &Self::TypeInfo,
136-
registry: &mut ::juniper::Registry<'r, S>,
137-
) -> ::juniper::meta::MetaType<'r, S>
155+
registry: &mut ::juniper::Registry<'r, #scalar>,
156+
) -> ::juniper::meta::MetaType<'r, #scalar>
138157
where
139-
S: 'r,
158+
#scalar: 'r,
140159
{
141160
registry.build_scalar_type::<Self>(info)
142161
#description
143162
.into_meta()
144163
}
145164
}
146165

147-
impl<S> ::juniper::GraphQLValue<S> for #ident
166+
impl#impl_generics ::juniper::GraphQLValue<#scalar> for #ident
148167
where
149-
S: ::juniper::ScalarValue,
168+
#scalar: ::juniper::ScalarValue,
150169
{
151170
type Context = ();
152171
type TypeInfo = ();
153172

154173
fn type_name<'__i>(&self, info: &'__i Self::TypeInfo) -> Option<&'__i str> {
155-
<Self as ::juniper::GraphQLType<S>>::name(info)
174+
<Self as ::juniper::GraphQLType<#scalar>>::name(info)
156175
}
157176

158177
fn resolve(
159178
&self,
160179
info: &(),
161-
selection: Option<&[::juniper::Selection<S>]>,
162-
executor: &::juniper::Executor<Self::Context, S>,
163-
) -> ::juniper::ExecutionResult<S> {
164-
::juniper::GraphQLValue::resolve(&self.0, info, selection, executor)
180+
selection: Option<&[::juniper::Selection<#scalar>]>,
181+
executor: &::juniper::Executor<Self::Context, #scalar>,
182+
) -> ::juniper::ExecutionResult<#scalar> {
183+
::juniper::GraphQLValue::<#scalar>::resolve(&self.0, info, selection, executor)
165184
}
166185
}
167186

168-
impl<S> ::juniper::ToInputValue<S> for #ident
187+
impl#impl_generics ::juniper::ToInputValue<#scalar> for #ident
169188
where
170-
S: ::juniper::ScalarValue,
189+
#scalar: ::juniper::ScalarValue,
171190
{
172-
fn to_input_value(&self) -> ::juniper::InputValue<S> {
173-
::juniper::ToInputValue::to_input_value(&self.0)
191+
fn to_input_value(&self) -> ::juniper::InputValue<#scalar> {
192+
::juniper::ToInputValue::<#scalar>::to_input_value(&self.0)
174193
}
175194
}
176195

177-
impl<S> ::juniper::FromInputValue<S> for #ident
196+
impl#impl_generics ::juniper::FromInputValue<#scalar> for #ident
178197
where
179-
S: ::juniper::ScalarValue,
198+
#scalar: ::juniper::ScalarValue,
180199
{
181-
fn from_input_value(v: &::juniper::InputValue<S>) -> Option<#ident> {
182-
let inner: #inner_ty = ::juniper::FromInputValue::from_input_value(v)?;
200+
fn from_input_value(v: &::juniper::InputValue<#scalar>) -> Option<#ident> {
201+
let inner: #inner_ty = ::juniper::FromInputValue::<#scalar>::from_input_value(v)?;
183202
Some(#ident(inner))
184203
}
185204
}
186205

187-
impl<S> ::juniper::ParseScalarValue<S> for #ident
206+
impl#impl_generics ::juniper::ParseScalarValue<#scalar> for #ident
188207
where
189-
S: ::juniper::ScalarValue,
208+
#scalar: ::juniper::ScalarValue,
190209
{
191210
fn from_str<'a>(
192211
value: ::juniper::parser::ScalarToken<'a>,
193-
) -> ::juniper::ParseScalarResult<'a, S> {
194-
<#inner_ty as ::juniper::ParseScalarValue<S>>::from_str(value)
212+
) -> ::juniper::ParseScalarResult<'a, #scalar> {
213+
<#inner_ty as ::juniper::ParseScalarValue<#scalar>>::from_str(value)
195214
}
196215
}
197216

198-
impl<S: ::juniper::ScalarValue> ::juniper::marker::IsOutputType<S> for #ident { }
199-
impl<S: ::juniper::ScalarValue> ::juniper::marker::IsInputType<S> for #ident { }
217+
impl#impl_generics ::juniper::marker::IsOutputType<#scalar> for #ident
218+
where #scalar: ::juniper::ScalarValue,
219+
{ }
220+
impl#impl_generics ::juniper::marker::IsInputType<#scalar> for #ident
221+
where #scalar: ::juniper::ScalarValue,
222+
{ }
200223
);
201224

202225
Ok(content)

0 commit comments

Comments
 (0)