@@ -105,31 +105,57 @@ fn to_output<S: ScalarValue>(v: &Incremented) -> Value<S> {
105
105
Customization of a [ custom GraphQL scalar] [ 2 ] value parsing is possible via ` #[graphql(from_input_with = <fn path>)] ` attribute:
106
106
``` rust
107
107
# extern crate juniper;
108
- # use juniper :: {GraphQLScalar , InputValue , ScalarValue };
108
+ # use juniper :: {GraphQLScalar , ScalarValue };
109
109
#
110
110
#[derive(GraphQLScalar )]
111
111
#[graphql(from_input_with = Self :: from_input, transparent)]
112
112
struct UserId (String );
113
113
114
114
impl UserId {
115
- /// Checks whether the [`InputValue`] is a [`String`] beginning with `id: `
116
- /// and strips it.
117
- fn from_input <S >(input : & InputValue <S >) -> Result <Self , String >
118
- where
119
- S : ScalarValue
120
- {
121
- input . as_string_value ()
122
- . ok_or_else (|| format! (" Expected `String`, found: {input}" ))
123
- . and_then (| str | {
124
- str . strip_prefix (" id: " )
125
- . ok_or_else (|| {
126
- format! (
127
- " Expected `UserId` to begin with `id: `, \
128
- found: {input}" ,
129
- )
130
- })
115
+ /// Checks whether the [`InputValue`] is a [`String`] beginning with `id: ` and strips it.
116
+ fn from_input (
117
+ input : & str ,
118
+ // ^^^^ any concrete type having `TryScalarValueTo` implementation could be used
119
+ ) -> Result <Self , Box <str >> {
120
+ // ^^^^^^^^ must implement `IntoFieldError`
121
+ input
122
+ . strip_prefix (" id: " )
123
+ . ok_or_else (|| {
124
+ format! (" Expected `UserId` to begin with `id: `, found: {input}" ). into ()
131
125
})
132
- . map (| id | Self (id . to_owned ()))
126
+ . map (| id | Self (id . into ()))
127
+ }
128
+ }
129
+ #
130
+ # fn main () {}
131
+ ```
132
+
133
+ The provided function is polymorphic by input and output types:
134
+ ``` rust
135
+ # extern crate juniper;
136
+ # use juniper :: {GraphQLScalar , Scalar , ScalarValue };
137
+ #
138
+ #[derive(GraphQLScalar )]
139
+ #[graphql(from_input_with = Self :: from_input, transparent)]
140
+ struct UserId (String );
141
+
142
+ impl UserId {
143
+ fn from_input (
144
+ input : & Scalar <impl ScalarValue >,
145
+ // ^^^^^^ for generic argument using `Scalar` transparent wrapper is required,
146
+ // otherwise Rust won't be able to infer the required type
147
+ ) -> Self {
148
+ // ^^^^ if the result is infallible, it's OK to not use `Result`
149
+ Self (
150
+ input
151
+ . try_to_int (). map (| i | i . to_string ())
152
+ . or_else (|| input . try_to_bool (). map (| f | f . to_string ()))
153
+ . or_else (|| input . try_to_float (). map (| b | b . to_string ()))
154
+ . or_else (|| input . try_to_string ())
155
+ . unwrap_or_else (|| {
156
+ unreachable! (" `ScalarValue` is at least one of primitive GraphQL types" )
157
+ }),
158
+ )
133
159
}
134
160
}
135
161
#
@@ -143,8 +169,7 @@ Customization of which tokens a [custom GraphQL scalar][0] type should be parsed
143
169
``` rust
144
170
# extern crate juniper;
145
171
# use juniper :: {
146
- # GraphQLScalar , InputValue , ParseScalarResult , ParseScalarValue ,
147
- # ScalarValue , ScalarToken , Value ,
172
+ # GraphQLScalar , ParseScalarResult , ParseScalarValue , Scalar , ScalarToken , ScalarValue , Value ,
148
173
# };
149
174
#
150
175
#[derive(GraphQLScalar )]
@@ -168,11 +193,11 @@ fn to_output<S: ScalarValue>(v: &StringOrInt) -> Value<S> {
168
193
}
169
194
}
170
195
171
- fn from_input < S : ScalarValue > (v : & InputValue < S >) -> Result <StringOrInt , String > {
172
- v . as_string_value ()
173
- . map (| s | StringOrInt :: String ( s . into ()) )
174
- . or_else (|| v . as_int_value (). map (StringOrInt :: Int ))
175
- . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ))
196
+ fn from_input (v : & Scalar < impl ScalarValue >) -> Result <StringOrInt , Box < str > > {
197
+ v . try_to_string ()
198
+ . map (StringOrInt :: String )
199
+ . or_else (|| v . try_to_int (). map (StringOrInt :: Int ))
200
+ . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ). into () )
176
201
}
177
202
178
203
fn parse_token <S : ScalarValue >(value : ScalarToken <'_ >) -> ParseScalarResult <S > {
@@ -191,8 +216,7 @@ Instead of providing all custom functions separately, it's possible to provide a
191
216
``` rust
192
217
# extern crate juniper;
193
218
# use juniper :: {
194
- # GraphQLScalar , InputValue , ParseScalarResult , ParseScalarValue ,
195
- # ScalarValue , ScalarToken , Value ,
219
+ # GraphQLScalar , ParseScalarResult , ParseScalarValue , Scalar , ScalarToken , ScalarValue , Value ,
196
220
# };
197
221
#
198
222
#[derive(GraphQLScalar )]
@@ -212,11 +236,11 @@ mod string_or_int {
212
236
}
213
237
}
214
238
215
- pub (super ) fn from_input < S : ScalarValue > (v : & InputValue < S >) -> Result <StringOrInt , String > {
216
- v . as_string_value ()
217
- . map (| s | StringOrInt :: String ( s . into ()) )
218
- . or_else (|| v . as_int_value (). map (StringOrInt :: Int ))
219
- . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ))
239
+ pub (super ) fn from_input (v : & Scalar < impl ScalarValue >) -> Result <StringOrInt , Box < str > > {
240
+ v . try_to_string ()
241
+ . map (StringOrInt :: String )
242
+ . or_else (|| v . try_to_int (). map (StringOrInt :: Int ))
243
+ . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ). into () )
220
244
}
221
245
222
246
pub (super ) fn parse_token <S : ScalarValue >(t : ScalarToken <'_ >) -> ParseScalarResult <S > {
@@ -232,8 +256,7 @@ A regular `impl` block is also suitable for that:
232
256
``` rust
233
257
# extern crate juniper;
234
258
# use juniper :: {
235
- # GraphQLScalar , InputValue , ParseScalarResult , ParseScalarValue ,
236
- # ScalarValue , ScalarToken , Value ,
259
+ # GraphQLScalar , ParseScalarResult , ParseScalarValue , Scalar , ScalarToken , ScalarValue , Value ,
237
260
# };
238
261
#
239
262
#[derive(GraphQLScalar )]
@@ -251,14 +274,11 @@ impl StringOrInt {
251
274
}
252
275
}
253
276
254
- fn from_input <S >(v : & InputValue <S >) -> Result <Self , String >
255
- where
256
- S : ScalarValue
257
- {
258
- v . as_string_value ()
259
- . map (| s | Self :: String (s . into ()))
260
- . or_else (|| v . as_int_value (). map (Self :: Int ))
261
- . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ))
277
+ fn from_input (v : & Scalar <impl ScalarValue >) -> Result <Self , Box <str >> {
278
+ v . try_to_string ()
279
+ . map (Self :: String )
280
+ . or_else (|| v . try_to_int (). map (Self :: Int ))
281
+ . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ). into ())
262
282
}
263
283
264
284
fn parse_token <S >(value : ScalarToken <'_ >) -> ParseScalarResult <S >
@@ -277,8 +297,7 @@ At the same time, any custom function still may be specified separately, if requ
277
297
``` rust
278
298
# extern crate juniper;
279
299
# use juniper :: {
280
- # GraphQLScalar , InputValue , ParseScalarResult , ScalarValue ,
281
- # ScalarToken , Value
300
+ # GraphQLScalar , ParseScalarResult , Scalar , ScalarToken , ScalarValue , Value ,
282
301
# };
283
302
#
284
303
#[derive(GraphQLScalar )]
@@ -304,14 +323,11 @@ mod string_or_int {
304
323
}
305
324
}
306
325
307
- pub (super ) fn from_input <S >(v : & InputValue <S >) -> Result <StringOrInt , String >
308
- where
309
- S : ScalarValue ,
310
- {
311
- v . as_string_value ()
312
- . map (| s | StringOrInt :: String (s . into ()))
313
- . or_else (|| v . as_int_value (). map (StringOrInt :: Int ))
314
- . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ))
326
+ pub (super ) fn from_input (v : & Scalar <impl ScalarValue >) -> Result <StringOrInt , Box <str >> {
327
+ v . try_to_string ()
328
+ . map (StringOrInt :: String )
329
+ . or_else (|| v . try_to_int (). map (StringOrInt :: Int ))
330
+ . ok_or_else (|| format! (" Expected `String` or `Int`, found: {v}" ). into ())
315
331
}
316
332
317
333
// No need in `parse_token()` function.
@@ -351,9 +367,10 @@ For implementing [custom scalars][2] on foreign types there is [`#[graphql_scala
351
367
# }
352
368
#
353
369
# use juniper :: DefaultScalarValue as CustomScalarValue ;
354
- use juniper :: {InputValue , ScalarValue , Value , graphql_scalar};
370
+ use juniper :: {ScalarValue , Value , graphql_scalar};
355
371
356
- #[graphql_scalar(
372
+ #[graphql_scalar]
373
+ #[graphql(
357
374
with = date_scalar,
358
375
parse_token(String ),
359
376
scalar = CustomScalarValue ,
@@ -369,10 +386,8 @@ mod date_scalar {
369
386
Value :: scalar (v . to_string ())
370
387
}
371
388
372
- pub (super ) fn from_input (v : & InputValue <CustomScalarValue >) -> Result <Date , String > {
373
- v . as_string_value ()
374
- . ok_or_else (|| format! (" Expected `String`, found: {v}" ))
375
- . and_then (| s | s . parse (). map_err (| e | format! (" Failed to parse `Date`: {e}" )))
389
+ pub (super ) fn from_input (s : & str ) -> Result <Date , Box <str >> {
390
+ s . parse (). map_err (| e | format! (" Failed to parse `Date`: {e}" ). into ())
376
391
}
377
392
}
378
393
#
0 commit comments