Skip to content
Merged
4 changes: 2 additions & 2 deletions book/src/types/scalars.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ impl UserId {
/// Checks whether the [`InputValue`] is a [`String`] beginning with `id: ` and strips it.
fn from_input(
input: &str,
// ^^^^ any concrete type having `TryScalarValueTo` implementation could be used
// ^^^^ any concrete type having `FromScalarValue` implementation could be used
) -> Result<Self, Box<str>> {
// ^^^^^^^^ must implement `IntoFieldError`
input
Expand Down Expand Up @@ -145,7 +145,7 @@ impl UserId {
// ^^^^^^ for generic argument using `Scalar` transparent wrapper is required,
// otherwise Rust won't be able to infer the required type
) -> Self {
// ^^^^ if the result is infallible, it's OK to not use `Result`
// ^^^^ if the result is infallible, it's OK to omit `Result`
Self(
input
.try_to_int().map(|i| i.to_string())
Expand Down
46 changes: 25 additions & 21 deletions juniper/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,17 +71,18 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
- Removed `as_float_value()`, `as_string_value()` and `as_scalar_value()` methods (use `as_scalar()` method and then `ScalarValue` methods instead).
- `InputValue` enum: ([#1327])
- Removed `as_float_value()`, `as_int_value()`, `as_string_value()` and `as_scalar_value()` methods (use `as_scalar()` method and then `ScalarValue` methods instead).
- `ScalarValue` trait: ([#1327])
- Switched from `From` conversions to `TryScalarValueTo` conversions.
- Made to require `TryScalarValueTo` conversions for `bool`, `f64`, `i32`, `String` and `&str` types (could be derived with `#[value(<conversion>)]` attributes of `#[derive(ScalarValue)]` macro).
- Made to require `TryInto<String>` conversion (could be derived with `derive_more::TryInto`).
- Made `is_type()` method required and to accept `Any` type.
- Renamed `as_bool()` method as `try_to_bool()` and made it defined by default as `TryScalarValueTo<bool>` alias.
- Renamed `as_float()` method as `try_to_float()` and made it defined by default as `TryScalarValueTo<f64>` alias.
- Renamed `as_int()` method as `try_to_int()` and made it defined by default as `TryScalarValueTo<i32>` alias.
- Renamed `as_string()` method as `try_to_string()` and made it defined by default as `TryScalarValueTo<String>` alias.
- Renamed `as_str()` method as `try_as_str()` and made it defined by default as `TryScalarValueTo<&str>` alias.
- Renamed `into_string()` method as `try_into_string()` and made it defined by default as `TryInto<String>` alias.
- `ScalarValue` trait:
- Switched from `From` conversions to `TryToPrimitive` and `FromScalarValue` conversions. ([#1327], [#1329])
- Made to require `TryToPrimitive` conversions for `bool`, `f64`, `i32`, `String` and `&str` types (could be derived with `#[value(<conversion>)]` attributes of `#[derive(ScalarValue)]` macro). ([#1327], [#1329])
- Made to require `TryInto<String>` conversion (could be derived with `derive_more::TryInto`). ([#1327])
- Made `is_type()` method required and to accept `Any` type. ([#1327])
- Renamed `as_bool()` method as `try_to_bool()` and made it defined by default as `TryToPrimitive<bool>` alias. ([#1327])
- Renamed `as_float()` method as `try_to_float()` and made it defined by default as `TryToPrimitive<f64>` alias. ([#1327])
- Renamed `as_int()` method as `try_to_int()` and made it defined by default as `TryToPrimitive<i32>` alias. ([#1327])
- Renamed `as_string()` method as `try_to_string()` and made it defined by default as `TryToPrimitive<String>` alias. ([#1327])
- Renamed `as_str()` method as `try_as_str()` and made it defined by default as `TryToPrimitive<&str>` alias. ([#1327])
- Renamed `into_string()` method as `try_into_string()` and made it defined by default as `TryInto<String>` alias. ([#1327])
- Required new `downcast_type::<T>()` method (could be derived with `#[derive(ScalarValue)]` macro). ([#1329])
- `#[derive(ScalarValue)]` macro: ([#1327])
- Renamed `#[value(as_bool)]` attribute as `#[value(to_bool)]`.
- Renamed `#[value(as_float)]` attribute as `#[value(to_float)]`.
Expand All @@ -90,9 +91,9 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
- Removed `#[value(into_string)]` attribute.
- Removed `#[value(allow_missing_attributes)]` attribute (now attributes can always be omitted).
- `From` and `Display` implementations are not derived anymore (recommended way is to use [`derive_more` crate] for this).
- `#[derive(GraphQLScalar)]` and `#[graphql_scalar]` macros: ([#1327])
- Made provided `from_input()` function to accept `ScalarValue` (or anything `TryScalarValueTo`-convertible) directly instead of `InputValue`.
- Removed `LocalBoxFuture` usage from `http::tests::WsIntegration` trait. ([todo])
- `#[derive(GraphQLScalar)]` and `#[graphql_scalar]` macros:
- Made provided `from_input()` function to accept `ScalarValue` (or anything `FromScalarValue`-convertible) directly instead of `InputValue`. ([#1327])
- Removed `LocalBoxFuture` usage from `http::tests::WsIntegration` trait. ([4b14c015])

### Added

Expand All @@ -109,14 +110,16 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
- `String` scalar implementation for `arcstr::ArcStr`. ([#1247])
- `String` scalar implementation for `compact_str::CompactString`. ([20609366])
- `IntoValue` and `IntoInputValue` conversion traits allowing to work around orphan rules with custom `ScalarValue`. ([#1324])
- `FromScalarValue` conversion trait. ([#1329])
- `TryToPrimitive` conversion trait aiding `ScalarValue` trait. ([#1327], [#1329])
- `ScalarValue` trait:
- `from_displayable()` method allowing to specialize `ScalarValue` conversion from custom string types. ([#1324], [#819])
- `try_to::<T>()` method defined by default as `TryScalarValueTo<T>` alias. ([#1327])
- `TryScalarValueTo` conversion trait aiding `ScalarValue` trait. ([#1327])
- `#[derive(GraphQLScalar)]` and `#[graphql_scalar]` macros: ([#1327])
- Support for specifying concrete types as input argument in provided `from_input()` function.
- Support for non-`Result` return type in provided `from_input()` function.
- `Scalar` transparent wrapper for aiding type inference in `from_input()` function when input argument is generic `ScalarValue`.
- `try_to::<T>()` method defined by default as `FromScalarValue<T>` alias. ([#1327], [#1329])
- `#[derive(GraphQLScalar)]` and `#[graphql_scalar]` macros:
- Support for specifying concrete types as input argument in provided `from_input()` function. ([#1327])
- Support for non-`Result` return type in provided `from_input()` function. ([#1327])
- `Scalar` transparent wrapper for aiding type inference in `from_input()` function when input argument is generic `ScalarValue`. ([#1327])
- Generating of `FromScalarValue` implementation. ([#1329])

### Changed

Expand Down Expand Up @@ -144,9 +147,10 @@ All user visible changes to `juniper` crate will be documented in this file. Thi
[#1324]: /../../pull/1324
[#1326]: /../../pull/1326
[#1327]: /../../pull/1327
[#1329]: /../../pull/1329
[1b1fc618]: /../../commit/1b1fc61879ffdd640d741e187dc20678bf7ab295
[20609366]: /../../commit/2060936635609b0186d46d8fbd06eb30fce660e3
[todo]: /../../commit/todo
[4b14c015]: /../../commit/4b14c015018d31cb6df848efdee24d96416b76d9



Expand Down
22 changes: 8 additions & 14 deletions juniper/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,24 +200,18 @@ pub type Document<'a, S> = [Definition<'a, S>];
#[doc(hidden)]
pub type OwnedDocument<'a, S> = Vec<Definition<'a, S>>;

/// Parsing of an unstructured input value into a Rust data type.
/// Parsing of an unstructured [`InputValue`] into a Rust data type.
///
/// The conversion _can_ fail, and must in that case return [`Err`]. Thus not
/// restricted in the definition of this trait, the returned [`Err`] should be
/// convertible with [`IntoFieldError`] to fit well into the library machinery.
/// The conversion _can_ fail, and must in that case return an [`Err`]. Thus, not restricted in the
/// definition of this trait, the returned [`Err`] should be convertible with the [`IntoFieldError`]
/// trait to fit well into the library machinery.
///
/// Implemented automatically by the convenience proc macro [`graphql_scalar!`]
/// or by deriving `GraphQLEnum`.
///
/// Must be implemented manually when manually exposing new enums or scalars.
///
/// [`graphql_scalar!`]: macro@crate::graphql_scalar
/// [`IntoFieldError`]: crate::IntoFieldError
pub trait FromInputValue<S = DefaultScalarValue>: Sized {
/// Type of this conversion error.
///
/// Thus not restricted, it should be convertible with [`IntoFieldError`] to
/// fit well into the library machinery.
/// Thus, not restricted, it should be convertible with the [`IntoFieldError`] trait to fit well
/// into the library machinery.
///
/// [`IntoFieldError`]: crate::IntoFieldError
type Error;
Expand Down Expand Up @@ -615,13 +609,13 @@ impl<'a, S> VariableDefinitions<'a, S> {
}

#[cfg(test)]
mod tests {
mod spec_input_value_fmt {
use crate::graphql_input_value;

use super::InputValue;

#[test]
fn test_input_value_fmt() {
fn correct() {
let value: InputValue = graphql_input_value!(null);
assert_eq!(value.to_string(), "null");

Expand Down
4 changes: 2 additions & 2 deletions juniper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ pub use crate::{
},
validation::RuleError,
value::{
AnyExt, DefaultScalarValue, IntoValue, Object, ParseScalarResult, ParseScalarValue, Scalar,
ScalarValue, TryScalarValueTo, Value, WrongInputScalarTypeError,
AnyExt, DefaultScalarValue, FromScalarValue, IntoValue, Object, ParseScalarResult,
ParseScalarValue, Scalar, ScalarValue, TryToPrimitive, Value, WrongInputScalarTypeError,
},
};

Expand Down
26 changes: 25 additions & 1 deletion juniper/src/types/pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use crate::{
async_await::GraphQLValueAsync,
base::{Arguments, GraphQLType, GraphQLValue},
},
value::ScalarValue,
value::{FromScalarValue, ScalarValue},
};

impl<S, T> GraphQLType<S> for Box<T>
Expand Down Expand Up @@ -87,6 +87,18 @@ where
}
}

impl<'s, T, S> FromScalarValue<'s, S> for Box<T>
where
S: ScalarValue,
T: FromScalarValue<'s, S> + 's,
{
type Error = T::Error;

fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
T::from_scalar_value(v).map(Self::new)
}
}

impl<T, S> FromInputValue<S> for Box<T>
where
S: ScalarValue,
Expand Down Expand Up @@ -275,6 +287,18 @@ where
}
}

impl<'s, T, S> FromScalarValue<'s, S> for Arc<T>
where
S: ScalarValue,
T: FromScalarValue<'s, S> + 's,
{
type Error = T::Error;

fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
T::from_scalar_value(v).map(Self::new)
}
}

impl<T, S> FromInputValue<S> for Arc<T>
where
S: ScalarValue,
Expand Down
96 changes: 83 additions & 13 deletions juniper/src/types/scalars.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use std::{char, convert::identity, marker::PhantomData, rc::Rc, thread::JoinHandle};
use std::{char, marker::PhantomData, rc::Rc, thread::JoinHandle};

use derive_more::with_trait::{Deref, Display, From, Into};
use serde::{Deserialize, Serialize};

use crate::{
GraphQLScalar, Scalar,
GraphQLScalar, IntoFieldError, Scalar,
ast::{InputValue, Selection, ToInputValue},
executor::{ExecutionResult, Executor, Registry},
graphql_scalar,
Expand All @@ -16,7 +16,10 @@ use crate::{
base::{GraphQLType, GraphQLValue},
subscriptions::GraphQLSubscriptionValue,
},
value::{ParseScalarResult, ScalarValue, Value, WrongInputScalarTypeError},
value::{
FromScalarValue, ParseScalarResult, ScalarValue, TryToPrimitive, Value,
WrongInputScalarTypeError,
},
};

/// An ID as defined by the GraphQL specification
Expand Down Expand Up @@ -56,12 +59,23 @@ impl ID {
}

#[graphql_scalar]
#[graphql(with = impl_string_scalar, from_input_with = identity::<String>)]
#[graphql(with = impl_string_scalar, from_input_with = __builtin)]
type String = std::string::String;

mod impl_string_scalar {
use super::*;

impl<'s, S> FromScalarValue<'s, S> for String
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;

fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}

pub(super) fn to_output<S: ScalarValue>(v: &str) -> Value<S> {
Value::scalar(v.to_owned())
}
Expand Down Expand Up @@ -176,14 +190,20 @@ type ArcStr = arcstr::ArcStr;

mod impl_arcstr_scalar {
use super::ArcStr;
use crate::{IntoValue as _, ScalarValue, Value};
use crate::{FromScalarValue, IntoValue as _, Scalar, ScalarValue, Value};

pub(super) fn to_output<S: ScalarValue>(v: &ArcStr) -> Value<S> {
v.into_value()
}

pub(super) fn from_input(s: &str) -> ArcStr {
s.into()
pub(super) fn from_input<S: ScalarValue>(
v: &Scalar<S>,
) -> Result<ArcStr, <&str as FromScalarValue<'_, S>>::Error> {
if let Some(s) = v.downcast_type::<ArcStr>() {
Ok(s.clone())
} else {
v.try_to::<&str>().map(ArcStr::from)
}
}
}

Expand All @@ -193,14 +213,20 @@ type CompactString = compact_str::CompactString;

mod impl_compactstring_scalar {
use super::CompactString;
use crate::{IntoValue as _, ScalarValue, Value};
use crate::{FromScalarValue, IntoValue as _, Scalar, ScalarValue, Value};

pub(super) fn to_output<S: ScalarValue>(v: &CompactString) -> Value<S> {
v.into_value()
}

pub(super) fn from_input(s: &str) -> CompactString {
s.into()
pub(super) fn from_input<S: ScalarValue>(
v: &Scalar<S>,
) -> Result<CompactString, <&str as FromScalarValue<'_, S>>::Error> {
if let Some(s) = v.downcast_type::<CompactString>() {
Ok(s.clone())
} else {
v.try_to::<&str>().map(CompactString::from)
}
}
}

Expand Down Expand Up @@ -274,13 +300,35 @@ where
}
}

impl<'s, S> FromScalarValue<'s, S> for &'s str
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;

fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}

#[graphql_scalar]
#[graphql(with = impl_boolean_scalar, from_input_with = identity::<Boolean>)]
#[graphql(with = impl_boolean_scalar, from_input_with = __builtin)]
type Boolean = bool;

mod impl_boolean_scalar {
use super::*;

impl<'s, S> FromScalarValue<'s, S> for Boolean
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;

fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}

pub(super) fn to_output<S: ScalarValue>(v: &Boolean) -> Value<S> {
Value::scalar(*v)
}
Expand All @@ -292,12 +340,23 @@ mod impl_boolean_scalar {
}

#[graphql_scalar]
#[graphql(with = impl_int_scalar, from_input_with = identity::<Int>)]
#[graphql(with = impl_int_scalar, from_input_with = __builtin)]
type Int = i32;

mod impl_int_scalar {
use super::*;

impl<'s, S> FromScalarValue<'s, S> for Int
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;

fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}

pub(super) fn to_output<S: ScalarValue>(v: &Int) -> Value<S> {
Value::scalar(*v)
}
Expand All @@ -314,12 +373,23 @@ mod impl_int_scalar {
}

#[graphql_scalar]
#[graphql(with = impl_float_scalar, from_input_with = identity::<Float>)]
#[graphql(with = impl_float_scalar, from_input_with = __builtin)]
type Float = f64;

mod impl_float_scalar {
use super::*;

impl<'s, S> FromScalarValue<'s, S> for Float
where
S: TryToPrimitive<'s, Self, Error: IntoFieldError<S>> + 's,
{
type Error = S::Error;

fn from_scalar_value(v: &'s S) -> Result<Self, Self::Error> {
v.try_to_primitive()
}
}

pub(super) fn to_output<S: ScalarValue>(v: &Float) -> Value<S> {
Value::scalar(*v)
}
Expand Down
4 changes: 2 additions & 2 deletions juniper/src/value/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ pub(crate) use self::scalar::ScalarValueFmt;
pub use self::{
object::Object,
scalar::{
AnyExt, DefaultScalarValue, ParseScalarResult, ParseScalarValue, Scalar, ScalarValue,
TryScalarValueTo, WrongInputScalarTypeError,
AnyExt, DefaultScalarValue, FromScalarValue, ParseScalarResult, ParseScalarValue, Scalar,
ScalarValue, TryToPrimitive, WrongInputScalarTypeError,
},
};
use crate::{
Expand Down
Loading
Loading