Skip to content

Strip Value from to_output() function for GraphQL scalars #1330

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions juniper/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,8 @@ pub trait FromInputValue<S = DefaultScalarValue>: Sized {
}
}

/// Losslessly clones a Rust data type into an InputValue.
pub trait ToInputValue<S = DefaultScalarValue>: Sized {
/// Losslessly clones a Rust data type into an [`InputValue`].
pub trait ToInputValue<S = DefaultScalarValue> {
/// Performs the conversion.
fn to_input_value(&self) -> InputValue<S>;
}
Expand Down
6 changes: 3 additions & 3 deletions juniper/src/executor_tests/variables.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
GraphQLInputObject, GraphQLScalar, ScalarValue, Value,
GraphQLInputObject, GraphQLScalar,
executor::Variables,
graphql_object, graphql_value, graphql_vars,
parser::SourcePosition,
Expand All @@ -14,8 +14,8 @@ use crate::{
struct TestComplexScalar;

impl TestComplexScalar {
fn to_output<S: ScalarValue>(&self) -> Value<S> {
graphql_value!("SerializedValue")
fn to_output(&self) -> &'static str {
"SerializedValue"
}

fn from_input(s: &str) -> Result<Self, Box<str>> {
Expand Down
25 changes: 12 additions & 13 deletions juniper/src/integrations/bigdecimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@
//!
//! [`BigDecimal`]: bigdecimal::BigDecimal

use std::str::FromStr as _;

use crate::{Scalar, ScalarValue, Value, graphql_scalar};
use crate::graphql_scalar;

// TODO: Try remove on upgrade of `bigdecimal` crate.
mod for_minimal_versions_check_only {
Expand All @@ -29,18 +27,20 @@ mod for_minimal_versions_check_only {
/// See also [`bigdecimal`] crate for details.
///
/// [`bigdecimal`]: https://docs.rs/bigdecimal
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
with = bigdecimal_scalar,
parse_token(i32, f64, String),
specified_by_url = "https://docs.rs/bigdecimal",
)]
type BigDecimal = bigdecimal::BigDecimal;

mod bigdecimal_scalar {
use super::*;
use super::BigDecimal;
use crate::{Scalar, ScalarValue};

pub(super) fn to_output<S: ScalarValue>(v: &BigDecimal) -> Value<S> {
Value::scalar(v.to_string())
pub(super) fn to_output(v: &BigDecimal) -> String {
v.to_string() // TODO: Optimize via `Display`?
}

pub(super) fn from_input(v: &Scalar<impl ScalarValue>) -> Result<BigDecimal, Box<str>> {
Expand All @@ -50,13 +50,14 @@ mod bigdecimal_scalar {
// See akubera/bigdecimal-rs#103 for details:
// https://github.com/akubera/bigdecimal-rs/issues/103
let mut buf = ryu::Buffer::new();
BigDecimal::from_str(buf.format(f))
buf.format(f)
.parse::<BigDecimal>()
.map_err(|e| format!("Failed to parse `BigDecimal` from `Float`: {e}").into())
} else {
v.try_to::<&str>()
.map_err(|e| e.to_string().into())
.and_then(|s| {
BigDecimal::from_str(s).map_err(|e| {
s.parse::<BigDecimal>().map_err(|e| {
format!("Failed to parse `BigDecimal` from `String`: {e}").into()
})
})
Expand All @@ -66,8 +67,6 @@ mod bigdecimal_scalar {

#[cfg(test)]
mod test {
use std::str::FromStr as _;

use crate::{FromInputValue as _, InputValue, ToInputValue as _, graphql_input_value};

use super::BigDecimal;
Expand All @@ -91,7 +90,7 @@ mod test {
] {
let input: InputValue = input;
let parsed = BigDecimal::from_input_value(&input);
let expected = BigDecimal::from_str(expected).unwrap();
let expected = expected.parse::<BigDecimal>().unwrap();

assert!(
parsed.is_ok(),
Expand Down Expand Up @@ -130,7 +129,7 @@ mod test {
"123",
"43.44",
] {
let actual: InputValue = BigDecimal::from_str(raw).unwrap().to_input_value();
let actual: InputValue = raw.parse::<BigDecimal>().unwrap().to_input_value();

assert_eq!(actual, graphql_input_value!((raw)), "on value: {raw}");
}
Expand Down
24 changes: 12 additions & 12 deletions juniper/src/integrations/bson.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
//! [s1]: https://graphql-scalars.dev/docs/scalars/object-id
//! [s4]: https://graphql-scalars.dev/docs/scalars/date-time

use crate::{ScalarValue, Value, graphql_scalar};
use crate::graphql_scalar;

// TODO: Try remove on upgrade of `bson` crate.
mod for_minimal_versions_check_only {
Expand All @@ -29,7 +29,8 @@ mod for_minimal_versions_check_only {
/// [0]: https://www.mongodb.com/docs/manual/reference/bson-types#objectid
/// [1]: https://graphql-scalars.dev/docs/scalars/object-id
/// [2]: https://docs.rs/bson/*/bson/oid/struct.ObjectId.html
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
name = "ObjectID",
with = object_id,
parse_token(String),
Expand All @@ -38,10 +39,10 @@ mod for_minimal_versions_check_only {
type ObjectId = bson::oid::ObjectId;

mod object_id {
use super::*;
use super::ObjectId;

pub(super) fn to_output<S: ScalarValue>(v: &ObjectId) -> Value<S> {
Value::scalar(v.to_hex())
pub(super) fn to_output(v: &ObjectId) -> String {
v.to_hex()
}

pub(super) fn from_input(s: &str) -> Result<ObjectId, Box<str>> {
Expand All @@ -62,21 +63,20 @@ mod object_id {
/// [1]: https://graphql-scalars.dev/docs/scalars/date-time
/// [2]: https://docs.rs/bson/*/bson/struct.DateTime.html
/// [3]: https://www.mongodb.com/docs/manual/reference/bson-types#date
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
with = date_time,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/date-time",
)]
type DateTime = bson::DateTime;

mod date_time {
use super::*;
use super::DateTime;

pub(super) fn to_output<S: ScalarValue>(v: &DateTime) -> Value<S> {
Value::scalar(
(*v).try_to_rfc3339_string()
.unwrap_or_else(|e| panic!("failed to format `DateTime` as RFC 3339: {e}")),
)
pub(super) fn to_output(v: &DateTime) -> String {
(*v).try_to_rfc3339_string()
.unwrap_or_else(|e| panic!("failed to format `DateTime` as RFC 3339: {e}"))
}

pub(super) fn from_input(s: &str) -> Result<DateTime, Box<str>> {
Expand Down
70 changes: 31 additions & 39 deletions juniper/src/integrations/chrono.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::fmt;

use chrono::{FixedOffset, TimeZone};

use crate::{ScalarValue, Value, graphql_scalar};
use crate::graphql_scalar;

/// Date in the proleptic Gregorian calendar (without time zone).
///
Expand All @@ -36,26 +36,24 @@ use crate::{ScalarValue, Value, graphql_scalar};
///
/// [1]: https://graphql-scalars.dev/docs/scalars/local-date
/// [2]: https://docs.rs/chrono/latest/chrono/naive/struct.NaiveDate.html
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
with = local_date,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/local-date",
)]
pub type LocalDate = chrono::NaiveDate;

mod local_date {
use super::*;
use super::LocalDate;

/// Format of a [`LocalDate` scalar][1].
///
/// [1]: https://graphql-scalars.dev/docs/scalars/local-date
const FORMAT: &str = "%Y-%m-%d";

pub(super) fn to_output<S>(v: &LocalDate) -> Value<S>
where
S: ScalarValue,
{
Value::scalar(v.format(FORMAT).to_string())
pub(super) fn to_output(v: &LocalDate) -> String {
v.format(FORMAT).to_string() // TODO: Optimize via `Display`?
}

pub(super) fn from_input(s: &str) -> Result<LocalDate, Box<str>> {
Expand All @@ -75,7 +73,8 @@ mod local_date {
///
/// [1]: https://graphql-scalars.dev/docs/scalars/local-time
/// [2]: https://docs.rs/chrono/latest/chrono/naive/struct.NaiveTime.html
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
with = local_time,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/local-time",
Expand All @@ -85,7 +84,7 @@ pub type LocalTime = chrono::NaiveTime;
mod local_time {
use chrono::Timelike as _;

use super::*;
use super::LocalTime;

/// Full format of a [`LocalTime` scalar][1].
///
Expand All @@ -102,18 +101,13 @@ mod local_time {
/// [1]: https://graphql-scalars.dev/docs/scalars/local-time
const FORMAT_NO_SECS: &str = "%H:%M";

pub(super) fn to_output<S>(v: &LocalTime) -> Value<S>
where
S: ScalarValue,
{
Value::scalar(
if v.nanosecond() == 0 {
v.format(FORMAT_NO_MILLIS)
} else {
v.format(FORMAT)
}
.to_string(),
)
pub(super) fn to_output(v: &LocalTime) -> String {
if v.nanosecond() == 0 {
v.format(FORMAT_NO_MILLIS)
} else {
v.format(FORMAT)
}
.to_string() // TODO: Optimize via `Display`?
}

pub(super) fn from_input(s: &str) -> Result<LocalTime, Box<str>> {
Expand All @@ -134,26 +128,24 @@ mod local_time {
///
/// [1]: https://graphql-scalars.dev/docs/scalars/local-date-time
/// [2]: https://docs.rs/chrono/latest/chrono/naive/struct.NaiveDateTime.html
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
with = local_date_time,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/local-date-time",
)]
pub type LocalDateTime = chrono::NaiveDateTime;

mod local_date_time {
use super::*;
use super::LocalDateTime;

/// Format of a [`LocalDateTime` scalar][1].
///
/// [1]: https://graphql-scalars.dev/docs/scalars/local-date-time
const FORMAT: &str = "%Y-%m-%dT%H:%M:%S";

pub(super) fn to_output<S>(v: &LocalDateTime) -> Value<S>
where
S: ScalarValue,
{
Value::scalar(v.format(FORMAT).to_string())
pub(super) fn to_output(v: &LocalDateTime) -> String {
v.format(FORMAT).to_string() // TODO: Optimize via `Display`?
}

pub(super) fn from_input(s: &str) -> Result<LocalDateTime, Box<str>> {
Expand All @@ -174,7 +166,8 @@ mod local_date_time {
/// [0]: https://datatracker.ietf.org/doc/html/rfc3339#section-5
/// [1]: https://graphql-scalars.dev/docs/scalars/date-time
/// [2]: https://docs.rs/chrono/latest/chrono/struct.DateTime.html
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
with = date_time,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/date-time",
Expand All @@ -186,20 +179,19 @@ mod local_date_time {
pub type DateTime<Tz> = chrono::DateTime<Tz>;

mod date_time {
use chrono::{SecondsFormat, Utc};
use std::fmt;

use chrono::{FixedOffset, SecondsFormat, TimeZone, Utc};

use super::*;
use super::{DateTime, FromFixedOffset};

pub(super) fn to_output<S, Tz>(v: &DateTime<Tz>) -> Value<S>
pub(super) fn to_output<Tz>(v: &DateTime<Tz>) -> String
where
S: ScalarValue,
Tz: chrono::TimeZone,
Tz: TimeZone,
Tz::Offset: fmt::Display,
{
Value::scalar(
v.with_timezone(&Utc)
.to_rfc3339_opts(SecondsFormat::AutoSi, true),
)
v.with_timezone(&Utc)
.to_rfc3339_opts(SecondsFormat::AutoSi, true) // TODO: Optimize via `Display`?
}

pub(super) fn from_input<Tz>(s: &str) -> Result<DateTime<Tz>, Box<str>>
Expand Down
11 changes: 6 additions & 5 deletions juniper/src/integrations/chrono_tz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
//! [1]: http://www.iana.org/time-zones
//! [s1]: https://graphql-scalars.dev/docs/scalars/time-zone

use crate::{ScalarValue, Value, graphql_scalar};
use crate::graphql_scalar;

// TODO: Try remove on upgrade of `chrono-tz` crate.
mod for_minimal_versions_check_only {
Expand All @@ -31,18 +31,19 @@ mod for_minimal_versions_check_only {
/// [1]: https://graphql-scalars.dev/docs/scalars/time-zone
/// [2]: https://docs.rs/chrono-tz/*/chrono_tz/enum.Tz.html
/// [3]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
#[graphql_scalar(
#[graphql_scalar]
#[graphql(
with = tz,
parse_token(String),
specified_by_url = "https://graphql-scalars.dev/docs/scalars/time-zone",
)]
pub type TimeZone = chrono_tz::Tz;

mod tz {
use super::*;
use super::TimeZone;

pub(super) fn to_output<S: ScalarValue>(v: &TimeZone) -> Value<S> {
Value::scalar(v.name().to_owned())
pub(super) fn to_output(v: &TimeZone) -> &'static str {
v.name()
}

pub(super) fn from_input(s: &str) -> Result<TimeZone, Box<str>> {
Expand Down
Loading
Loading