Skip to content

Commit 2ba9f71

Browse files
andrisakLegNeato
andauthored
Make graphql_scalar a proc macro (#610)
Fixes #571 Signed-off-by: andrisak <[email protected]> * Replaced the old macro with the new proc macro. Updated documentation. Signed-off-by: andrisak <[email protected]> Co-authored-by: Christian Legnitto <[email protected]>
1 parent fe99e1c commit 2ba9f71

File tree

19 files changed

+651
-569
lines changed

19 files changed

+651
-569
lines changed

docs/book/content/types/scalars.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ There are two ways to define custom scalars.
1212
* For simple scalars that just wrap a primitive type, you can use the newtype pattern with
1313
a custom derive.
1414
* For more advanced use cases with custom validation, you can use
15-
the `graphql_scalar!` macro.
15+
the `graphql_scalar` proc macro.
1616

1717

1818
## Built-in scalars
@@ -79,7 +79,7 @@ pub struct UserId(i32);
7979
## Custom scalars
8080

8181
For more complex situations where you also need custom parsing or validation,
82-
you can use the `graphql_scalar!` macro.
82+
you can use the `graphql_scalar` proc macro.
8383

8484
Typically, you represent your custom scalars as strings.
8585

@@ -112,26 +112,28 @@ The example below is used just for illustration.
112112
use juniper::{Value, ParseScalarResult, ParseScalarValue};
113113
use date::Date;
114114

115-
juniper::graphql_scalar!(Date where Scalar = <S> {
116-
description: "Date"
117-
115+
#[juniper::graphql_scalar(description = "Date")]
116+
impl<S> GraphQLScalar for Date
117+
where
118+
S: ScalarValue
119+
{
118120
// Define how to convert your custom scalar into a primitive type.
119-
resolve(&self) -> Value {
121+
fn resolve(&self) -> Value {
120122
Value::scalar(self.to_string())
121123
}
122124

123125
// Define how to parse a primitive type into your custom scalar.
124-
from_input_value(v: &InputValue) -> Option<Date> {
126+
fn from_input_value(v: &InputValue) -> Option<Date> {
125127
v.as_scalar_value()
126128
.and_then(|v| v.as_str())
127129
.and_then(|s| s.parse().ok())
128130
}
129131

130132
// Define how to parse a string value.
131-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
133+
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
132134
<String as ParseScalarValue<S>>::from_str(value)
133135
}
134-
});
136+
}
135137

136138
# fn main() {}
137139
```

juniper/src/macros/tests/scalar.rs renamed to integration_tests/juniper_tests/src/codegen/impl_scalar.rs

Lines changed: 43 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
use crate::{
2-
executor::Variables,
3-
schema::model::RootNode,
4-
types::scalars::{EmptyMutation, EmptySubscription},
5-
value::{DefaultScalarValue, Object, ParseScalarResult, ParseScalarValue, Value},
1+
use juniper::{
2+
DefaultScalarValue, EmptyMutation, EmptySubscription, Object, ParseScalarResult,
3+
ParseScalarValue, RootNode, Value, Variables,
64
};
75

86
struct DefaultName(i32);
@@ -21,66 +19,72 @@ Syntax to validate:
2119
2220
*/
2321

24-
graphql_scalar!(DefaultName where Scalar = <S> {
25-
resolve(&self) -> Value {
22+
#[juniper::graphql_scalar]
23+
impl<S> GraphQLScalar for DefaultName
24+
where
25+
S: juniper::ScalarValue,
26+
{
27+
fn resolve(&self) -> Value {
2628
Value::scalar(self.0)
2729
}
2830

29-
from_input_value(v: &InputValue) -> Option<DefaultName> {
30-
v.as_scalar_value().and_then(|s| s.as_int()).map(|i| DefaultName(i))
31+
fn from_input_value(v: &juniper::InputValue) -> Option<DefaultName> {
32+
v.as_scalar_value()
33+
.and_then(|s| s.as_int())
34+
.map(|i| DefaultName(i))
3135
}
3236

33-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, S> {
37+
fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, S> {
3438
<i32 as ParseScalarValue<S>>::from_str(value)
3539
}
36-
});
40+
}
3741

38-
graphql_scalar!(OtherOrder {
39-
resolve(&self) -> Value {
42+
#[juniper::graphql_scalar]
43+
impl GraphQLScalar for OtherOrder {
44+
fn resolve(&self) -> Value {
4045
Value::scalar(self.0)
4146
}
4247

43-
from_input_value(v: &InputValue) -> Option<OtherOrder> {
48+
fn from_input_value(v: &juniper::InputValue) -> Option<OtherOrder> {
4449
v.as_scalar_value::<i32>().map(|i| OtherOrder(*i))
4550
}
4651

47-
48-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
52+
fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
4953
<i32 as ParseScalarValue>::from_str(value)
5054
}
51-
});
55+
}
5256

53-
graphql_scalar!(Named as "ANamedScalar" where Scalar = DefaultScalarValue {
54-
resolve(&self) -> Value {
57+
#[juniper::graphql_scalar(name = "ANamedScalar")]
58+
impl GraphQLScalar for Named {
59+
fn resolve(&self) -> Value {
5560
Value::scalar(self.0)
5661
}
5762

58-
from_input_value(v: &InputValue) -> Option<Named> {
63+
fn from_input_value(v: &juniper::InputValue) -> Option<Named> {
5964
v.as_scalar_value::<i32>().map(|i| Named(*i))
6065
}
6166

62-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
67+
fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
6368
<i32 as ParseScalarValue>::from_str(value)
6469
}
65-
});
66-
67-
graphql_scalar!(ScalarDescription {
68-
description: "A sample scalar, represented as an integer"
70+
}
6971

70-
resolve(&self) -> Value {
72+
#[juniper::graphql_scalar(description = "A sample scalar, represented as an integer")]
73+
impl GraphQLScalar for ScalarDescription {
74+
fn resolve(&self) -> Value {
7175
Value::scalar(self.0)
7276
}
7377

74-
from_input_value(v: &InputValue) -> Option<ScalarDescription> {
78+
fn from_input_value(v: &juniper::InputValue) -> Option<ScalarDescription> {
7579
v.as_scalar_value::<i32>().map(|i| ScalarDescription(*i))
7680
}
7781

78-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a> {
82+
fn from_str<'a>(value: juniper::ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
7983
<i32 as ParseScalarValue>::from_str(value)
8084
}
81-
});
85+
}
8286

83-
#[crate::graphql_object_internal]
87+
#[juniper::graphql_object]
8488
impl Root {
8589
fn default_name() -> DefaultName {
8690
DefaultName(0)
@@ -106,7 +110,7 @@ where
106110
EmptySubscription::<()>::new(),
107111
);
108112

109-
let (result, errs) = crate::execute(doc, None, &schema, &Variables::new(), &())
113+
let (result, errs) = juniper::execute(doc, None, &schema, &Variables::new(), &())
110114
.await
111115
.expect("Execution failed");
112116

@@ -129,19 +133,22 @@ where
129133
fn path_in_resolve_return_type() {
130134
struct ResolvePath(i32);
131135

132-
graphql_scalar!(ResolvePath {
133-
resolve(&self) -> self::Value {
136+
#[juniper::graphql_scalar]
137+
impl GraphQLScalar for ResolvePath {
138+
fn resolve(&self) -> self::Value {
134139
Value::scalar(self.0)
135140
}
136141

137-
from_input_value(v: &InputValue) -> Option<ResolvePath> {
142+
fn from_input_value(v: &juniper::InputValue) -> Option<ResolvePath> {
138143
v.as_scalar_value::<i32>().map(|i| ResolvePath(*i))
139144
}
140145

141-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a> {
146+
fn from_str<'a>(
147+
value: juniper::ScalarToken<'a>,
148+
) -> ParseScalarResult<'a, DefaultScalarValue> {
142149
<i32 as ParseScalarValue>::from_str(value)
143150
}
144-
});
151+
}
145152
}
146153

147154
#[tokio::test]

integration_tests/juniper_tests/src/codegen/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ mod derive_input_object;
33
mod derive_object;
44
mod derive_object_with_raw_idents;
55
mod derive_union;
6+
mod impl_scalar;
67
mod impl_union;
78
mod scalar_value_transparent;

integration_tests/juniper_tests/src/custom_scalar.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,28 +133,29 @@ impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
133133
}
134134
}
135135

136-
juniper::graphql_scalar!(i64 as "Long" where Scalar = MyScalarValue {
137-
resolve(&self) -> Value {
136+
#[juniper::graphql_scalar(name = "Long")]
137+
impl GraphQLScalar for i64 {
138+
fn resolve(&self) -> Value {
138139
Value::scalar(*self)
139140
}
140141

141-
from_input_value(v: &InputValue) -> Option<i64> {
142+
fn from_input_value(v: &InputValue) -> Option<i64> {
142143
match *v {
143144
InputValue::Scalar(MyScalarValue::Long(i)) => Some(i),
144145
_ => None,
145146
}
146147
}
147148

148-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, MyScalarValue> {
149+
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, MyScalarValue> {
149150
if let ScalarToken::Int(v) = value {
150-
v.parse()
151-
.map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
152-
.map(|s: i64| s.into())
151+
v.parse()
152+
.map_err(|_| ParseError::UnexpectedToken(Token::Scalar(value)))
153+
.map(|s: i64| s.into())
153154
} else {
154-
Err(ParseError::UnexpectedToken(Token::Scalar(value)))
155+
Err(ParseError::UnexpectedToken(Token::Scalar(value)))
155156
}
156157
}
157-
});
158+
}
158159

159160
struct TestType;
160161

juniper/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ See [#618](https://github.com/graphql-rust/juniper/pull/618).
3636

3737
- remove old `graphql_object!` macro, rename `object` proc macro to `graphql_object`
3838

39+
- remove old `graphql_scalar!` macro, rename `scalar` proc macro to `graphql_scalar`
40+
3941
- Remove deprecated `ScalarValue` custom derive (renamed to GraphQLScalarValue)
4042

4143
- `graphql_union!` macro removed, replaced by `#[graphql_union]` proc macro

juniper/src/ast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ pub type Document<'a, S> = Vec<Definition<'a, S>>;
147147
/// Parse an unstructured input value into a Rust data type.
148148
///
149149
/// The conversion _can_ fail, and must in that case return None. Implemented
150-
/// automatically by the convenience macro `graphql_scalar!` or by deriving GraphQLEnum.
150+
/// automatically by the convenience proc macro `graphql_scalar` or by deriving GraphQLEnum.
151151
///
152152
/// Must be implemented manually when manually exposing new enums or scalars.
153153
pub trait FromInputValue<S = DefaultScalarValue>: Sized {

juniper/src/executor_tests/introspection/mod.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
executor::Variables,
1212
schema::model::RootNode,
1313
types::scalars::{EmptyMutation, EmptySubscription},
14-
value::{ParseScalarResult, ParseScalarValue, Value},
14+
value::{DefaultScalarValue, ParseScalarResult, ParseScalarValue, Value},
1515
};
1616

1717
#[derive(GraphQLEnum)]
@@ -27,19 +27,20 @@ struct Interface;
2727

2828
struct Root;
2929

30-
graphql_scalar!(Scalar as "SampleScalar" {
31-
resolve(&self) -> Value {
30+
#[crate::graphql_scalar_internal(name = "SampleScalar")]
31+
impl GraphQLScalar for Scalar {
32+
fn resolve(&self) -> Value {
3233
Value::scalar(self.0)
3334
}
3435

35-
from_input_value(v: &InputValue) -> Option<Scalar> {
36+
fn from_input_value(v: &InputValue) -> Option<Scalar> {
3637
v.as_scalar_value().map(|i: &i32| Scalar(*i))
3738
}
3839

39-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a> {
40+
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
4041
<i32 as ParseScalarValue>::from_str(value)
4142
}
42-
});
43+
}
4344

4445
graphql_interface!(Interface: () as "SampleInterface" |&self| {
4546
description: "A sample interface"

juniper/src/executor_tests/variables.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@ struct TestComplexScalar;
1616

1717
struct TestType;
1818

19-
graphql_scalar!(TestComplexScalar {
20-
resolve(&self) -> Value {
19+
#[crate::graphql_scalar_internal]
20+
impl GraphQLScalar for TestComplexScalar {
21+
fn resolve(&self) -> Value {
2122
Value::scalar(String::from("SerializedValue"))
2223
}
2324

24-
from_input_value(v: &InputValue) -> Option<TestComplexScalar> {
25+
fn from_input_value(v: &InputValue) -> Option<TestComplexScalar> {
2526
if let Some(s) = v.as_scalar_value::<String>() {
2627
if *s == "SerializedValue" {
2728
return Some(TestComplexScalar);
@@ -31,10 +32,10 @@ graphql_scalar!(TestComplexScalar {
3132
None
3233
}
3334

34-
from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a> {
35-
<String as ParseScalarValue<_>>::from_str(value)
35+
fn from_str<'a>(value: ScalarToken<'a>) -> ParseScalarResult<'a, DefaultScalarValue> {
36+
<String as ParseScalarValue>::from_str(value)
3637
}
37-
});
38+
}
3839

3940
#[derive(GraphQLInputObject, Debug)]
4041
#[graphql(scalar = "DefaultScalarValue")]

0 commit comments

Comments
 (0)