Skip to content

Commit a00f807

Browse files
committed
Fix codegen tests and docs
1 parent a312e57 commit a00f807

File tree

3 files changed

+87
-72
lines changed

3 files changed

+87
-72
lines changed

juniper_codegen/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ syn = { version = "2.0", features = ["extra-traits", "full", "visit", "visit-mut
2929
url = "2.0"
3030

3131
[dev-dependencies]
32-
derive_more = { version = "2.0", features = ["from"] }
32+
derive_more = { version = "2.0", features = ["from", "try_into"] }
3333
futures = "0.3.22"
3434
juniper = { path = "../juniper" }
3535
serde = "1.0.122"

juniper_codegen/src/graphql_enum/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,9 @@ impl Definition {
594594
fn from_input_value(
595595
v: &::juniper::InputValue<#scalar>,
596596
) -> ::core::result::Result<Self, Self::Error> {
597-
match v.as_enum_value().or_else(|| v.as_scalar()?.try_as_str()) {
597+
match v.as_enum_value()
598+
.or_else(|| ::juniper::ScalarValue::try_as_str(v.as_scalar()?))
599+
{
598600
#( #variants )*
599601
_ => ::core::result::Result::Err(
600602
::std::format!("Unknown enum value: {}", v),

juniper_codegen/src/lib.rs

Lines changed: 83 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,13 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
365365
})
366366
}
367367

368-
/// `#[derive(GraphQLScalar)]` macro for deriving a [GraphQL scalar][0]
369-
/// implementation.
368+
/// `#[derive(GraphQLScalar)]` macro for deriving a [GraphQL scalar][0] implementation.
370369
///
371370
/// # Transparent delegation
372371
///
373-
/// Quite often we want to create a custom [GraphQL scalar][0] type by just
374-
/// wrapping an existing one, inheriting all its behavior. In Rust, this is
375-
/// often called as ["newtype pattern"][1]. This is achieved by annotating
376-
/// the definition with the `#[graphql(transparent)]` attribute:
372+
/// Quite often we want to create a custom [GraphQL scalar][0] type by just wrapping an existing
373+
/// one, inheriting all its behavior. In Rust, this is often called as ["newtype pattern"][1]. This
374+
/// could be achieved by annotating the definition with the `#[graphql(transparent)]` attribute:
377375
/// ```rust
378376
/// # use juniper::{GraphQLObject, GraphQLScalar};
379377
/// #
@@ -415,8 +413,8 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
415413
/// struct UserId(String);
416414
/// ```
417415
///
418-
/// All the methods inherited from `Newtype`'s field may also be overridden
419-
/// with the attributes described below.
416+
/// All the methods inherited from `Newtype`'s field may also be overridden with the attributes
417+
/// described below.
420418
///
421419
/// # Custom resolving
422420
///
@@ -440,7 +438,7 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
440438
/// Customization of a [GraphQL scalar][0] type parsing is possible via
441439
/// `#[graphql(from_input_with = <fn path>)]` attribute:
442440
/// ```rust
443-
/// # use juniper::{DefaultScalarValue, GraphQLScalar, ScalarValue};
441+
/// # use juniper::{GraphQLScalar, ScalarValue};
444442
/// #
445443
/// #[derive(GraphQLScalar)]
446444
/// #[graphql(from_input_with = Self::from_input, transparent)]
@@ -450,34 +448,57 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
450448
/// /// Checks whether the [`ScalarValue`] is a [`String`] beginning with
451449
/// /// `id: ` and strips it.
452450
/// fn from_input(
453-
/// input: &impl ScalarValue,
454-
/// ) -> Result<Self, String> {
455-
/// // ^^^^^^ must implement `IntoFieldError`
456-
/// input.try_as_str()
457-
/// .ok_or_else(|| format!("Expected `String`, found: {input}"))
458-
/// .and_then(|str| {
459-
/// str.strip_prefix("id: ")
460-
/// .ok_or_else(|| {
461-
/// format!(
462-
/// "Expected `UserId` to begin with `id: `, \
463-
/// found: {input}",
464-
/// )
465-
/// })
451+
/// input: &str,
452+
/// // ^^^^ any concrete type having `TryScalarValueTo` implementation could be used
453+
/// ) -> Result<Self, Box<str>> {
454+
/// // ^^^^^^^^ must implement `IntoFieldError`
455+
/// input
456+
/// .strip_prefix("id: ")
457+
/// .ok_or_else(|| {
458+
/// format!("Expected `UserId` to begin with `id: `, found: {input}").into()
466459
/// })
467460
/// .map(|id| Self(id.into()))
468461
/// }
469462
/// }
470463
/// ```
471464
///
465+
/// The provided function is polymorphic by input and output types:
466+
/// ```rust
467+
/// # use juniper::{GraphQLScalar, Scalar, ScalarValue};
468+
/// #
469+
/// #[derive(GraphQLScalar)]
470+
/// #[graphql(from_input_with = Self::from_input, transparent)]
471+
/// struct UserId(String);
472+
///
473+
/// impl UserId {
474+
/// fn from_input(
475+
/// input: &Scalar<impl ScalarValue>,
476+
/// // ^^^^^^ for generic argument using `Scalar` transparent wrapper is required,
477+
/// // otherwise Rust won't be able to infer the required type
478+
/// ) -> Self {
479+
/// // ^^^^ if the result is infallible, it's OK to not use `Result`
480+
/// Self(
481+
/// input
482+
/// .try_to_int().map(|i| i.to_string())
483+
/// .or_else(|| input.try_to_bool().map(|f| f.to_string()))
484+
/// .or_else(|| input.try_to_float().map(|b| b.to_string()))
485+
/// .or_else(|| input.try_to_string())
486+
/// .unwrap_or_else(|| {
487+
/// unreachable!("`ScalarValue` is at least one of primitive GraphQL types")
488+
/// }),
489+
/// )
490+
/// }
491+
/// }
492+
/// ```
493+
///
472494
/// # Custom token parsing
473495
///
474-
/// Customization of which tokens a [GraphQL scalar][0] type should be parsed is
475-
/// possible via `#[graphql(parse_token_with = <fn path>)]` or
476-
/// `#[graphql(parse_token(<types>)]` attributes:
496+
/// Customization of which tokens a [GraphQL scalar][0] type should be parsed is possible via
497+
/// `#[graphql(parse_token_with = <fn path>)]` or `#[graphql(parse_token(<types>)]` attributes:
477498
/// ```rust
478499
/// # use juniper::{
479-
/// # GraphQLScalar, ParseScalarResult, ParseScalarValue, ScalarValue,
480-
/// # ScalarToken, Value,
500+
/// # GraphQLScalar, ParseScalarResult, ParseScalarValue, Scalar, ScalarToken, ScalarValue,
501+
/// # Value,
481502
/// # };
482503
/// #
483504
/// #[derive(GraphQLScalar)]
@@ -501,30 +522,29 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
501522
/// }
502523
/// }
503524
///
504-
/// fn from_input(v: &impl ScalarValue) -> Result<StringOrInt, String> {
525+
/// fn from_input(v: &Scalar<impl ScalarValue>) -> Result<StringOrInt, Box<str>> {
505526
/// v.try_to_string()
506527
/// .map(StringOrInt::String)
507528
/// .or_else(|| v.try_to_int().map(StringOrInt::Int))
508-
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
529+
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into())
509530
/// }
510531
///
511532
/// fn parse_token<S: ScalarValue>(value: ScalarToken<'_>) -> ParseScalarResult<S> {
512533
/// <String as ParseScalarValue<S>>::from_str(value)
513534
/// .or_else(|_| <i32 as ParseScalarValue<S>>::from_str(value))
514535
/// }
515536
/// ```
516-
/// > __NOTE:__ Once we provide all 3 custom functions, there is no sense in
517-
/// > following the [newtype pattern][1] anymore.
537+
/// > __NOTE:__ Once we provide all 3 custom functions, there is no sense in following the
538+
/// > [newtype pattern][1] anymore.
518539
///
519540
/// # Full behavior
520541
///
521-
/// Instead of providing all custom functions separately, it's possible to
522-
/// provide a module holding the appropriate `to_output()`, `from_input()` and
523-
/// `parse_token()` functions:
542+
/// Instead of providing all custom functions separately, it's possible to provide a module holding
543+
/// the appropriate `to_output()`, `from_input()` and `parse_token()` functions:
524544
/// ```rust
525545
/// # use juniper::{
526-
/// # GraphQLScalar, ParseScalarResult, ParseScalarValue, ScalarValue,
527-
/// # ScalarToken, Value,
546+
/// # GraphQLScalar, ParseScalarResult, ParseScalarValue, Scalar, ScalarToken, ScalarValue,
547+
/// # Value,
528548
/// # };
529549
/// #
530550
/// #[derive(GraphQLScalar)]
@@ -544,11 +564,11 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
544564
/// }
545565
/// }
546566
///
547-
/// pub(super) fn from_input(v: &impl ScalarValue) -> Result<StringOrInt, String> {
567+
/// pub(super) fn from_input(v: &Scalar<impl ScalarValue>) -> Result<StringOrInt, Box<str>> {
548568
/// v.try_to_string()
549569
/// .map(StringOrInt::String)
550570
/// .or_else(|| v.try_to_int().map(StringOrInt::Int))
551-
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
571+
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into())
552572
/// }
553573
///
554574
/// pub(super) fn parse_token<S: ScalarValue>(t: ScalarToken<'_>) -> ParseScalarResult<S> {
@@ -563,8 +583,8 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
563583
/// A regular `impl` block is also suitable for that:
564584
/// ```rust
565585
/// # use juniper::{
566-
/// # GraphQLScalar, ParseScalarResult, ParseScalarValue, ScalarValue,
567-
/// # ScalarToken, Value,
586+
/// # GraphQLScalar, ParseScalarResult, ParseScalarValue, Scalar, ScalarToken, ScalarValue,
587+
/// # Value,
568588
/// # };
569589
/// #
570590
/// #[derive(GraphQLScalar)]
@@ -582,11 +602,11 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
582602
/// }
583603
/// }
584604
///
585-
/// fn from_input(v: &impl ScalarValue) -> Result<Self, String> {
605+
/// fn from_input(v: &Scalar<impl ScalarValue>) -> Result<Self, Box<str>> {
586606
/// v.try_to_string()
587607
/// .map(Self::String)
588608
/// .or_else(|| v.try_to_int().map(Self::Int))
589-
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
609+
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into())
590610
/// }
591611
///
592612
/// fn parse_token<S>(value: ScalarToken<'_>) -> ParseScalarResult<S>
@@ -603,9 +623,7 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
603623
///
604624
/// At the same time, any custom function still may be specified separately:
605625
/// ```rust
606-
/// # use juniper::{
607-
/// # GraphQLScalar, ParseScalarResult, ScalarValue, ScalarToken, Value,
608-
/// # };
626+
/// # use juniper::{GraphQLScalar, ParseScalarResult, Scalar, ScalarToken, ScalarValue, Value};
609627
/// #
610628
/// #[derive(GraphQLScalar)]
611629
/// #[graphql(
@@ -630,11 +648,11 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
630648
/// }
631649
/// }
632650
///
633-
/// pub(super) fn from_input(v: &impl ScalarValue) -> Result<StringOrInt, String> {
651+
/// pub(super) fn from_input(v: &Scalar<impl ScalarValue>) -> Result<StringOrInt, Box<str>> {
634652
/// v.try_to_string()
635653
/// .map(StringOrInt::String)
636654
/// .or_else(|| v.try_to_int().map(StringOrInt::Int))
637-
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}"))
655+
/// .ok_or_else(|| format!("Expected `String` or `Int`, found: {v}").into())
638656
/// }
639657
///
640658
/// // No need in `parse_token()` function.
@@ -645,18 +663,17 @@ pub fn derive_enum(input: TokenStream) -> TokenStream {
645663
///
646664
/// # Custom `ScalarValue`
647665
///
648-
/// By default, this macro generates code, which is generic over a
649-
/// [`ScalarValue`] type. Concrete [`ScalarValue`] type may be specified via
650-
/// `#[graphql(scalar = <type>)]` attribute.
666+
/// By default, this macro generates code, which is generic over a [`ScalarValue`] type. Concrete
667+
/// [`ScalarValue`] type may be specified via the `#[graphql(scalar = <type>)]` attribute.
651668
///
652-
/// It also may be used to provide additional bounds to the [`ScalarValue`]
653-
/// generic, like the following: `#[graphql(scalar = S: Trait)]`.
669+
/// It also may be used to provide additional bounds to the [`ScalarValue`] generic, like the
670+
/// following: `#[graphql(scalar = S: Trait)]`.
654671
///
655672
/// # Additional arbitrary trait bounds
656673
///
657-
/// [GraphQL scalar][0] type implementation may be bound with any additional
658-
/// trait bounds via `#[graphql(where(<bounds>))]` attribute, like the
659-
/// following: `#[graphql(where(S: Trait, Self: fmt::Debug + fmt::Display))]`.
674+
/// [GraphQL scalar][0] type implementation may be bound with any additional trait bounds via
675+
/// `#[graphql(where(<bounds>))]` attribute, like the following:
676+
/// `#[graphql(where(S: Trait, Self: fmt::Debug + fmt::Display))]`.
660677
///
661678
/// [0]: https://spec.graphql.org/October2021#sec-Scalars
662679
/// [1]: https://rust-unofficial.github.io/patterns/patterns/behavioural/newtype.html
@@ -670,9 +687,8 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream {
670687
})
671688
}
672689

