@@ -105,31 +105,57 @@ fn to_output<S: ScalarValue>(v: &Incremented) -> Value<S> {
105105Customization of a [ custom GraphQL scalar] [ 2 ] value parsing is possible via ` #[graphql(from_input_with = <fn path>)] ` attribute:
106106``` rust
107107# extern crate juniper;
108- # use juniper :: {GraphQLScalar , InputValue , ScalarValue };
108+ # use juniper :: {GraphQLScalar , ScalarValue };
109109#
110110#[derive(GraphQLScalar )]
111111#[graphql(from_input_with = Self :: from_input, transparent)]
112112struct UserId (String );
113113
114114impl 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 ()
131125 })
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+ )
133159 }
134160}
135161#
@@ -143,8 +169,7 @@ Customization of which tokens a [custom GraphQL scalar][0] type should be parsed
143169``` rust
144170# extern crate juniper;
145171# use juniper :: {
146- # GraphQLScalar , InputValue , ParseScalarResult , ParseScalarValue ,
147- # ScalarValue , ScalarToken , Value ,
172+ # GraphQLScalar , ParseScalarResult , ParseScalarValue , Scalar , ScalarToken , ScalarValue , Value ,
148173# };
149174#
150175#[derive(GraphQLScalar )]
@@ -168,11 +193,11 @@ fn to_output<S: ScalarValue>(v: &StringOrInt) -> Value<S> {
168193 }
169194}
170195
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 () )
176201}
177202
178203fn 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
191216``` rust
192217# extern crate juniper;
193218# use juniper :: {
194- # GraphQLScalar , InputValue , ParseScalarResult , ParseScalarValue ,
195- # ScalarValue , ScalarToken , Value ,
219+ # GraphQLScalar , ParseScalarResult , ParseScalarValue , Scalar , ScalarToken , ScalarValue , Value ,
196220# };
197221#
198222#[derive(GraphQLScalar )]
@@ -212,11 +236,11 @@ mod string_or_int {
212236 }
213237 }
214238
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 () )
220244 }
221245
222246 pub (super ) fn parse_token <S : ScalarValue >(t : ScalarToken <'_ >) -> ParseScalarResult <S > {
@@ -232,8 +256,7 @@ A regular `impl` block is also suitable for that:
232256``` rust
233257# extern crate juniper;
234258# use juniper :: {
235- # GraphQLScalar , InputValue , ParseScalarResult , ParseScalarValue ,
236- # ScalarValue , ScalarToken , Value ,
259+ # GraphQLScalar , ParseScalarResult , ParseScalarValue , Scalar , ScalarToken , ScalarValue , Value ,
237260# };
238261#
239262#[derive(GraphQLScalar )]
@@ -251,14 +274,11 @@ impl StringOrInt {
251274 }
252275 }
253276
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 ())
262282 }
263283
264284 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
277297``` rust
278298# extern crate juniper;
279299# use juniper :: {
280- # GraphQLScalar , InputValue , ParseScalarResult , ScalarValue ,
281- # ScalarToken , Value
300+ # GraphQLScalar , ParseScalarResult , Scalar , ScalarToken , ScalarValue , Value ,
282301# };
283302#
284303#[derive(GraphQLScalar )]
@@ -304,14 +323,11 @@ mod string_or_int {
304323 }
305324 }
306325
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 ())
315331 }
316332
317333 // No need in `parse_token()` function.
@@ -351,9 +367,10 @@ For implementing [custom scalars][2] on foreign types there is [`#[graphql_scala
351367# }
352368#
353369# use juniper :: DefaultScalarValue as CustomScalarValue ;
354- use juniper :: {InputValue , ScalarValue , Value , graphql_scalar};
370+ use juniper :: {ScalarValue , Value , graphql_scalar};
355371
356- #[graphql_scalar(
372+ #[graphql_scalar]
373+ #[graphql(
357374 with = date_scalar,
358375 parse_token(String ),
359376 scalar = CustomScalarValue ,
@@ -369,10 +386,8 @@ mod date_scalar {
369386 Value :: scalar (v . to_string ())
370387 }
371388
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 ())
376391 }
377392}
378393#
0 commit comments