Skip to content

Commit 4cb6494

Browse files
committed
Upd docs
1 parent 2dc7d13 commit 4cb6494

File tree

1 file changed

+68
-15
lines changed

1 file changed

+68
-15
lines changed

juniper/src/value/scalar.rs

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -247,42 +247,95 @@ pub trait ScalarValue:
247247
///
248248
/// ```rust
249249
/// # use arcstr::ArcStr;
250-
/// # use juniper::{FromScalarValue, GraphQLScalar, Scalar, ScalarValue, TryScalarValueTo, Value};
250+
/// # use juniper::{FieldResult, GraphQLScalar, Scalar, ScalarValue, TryScalarValueTo, Value};
251251
/// #
252252
/// #[derive(GraphQLScalar)]
253253
/// #[graphql(from_input_with = Self::from_input, transparent)]
254254
/// struct Name(ArcStr);
255255
///
256256
/// impl Name {
257-
/// fn from_input<S: ScalarValue>(
258-
/// v: &Scalar<S>,
259-
/// ) -> Result<Self, <&str as FromScalarValue<S>>::Error> {
257+
/// fn from_input<S: ScalarValue>(v: &Scalar<S>) -> FieldResult<Self, S> {
260258
/// // Check if our `ScalarValue` is represented by an `ArcStr` already, and if so,
261259
/// // do the cheap `Clone` instead of allocating a new `ArcStr` in its `From<&str>`
262260
/// // implementation.
263-
/// if let Some(s) = v.downcast_type::<ArcStr>() {
264-
/// Ok(Self(s.clone()))
261+
/// let s = if let Some(s) = v.downcast_type::<ArcStr>() {
262+
/// s.clone()
265263
/// } else {
266-
/// v.try_to::<&str>().map(|s| Self(s.into()))
264+
/// v.try_to::<&str>().map(ArcStr::from)?
265+
/// };
266+
/// if s.chars().next().is_some_and(char::is_uppercase) {
267+
/// Ok(Self(s))
268+
/// } else {
269+
/// Err("`Name` should start with a capital letter".into())
270+
/// }
271+
/// }
272+
/// }
273+
/// ```
274+
///
275+
/// However, this method is needed only when the type doesn't implement a [`GraphQLScalar`]
276+
/// itself, or does it in non-optimal way. In reality, the [`ArcStr`] already implements a
277+
/// [`GraphQLScalar`] and does the [`ScalarValue::downcast_type()`] check in its implementation,
278+
/// which can be naturally reused by calling the [`ScalarValue::try_to()`] method.
279+
///
280+
/// ```rust
281+
/// # use arcstr::ArcStr;
282+
/// # use juniper::{FieldResult, GraphQLScalar, Scalar, ScalarValue, TryScalarValueTo, Value};
283+
/// #
284+
/// #[derive(GraphQLScalar)]
285+
/// #[graphql(from_input_with = Self::from_input, transparent)]
286+
/// struct Name(ArcStr);
287+
///
288+
/// impl Name {
289+
/// fn from_input(s: ArcStr) -> Result<Self, &'static str> {
290+
/// // ^^^^^^ macro expansion will call the `ScalarValue::try_to()` method
291+
/// // to extract this type from the `ScalarValue` to this function
292+
/// if s.chars().next().is_some_and(char::is_uppercase) {
293+
/// Ok(Self(s))
294+
/// } else {
295+
/// Err("`Name` should start with a capital letter")
267296
/// }
268297
/// }
269298
/// }
270299
/// ```
271300
#[must_use]
272301
fn downcast_type<T: Any>(&self) -> Option<&T>;
273-
274-
/// TODO: renew docs
302+
275303
/// Tries to represent this [`ScalarValue`] as the specified type `T`.
276-
///
277-
/// This method could be used instead of other helpers in case the [`TryScalarValueTo::Error`]
278-
/// is needed.
304+
///
305+
/// This method is the recommended way to parse a defined [`GraphQLScalar`] type `T` from a
306+
/// [`ScalarValue`].
307+
///
308+
/// This method could be used instead of other `try_*` helpers in case the
309+
/// [`FromScalarValue::Error`] is needed.
310+
///
311+
/// # Example
312+
///
313+
/// ```rust
314+
/// # use juniper::{DefaultScalarValue, GraphQLScalar, ScalarValue as _};
315+
///
316+
/// let v = DefaultScalarValue::Boolean(false);
317+
/// assert_eq!(v.try_to::<bool>().unwrap(), false);
318+
/// assert!(v.try_to::<f64>().is_err());
319+
///
320+
/// #[derive(Debug, GraphQLScalar, PartialEq)]
321+
/// #[graphql(transparent)]
322+
/// struct Name(String);
323+
///
324+
/// let v = DefaultScalarValue::String("John".into());
325+
/// assert_eq!(v.try_to::<String>().unwrap(), "John");
326+
/// assert_eq!(v.try_to::<&str>().unwrap(), "John");
327+
/// assert_eq!(v.try_to::<Name>().unwrap(), Name("John".into()));
328+
/// assert!(v.try_to::<i32>().is_err());
329+
/// ```
279330
///
280331
/// # Implementation
281332
///
282-
/// This method is an ergonomic alias for the [`TryScalarValueTo<T>`] conversion.
333+
/// This method is an ergonomic alias for the [`FromScalarValue<T>`] conversion.
283334
///
284-
/// Implementations should not implement this method, but rather implement the
285-
/// [`TryScalarValueTo<T>`] conversion directly.
335+
/// Implementations should not implement this method, but rather implement only the
336+
/// [`TryScalarValueTo<T>`] conversion directly in case `T` is a primitive built-in GraphQL
337+
/// scalar type ([`bool`], [`f64`], [`i32`], [`&str`], or [`String`]), otherwise the
338+
/// [`FromScalarValue<T>`] conversion is provided when a [`GraphQLScalar`] is implemented.
286339
fn try_to<'a, T>(&'a self) -> Result<T, T::Error>
287340
where
288341
T: FromScalarValue<'a, Self> + 'a,

0 commit comments

Comments
 (0)