673-
/// `#[graphql_scalar]` macro.is interchangeable with
674-
/// `#[derive(`[`GraphQLScalar`]`)]` macro, and is used for deriving a
675-
/// [GraphQL scalar][0] implementation.
690+
/// `#[graphql_scalar]` macro.is interchangeable with the `#[derive(`[`GraphQLScalar`]`)]` macro,
691+
/// and is used for deriving a [GraphQL scalar][0] implementation.
676692
///
677693
/// ```rust
678694
/// # use juniper::graphql_scalar;
@@ -696,11 +712,10 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream {
696712
///
697713
/// # Foreign types
698714
///
699-
/// Additionally, `#[graphql_scalar]` can be used directly on foreign types via
700-
/// type alias, without using the [newtype pattern][1].
715+
/// Additionally, `#[graphql_scalar]` can be used directly on foreign types via type alias, without
716+
/// using the [newtype pattern][1].
701717
///
702-
/// > __NOTE:__ To satisfy [orphan rules] you should provide local
703-
/// > [`ScalarValue`] implementation.
718+
/// > __NOTE:__ To satisfy [orphan rules] you should provide local [`ScalarValue`] implementation.
704719
///
705720
/// ```rust
706721
/// # mod date {
@@ -740,10 +755,8 @@ pub fn derive_scalar(input: TokenStream) -> TokenStream {
740755
/// Value::scalar(v.to_string())
741756
/// }
742757
///
743-
/// pub(super) fn from_input(v: &CustomScalarValue) -> Result<Date, String> {
744-
/// v.try_as_str()
745-
/// .ok_or_else(|| format!("Expected `String`, found: {v}"))
746-
/// .and_then(|s| s.parse().map_err(|e| format!("Failed to parse `Date`: {e}")))
758+
/// pub(super) fn from_input(s: &str) -> Result<Date, Box<str>> {
759+
/// s.parse().map_err(|e| format!("Failed to parse `Date`: {e}").into())
747760
/// }
748761
/// }
749762
/// #
@@ -777,10 +790,10 @@ pub fn graphql_scalar(attr: TokenStream, body: TokenStream) -> TokenStream {
777790
/// ```rust
778791
/// # use std::{any::Any, fmt};
779792
/// #
780-
/// # use serde::{de, Deserialize, Deserializer, Serialize};
793+
/// use derive_more::with_trait::{Display, From, TryInto};
781794
/// # use juniper::ScalarValue;
782-
/// #
783-
/// #[derive(Clone, Debug, PartialEq, ScalarValue, Serialize)]
795+
/// # use serde::{de, Deserialize, Deserializer, Serialize};
796+
/// #[derive(Clone, Debug, Display, From, PartialEq, ScalarValue, Serialize, TryInto)]
784797
/// #[serde(untagged)]
785798
/// #[value(from_displayable_with = from_custom_str)]
786799
/// enum MyScalarValue {
@@ -801,7 +814,7 @@ pub fn graphql_scalar(attr: TokenStream, body: TokenStream) -> TokenStream {
801814
///
802815
/// // Custom implementation of `ScalarValue::from_displayable()` method for
803816
/// // possible efficient conversions into `MyScalarValue` from custom string types.
804-
/// fn from_custom_str<Str: fmt::Display + Any + ?Sized>(s: &Str) -> MyScalarValue {
817+
/// fn from_custom_str<Str: Display + Any + ?Sized>(s: &Str) -> MyScalarValue {
805818
/// use juniper::AnyExt as _; // allows downcasting directly on types without `dyn`
806819
///
807820
/// // Imagine this is some custom optimized string type.

0 commit comments

Comments
 (0)