Replace ScalarValue::Visitor with DeserializeOwned requirement (#985)

- remove `Serialize` impl from `#[derive(GraphQLScalarValue)]` macro expansion
This commit is contained in:
Kai Ren 2021-10-11 21:53:04 +03:00 committed by GitHub
parent 168114fcf0
commit f66296d618
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 576 additions and 764 deletions

View file

@ -12,6 +12,7 @@ juniper_subscriptions = { path = "../../juniper_subscriptions" }
[dev-dependencies]
async-trait = "0.1.39"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
fnv = "1.0"
tokio = { version = "1", features = ["rt", "macros", "time"] }

View file

@ -1,15 +1,16 @@
use std::{fmt, pin::Pin};
use std::{convert::TryInto as _, fmt, pin::Pin};
use futures::{stream, Stream};
use juniper::{
execute, graphql_object, graphql_scalar, graphql_subscription,
parser::{ParseError, ScalarToken, Spanning, Token},
serde::de,
serde::{de, Deserialize, Deserializer, Serialize},
EmptyMutation, FieldResult, GraphQLScalarValue, InputValue, Object, ParseScalarResult,
RootNode, ScalarValue, Value, Variables,
};
#[derive(GraphQLScalarValue, Clone, Debug, PartialEq)]
#[derive(GraphQLScalarValue, Clone, Debug, PartialEq, Serialize)]
#[serde(untagged)]
pub(crate) enum MyScalarValue {
Int(i32),
Long(i64),
@ -19,18 +20,16 @@ pub(crate) enum MyScalarValue {
}
impl ScalarValue for MyScalarValue {
type Visitor = MyScalarValueVisitor;
fn as_int(&self) -> Option<i32> {
match *self {
Self::Int(ref i) => Some(*i),
match self {
Self::Int(i) => Some(*i),
_ => None,
}
}
fn as_string(&self) -> Option<String> {
match *self {
Self::String(ref s) => Some(s.clone()),
match self {
Self::String(s) => Some(s.clone()),
_ => None,
}
}
@ -43,100 +42,92 @@ impl ScalarValue for MyScalarValue {
}
fn as_str(&self) -> Option<&str> {
match *self {
Self::String(ref s) => Some(s.as_str()),
match self {
Self::String(s) => Some(s.as_str()),
_ => None,
}
}
fn as_float(&self) -> Option<f64> {
match *self {
Self::Int(ref i) => Some(f64::from(*i)),
Self::Float(ref f) => Some(*f),
match self {
Self::Int(i) => Some(f64::from(*i)),
Self::Float(f) => Some(*f),
_ => None,
}
}
fn as_boolean(&self) -> Option<bool> {
match *self {
Self::Boolean(ref b) => Some(*b),
match self {
Self::Boolean(b) => Some(*b),
_ => None,
}
}
}
#[derive(Debug, Default)]
pub(crate) struct MyScalarValueVisitor;
impl<'de> Deserialize<'de> for MyScalarValue {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
type Value = MyScalarValue;
impl<'de> de::Visitor<'de> for Visitor {
type Value = MyScalarValue;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid input value")
}
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a valid input value")
}
fn visit_bool<E>(self, value: bool) -> Result<MyScalarValue, E> {
Ok(MyScalarValue::Boolean(value))
}
fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
Ok(MyScalarValue::Boolean(b))
}
fn visit_i32<E>(self, value: i32) -> Result<MyScalarValue, E>
where
E: de::Error,
{
Ok(MyScalarValue::Int(value))
}
fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
Ok(MyScalarValue::Int(n))
}
fn visit_i64<E>(self, value: i64) -> Result<MyScalarValue, E>
where
E: de::Error,
{
if value <= i64::from(i32::max_value()) {
self.visit_i32(value as i32)
} else {
Ok(MyScalarValue::Long(value))
fn visit_i64<E: de::Error>(self, b: i64) -> Result<Self::Value, E> {
if b <= i64::from(i32::MAX) {
self.visit_i32(b.try_into().unwrap())
} else {
Ok(MyScalarValue::Long(b))
}
}
fn visit_u32<E: de::Error>(self, n: u32) -> Result<Self::Value, E> {
if n <= i32::MAX as u32 {
self.visit_i32(n.try_into().unwrap())
} else {
self.visit_u64(n.into())
}
}
fn visit_u64<E: de::Error>(self, n: u64) -> Result<Self::Value, E> {
if n <= i64::MAX as u64 {
self.visit_i64(n.try_into().unwrap())
} else {
// Browser's `JSON.stringify()` serializes all numbers
// having no fractional part as integers (no decimal point),
// so we must parse large integers as floating point,
// otherwise we would error on transferring large floating
// point numbers.
// TODO: Use `FloatToInt` conversion once stabilized:
// https://github.com/rust-lang/rust/issues/67057
Ok(MyScalarValue::Float(n as f64))
}
}
fn visit_f64<E: de::Error>(self, f: f64) -> Result<Self::Value, E> {
Ok(MyScalarValue::Float(f))
}
fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
self.visit_string(s.into())
}
fn visit_string<E: de::Error>(self, s: String) -> Result<Self::Value, E> {
Ok(MyScalarValue::String(s))
}
}
}
fn visit_u32<E>(self, value: u32) -> Result<MyScalarValue, E>
where
E: de::Error,
{
if value <= i32::max_value() as u32 {
self.visit_i32(value as i32)
} else {
self.visit_u64(value as u64)
}
}
fn visit_u64<E>(self, value: u64) -> Result<MyScalarValue, E>
where
E: de::Error,
{
if value <= i64::max_value() as u64 {
self.visit_i64(value as i64)
} else {
// Browser's JSON.stringify serialize all numbers having no
// fractional part as integers (no decimal point), so we
// must parse large integers as floating point otherwise
// we would error on transferring large floating point
// numbers.
Ok(MyScalarValue::Float(value as f64))
}
}
fn visit_f64<E>(self, value: f64) -> Result<MyScalarValue, E> {
Ok(MyScalarValue::Float(value))
}
fn visit_str<E>(self, value: &str) -> Result<MyScalarValue, E>
where
E: de::Error,
{
self.visit_string(value.into())
}
fn visit_string<E>(self, value: String) -> Result<MyScalarValue, E> {
Ok(MyScalarValue::String(value))
de.deserialize_any(Visitor)
}
}
@ -169,7 +160,7 @@ struct TestType;
#[graphql_object(scalar = MyScalarValue)]
impl TestType {
fn long_field() -> i64 {
i64::from(i32::max_value()) + 1
i64::from(i32::MAX) + 1
}
fn long_with_arg(long_arg: i64) -> i64 {

View file

@ -2,15 +2,17 @@
## Breaking Changes
- `#[graphql_object]` and `#[graphql_subscription]` macros expansion now preserves defined `impl` blocks "as is" and reuses defined methods in opaque way. ([#971](https://github.com/graphql-rust/juniper/pull/971)
- `rename = "<policy>"` attribute's argument renamed to `rename_all = "<policy>"`. ([#971](https://github.com/graphql-rust/juniper/pull/971)
- Upgrade `bson` feature to [2.0 version of its crate](https://github.com/mongodb/bson-rust/releases/tag/v2.0.0). ([#979](https://github.com/graphql-rust/juniper/pull/979)
- Replaced `Visitor` associated type with `DeserializeOwned` requirement in `ScalarValue` trait. ([#985](https://github.com/graphql-rust/juniper/pull/985))
- Removed `Serialize` implementation from `#[derive(GraphQLScalarValue)]`macro, now should be provided explicitly. ([#985](https://github.com/graphql-rust/juniper/pull/985))
- `#[graphql_object]` and `#[graphql_subscription]` macros expansion now preserves defined `impl` blocks "as is" and reuses defined methods in opaque way. ([#971](https://github.com/graphql-rust/juniper/pull/971))
- `rename = "<policy>"` attribute's argument renamed to `rename_all = "<policy>"`. ([#971](https://github.com/graphql-rust/juniper/pull/971))
- Upgrade `bson` feature to [2.0 version of its crate](https://github.com/mongodb/bson-rust/releases/tag/v2.0.0). ([#979](https://github.com/graphql-rust/juniper/pull/979))
## Features
- Support using Rust array as GraphQL list. ([#966](https://github.com/graphql-rust/juniper/pull/966), [#918](https://github.com/graphql-rust/juniper/issues/918))
- Expose `GraphQLRequest` fields. ([#750](https://github.com/graphql-rust/juniper/issues/750))
- `#[graphql_interface]` macro now supports `rename_all = "<policy>"` argument influencing its fields and their arguments. ([#971](https://github.com/graphql-rust/juniper/pull/971)
- `#[graphql_interface]` macro now supports `rename_all = "<policy>"` argument influencing its fields and their arguments. ([#971](https://github.com/graphql-rust/juniper/pull/971))
## Fixes

View file

@ -214,80 +214,53 @@ impl<'a> fmt::Display for Type<'a> {
}
}
impl<S> InputValue<S>
where
S: ScalarValue,
{
/// Construct a null value.
impl<S> InputValue<S> {
/// Construct a `null` value.
pub fn null() -> Self {
InputValue::Null
}
/// Construct an integer value.
#[deprecated(since = "0.11.0", note = "Use `InputValue::scalar` instead")]
pub fn int(i: i32) -> Self {
Self::scalar(i)
}
/// Construct a floating point value.
#[deprecated(since = "0.11.0", note = "Use `InputValue::scalar` instead")]
pub fn float(f: f64) -> Self {
Self::scalar(f)
}
/// Construct a boolean value.
#[deprecated(since = "0.11.0", note = "Use `InputValue::scalar` instead")]
pub fn boolean(b: bool) -> Self {
Self::scalar(b)
}
/// Construct a string value.
#[deprecated(since = "0.11.0", note = "Use `InputValue::scalar` instead")]
pub fn string<T: AsRef<str>>(s: T) -> Self {
InputValue::scalar(s.as_ref().to_owned())
Self::Null
}
/// Construct a scalar value
pub fn scalar<T>(v: T) -> Self
where
T: Into<S>,
S: From<T>,
{
InputValue::Scalar(v.into())
Self::Scalar(v.into())
}
/// Construct an enum value.
pub fn enum_value<T: AsRef<str>>(s: T) -> Self {
InputValue::Enum(s.as_ref().to_owned())
Self::Enum(s.as_ref().to_owned())
}
/// Construct a variable value.
pub fn variable<T: AsRef<str>>(v: T) -> Self {
InputValue::Variable(v.as_ref().to_owned())
Self::Variable(v.as_ref().to_owned())
}
/// Construct an unlocated list.
/// Construct a [`Spanning::unlocated`] list.
///
/// Convenience function to make each `InputValue` in the input vector
/// not contain any location information. Can be used from `ToInputValue`
/// Convenience function to make each [`InputValue`] in the input vector
/// not contain any location information. Can be used from [`ToInputValue`]
/// implementations, where no source code position information is available.
pub fn list(l: Vec<Self>) -> Self {
InputValue::List(l.into_iter().map(Spanning::unlocated).collect())
Self::List(l.into_iter().map(Spanning::unlocated).collect())
}
/// Construct a located list.
pub fn parsed_list(l: Vec<Spanning<Self>>) -> Self {
InputValue::List(l)
Self::List(l)
}
/// Construct an unlocated object.
/// Construct aa [`Spanning::unlocated`] object.
///
/// Similar to `InputValue::list`, it makes each key and value in the given
/// hash map not contain any location information.
/// Similarly to [`InputValue::list`] it makes each key and value in the
/// given hash map not contain any location information.
pub fn object<K>(o: IndexMap<K, Self>) -> Self
where
K: AsRef<str> + Eq + Hash,
{
InputValue::Object(
Self::Object(
o.into_iter()
.map(|(k, v)| {
(
@ -301,19 +274,22 @@ where
/// Construct a located object.
pub fn parsed_object(o: Vec<(Spanning<String>, Spanning<Self>)>) -> Self {
InputValue::Object(o)
Self::Object(o)
}
/// Resolve all variables to their values.
pub fn into_const(self, vars: &Variables<S>) -> Self {
pub fn into_const(self, vars: &Variables<S>) -> Self
where
S: Clone,
{
match self {
InputValue::Variable(v) => vars.get(&v).map_or_else(InputValue::null, Clone::clone),
InputValue::List(l) => InputValue::List(
Self::Variable(v) => vars.get(&v).map_or_else(InputValue::null, Clone::clone),
Self::List(l) => Self::List(
l.into_iter()
.map(|s| s.map(|v| v.into_const(vars)))
.collect(),
),
InputValue::Object(o) => InputValue::Object(
Self::Object(o) => Self::Object(
o.into_iter()
.map(|(sk, sv)| (sk, sv.map(|v| v.into_const(vars))))
.collect(),
@ -322,7 +298,7 @@ where
}
}
/// Shorthand form of invoking `FromInputValue::from()`.
/// Shorthand form of invoking [`FromInputValue::from()`].
pub fn convert<T>(&self) -> Option<T>
where
T: FromInputValue<S>,
@ -330,43 +306,52 @@ where
<T as FromInputValue<S>>::from_input_value(self)
}
/// Does the value represent null?
/// Does the value represent a `null`?
pub fn is_null(&self) -> bool {
matches!(*self, InputValue::Null)
matches!(self, Self::Null)
}
/// Does the value represent a variable?
pub fn is_variable(&self) -> bool {
matches!(*self, InputValue::Variable(_))
matches!(self, Self::Variable(_))
}
/// View the underlying enum value, if present.
pub fn as_enum_value(&self) -> Option<&str> {
match *self {
InputValue::Enum(ref e) => Some(e),
match self {
Self::Enum(e) => Some(e.as_str()),
_ => None,
}
}
/// View the underlying int value, if present.
pub fn as_int_value(&self) -> Option<i32> {
pub fn as_int_value(&self) -> Option<i32>
where
S: ScalarValue,
{
self.as_scalar_value().and_then(|s| s.as_int())
}
/// View the underlying float value, if present.
pub fn as_float_value(&self) -> Option<f64> {
pub fn as_float_value(&self) -> Option<f64>
where
S: ScalarValue,
{
self.as_scalar_value().and_then(|s| s.as_float())
}
/// View the underlying string value, if present.
pub fn as_string_value(&self) -> Option<&str> {
pub fn as_string_value(&self) -> Option<&str>
where
S: ScalarValue,
{
self.as_scalar_value().and_then(|s| s.as_str())
}
/// View the underlying scalar value, if present.
pub fn as_scalar(&self) -> Option<&S> {
match *self {
InputValue::Scalar(ref s) => Some(s),
match self {
Self::Scalar(s) => Some(s),
_ => None,
}
}
@ -375,69 +360,71 @@ where
pub fn as_scalar_value<'a, T>(&'a self) -> Option<&'a T>
where
T: 'a,
&'a S: Into<Option<&'a T>>,
Option<&'a T>: From<&'a S>,
{
self.as_scalar().and_then(Into::into)
}
/// Convert the input value to an unlocated object value.
/// Converts this [`InputValue`] to a [`Spanning::unlocated`] object value.
///
/// This constructs a new IndexMap that contain references to the keys
/// and values in `self`.
/// This constructs a new [`IndexMap`] containing references to the keys
/// and values of `self`.
pub fn to_object_value(&self) -> Option<IndexMap<&str, &Self>> {
match *self {
InputValue::Object(ref o) => Some(
match self {
Self::Object(o) => Some(
o.iter()
.map(|&(ref sk, ref sv)| (sk.item.as_str(), &sv.item))
.map(|(sk, sv)| (sk.item.as_str(), &sv.item))
.collect(),
),
_ => None,
}
}
/// Convert the input value to an unlocated list value.
/// Converts this [`InputValue`] to a [`Spanning::unlocated`] list value.
///
/// This constructs a new vector that contain references to the values
/// in `self`.
/// This constructs a new [`Vec`] containing references to the values of
/// `self`.
pub fn to_list_value(&self) -> Option<Vec<&Self>> {
match *self {
InputValue::List(ref l) => Some(l.iter().map(|s| &s.item).collect()),
match self {
Self::List(l) => Some(l.iter().map(|s| &s.item).collect()),
_ => None,
}
}
/// Recursively find all variables
/// Recursively finds all variables
pub fn referenced_variables(&self) -> Vec<&str> {
match *self {
InputValue::Variable(ref name) => vec![name],
InputValue::List(ref l) => l
match self {
Self::Variable(name) => vec![name.as_str()],
Self::List(l) => l
.iter()
.flat_map(|v| v.item.referenced_variables())
.collect(),
InputValue::Object(ref obj) => obj
Self::Object(o) => o
.iter()
.flat_map(|&(_, ref v)| v.item.referenced_variables())
.flat_map(|(_, v)| v.item.referenced_variables())
.collect(),
_ => vec![],
}
}
/// Compare equality with another `InputValue` ignoring any source position information.
pub fn unlocated_eq(&self, other: &Self) -> bool {
use crate::InputValue::*;
/// Compares equality with another [`InputValue``] ignoring any source
/// position information.
pub fn unlocated_eq(&self, other: &Self) -> bool
where
S: PartialEq,
{
match (self, other) {
(&Null, &Null) => true,
(&Scalar(ref s1), &Scalar(ref s2)) => s1 == s2,
(&Enum(ref s1), &Enum(ref s2)) | (&Variable(ref s1), &Variable(ref s2)) => s1 == s2,
(&List(ref l1), &List(ref l2)) => l1
(Self::Null, Self::Null) => true,
(Self::Scalar(s1), Self::Scalar(s2)) => s1 == s2,
(Self::Enum(s1), Self::Enum(s2)) | (Self::Variable(s1), Self::Variable(s2)) => s1 == s2,
(Self::List(l1), Self::List(l2)) => l1
.iter()
.zip(l2.iter())
.all(|(v1, v2)| v1.item.unlocated_eq(&v2.item)),
(&Object(ref o1), &Object(ref o2)) => {
(Self::Object(o1), Self::Object(o2)) => {
o1.len() == o2.len()
&& o1.iter().all(|&(ref sk1, ref sv1)| {
o2.iter().any(|&(ref sk2, ref sv2)| {
&& o1.iter().all(|(sk1, sv1)| {
o2.iter().any(|(sk2, sv2)| {
sk1.item == sk2.item && sv1.item.unlocated_eq(&sv2.item)
})
})
@ -447,23 +434,20 @@ where
}
}
impl<S> fmt::Display for InputValue<S>
where
S: ScalarValue,
{
impl<S: ScalarValue> fmt::Display for InputValue<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
InputValue::Null => write!(f, "null"),
InputValue::Scalar(ref s) => {
match self {
Self::Null => write!(f, "null"),
Self::Scalar(s) => {
if let Some(s) = s.as_str() {
write!(f, "\"{}\"", s)
} else {
write!(f, "{}", s)
}
}
InputValue::Enum(ref v) => write!(f, "{}", v),
InputValue::Variable(ref v) => write!(f, "${}", v),
InputValue::List(ref v) => {
Self::Enum(v) => write!(f, "{}", v),
Self::Variable(v) => write!(f, "${}", v),
Self::List(v) => {
write!(f, "[")?;
for (i, spanning) in v.iter().enumerate() {
@ -475,7 +459,7 @@ where
write!(f, "]")
}
InputValue::Object(ref o) => {
Self::Object(o) => {
write!(f, "{{")?;
for (i, &(ref k, ref v)) in o.iter().enumerate() {

View file

@ -24,7 +24,7 @@ use crate::{
///
/// For GET, you will need to parse the query string and extract "query",
/// "operationName", and "variables" manually.
#[derive(Deserialize, Clone, Serialize, PartialEq, Debug)]
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct GraphQLRequest<S = DefaultScalarValue>
where
S: ScalarValue,
@ -37,7 +37,10 @@ where
pub operation_name: Option<String>,
/// Optional variables to execute the GraphQL operation with.
#[serde(bound(deserialize = "InputValue<S>: Deserialize<'de> + Serialize"))]
#[serde(bound(
deserialize = "InputValue<S>: Deserialize<'de>",
serialize = "InputValue<S>: Serialize",
))]
pub variables: Option<InputValue<S>>,
}

View file

@ -1,34 +1,27 @@
use indexmap::IndexMap;
use serde::{
de,
ser::{self, SerializeMap},
Serialize,
use std::{
convert::{TryFrom as _, TryInto as _},
fmt,
marker::PhantomData,
};
use std::fmt;
use indexmap::IndexMap;
use serde::{
de::{self, Deserializer, IntoDeserializer as _},
ser::{SerializeMap as _, Serializer},
serde_if_integer128, Deserialize, Serialize,
};
use crate::{
ast::InputValue,
executor::ExecutionError,
parser::{ParseError, SourcePosition, Spanning},
validation::RuleError,
GraphQLError, Object, ScalarValue, Value,
DefaultScalarValue, GraphQLError, Object, Value,
};
#[derive(Serialize)]
struct SerializeHelper {
message: &'static str,
}
impl<T> ser::Serialize for ExecutionError<T>
where
T: ScalarValue,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let mut map = serializer.serialize_map(Some(4))?;
impl<T: Serialize> Serialize for ExecutionError<T> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let mut map = ser.serialize_map(Some(4))?;
map.serialize_key("message")?;
map.serialize_value(self.error().message())?;
@ -49,274 +42,184 @@ where
}
}
impl<'a> ser::Serialize for GraphQLError<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
match *self {
GraphQLError::ParseError(ref err) => vec![err].serialize(serializer),
GraphQLError::ValidationError(ref errs) => errs.serialize(serializer),
GraphQLError::NoOperationProvided => [SerializeHelper {
impl<'a> Serialize for GraphQLError<'a> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
struct Helper {
message: &'static str,
}
match self {
Self::ParseError(e) => [e].serialize(ser),
Self::ValidationError(es) => es.serialize(ser),
Self::NoOperationProvided => [Helper {
message: "Must provide an operation",
}]
.serialize(serializer),
GraphQLError::MultipleOperationsProvided => [SerializeHelper {
.serialize(ser),
Self::MultipleOperationsProvided => [Helper {
message: "Must provide operation name \
if query contains multiple operations",
}]
.serialize(serializer),
GraphQLError::UnknownOperationName => [SerializeHelper {
.serialize(ser),
Self::UnknownOperationName => [Helper {
message: "Unknown operation",
}]
.serialize(serializer),
GraphQLError::IsSubscription => [SerializeHelper {
.serialize(ser),
Self::IsSubscription => [Helper {
message: "Expected query, got subscription",
}]
.serialize(serializer),
GraphQLError::NotSubscription => [SerializeHelper {
.serialize(ser),
Self::NotSubscription => [Helper {
message: "Expected subscription, got query",
}]
.serialize(serializer),
.serialize(ser),
}
}
}
impl<'de, S> de::Deserialize<'de> for InputValue<S>
where
S: ScalarValue,
{
fn deserialize<D>(deserializer: D) -> Result<InputValue<S>, D::Error>
where
D: de::Deserializer<'de>,
{
struct InputValueVisitor<S: ScalarValue>(S::Visitor);
impl<'de, S: Deserialize<'de>> Deserialize<'de> for InputValue<S> {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
struct Visitor<S: ?Sized>(PhantomData<S>);
impl<S: ScalarValue> Default for InputValueVisitor<S> {
fn default() -> Self {
InputValueVisitor(S::Visitor::default())
}
}
impl<'de, S> de::Visitor<'de> for InputValueVisitor<S>
where
S: ScalarValue,
{
impl<'de, S: Deserialize<'de>> de::Visitor<'de> for Visitor<S> {
type Value = InputValue<S>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid input value")
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a valid input value")
}
fn visit_bool<E>(self, value: bool) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_bool(value).map(InputValue::Scalar)
fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
S::deserialize(b.into_deserializer()).map(InputValue::Scalar)
}
fn visit_i8<E>(self, value: i8) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_i8(value).map(InputValue::Scalar)
fn visit_i8<E: de::Error>(self, n: i8) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_i16<E>(self, value: i16) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_i16(value).map(InputValue::Scalar)
fn visit_i16<E: de::Error>(self, n: i16) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_i32<E>(self, value: i32) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_i32(value).map(InputValue::Scalar)
fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_i64<E>(self, value: i64) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_i64(value).map(InputValue::Scalar)
fn visit_i64<E: de::Error>(self, n: i64) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
serde::serde_if_integer128! {
fn visit_i128<E>(self, value: i128) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_i128(value).map(InputValue::Scalar)
serde_if_integer128! {
fn visit_i128<E: de::Error>(self, n: i128) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
}
fn visit_u8<E>(self, value: u8) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_u8(value).map(InputValue::Scalar)
fn visit_u8<E: de::Error>(self, n: u8) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_u16<E>(self, value: u16) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_u16(value).map(InputValue::Scalar)
fn visit_u16<E: de::Error>(self, n: u16) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_u32<E>(self, value: u32) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_u32(value).map(InputValue::Scalar)
fn visit_u32<E: de::Error>(self, n: u32) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_u64<E>(self, value: u64) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_u64(value).map(InputValue::Scalar)
fn visit_u64<E: de::Error>(self, n: u64) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
serde::serde_if_integer128! {
fn visit_u128<E>(self, value: u128) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_u128(value).map(InputValue::Scalar)
serde_if_integer128! {
fn visit_u128<E: de::Error>(self, n: u128) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
}
fn visit_f32<E>(self, value: f32) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_f32(value).map(InputValue::Scalar)
fn visit_f32<E: de::Error>(self, n: f32) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_f64<E>(self, value: f64) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_f64(value).map(InputValue::Scalar)
fn visit_f64<E: de::Error>(self, n: f64) -> Result<Self::Value, E> {
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
}
fn visit_char<E>(self, value: char) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_char(value).map(InputValue::Scalar)
fn visit_char<E: de::Error>(self, c: char) -> Result<Self::Value, E> {
S::deserialize(c.into_deserializer()).map(InputValue::Scalar)
}
fn visit_str<E>(self, value: &str) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_str(value).map(InputValue::Scalar)
fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
S::deserialize(s.into_deserializer()).map(InputValue::Scalar)
}
fn visit_string<E>(self, value: String) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_string(value).map(InputValue::Scalar)
fn visit_string<E: de::Error>(self, s: String) -> Result<Self::Value, E> {
S::deserialize(s.into_deserializer()).map(InputValue::Scalar)
}
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_bytes(bytes).map(InputValue::Scalar)
fn visit_bytes<E: de::Error>(self, b: &[u8]) -> Result<Self::Value, E> {
S::deserialize(b.into_deserializer()).map(InputValue::Scalar)
}
fn visit_byte_buf<E>(self, bytes: Vec<u8>) -> Result<InputValue<S>, E>
where
E: de::Error,
{
self.0.visit_byte_buf(bytes).map(InputValue::Scalar)
fn visit_byte_buf<E: de::Error>(self, b: Vec<u8>) -> Result<Self::Value, E> {
S::deserialize(b.into_deserializer()).map(InputValue::Scalar)
}
fn visit_none<E>(self) -> Result<InputValue<S>, E>
where
E: de::Error,
{
Ok(InputValue::null())
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(InputValue::Null)
}
fn visit_unit<E>(self) -> Result<InputValue<S>, E>
where
E: de::Error,
{
Ok(InputValue::null())
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(InputValue::Null)
}
fn visit_seq<V>(self, mut visitor: V) -> Result<InputValue<S>, V::Error>
fn visit_seq<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: de::SeqAccess<'de>,
{
let mut values = Vec::new();
while let Some(el) = visitor.next_element()? {
values.push(el);
let mut vals = Vec::new();
while let Some(v) = visitor.next_element()? {
vals.push(v);
}
Ok(InputValue::list(values))
Ok(InputValue::list(vals))
}
fn visit_map<V>(self, mut visitor: V) -> Result<InputValue<S>, V::Error>
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where
V: de::MapAccess<'de>,
{
let mut object = IndexMap::<String, InputValue<S>>::with_capacity(
let mut obj = IndexMap::<String, InputValue<S>>::with_capacity(
visitor.size_hint().unwrap_or(0),
);
while let Some((key, value)) = visitor.next_entry()? {
object.insert(key, value);
while let Some((key, val)) = visitor.next_entry()? {
obj.insert(key, val);
}
Ok(InputValue::object(object))
Ok(InputValue::object(obj))
}
}
deserializer.deserialize_any(InputValueVisitor::default())
de.deserialize_any(Visitor(PhantomData))
}
}
impl<T> ser::Serialize for InputValue<T>
where
T: ScalarValue,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
match *self {
InputValue::Null | InputValue::Variable(_) => serializer.serialize_unit(),
InputValue::Scalar(ref s) => s.serialize(serializer),
InputValue::Enum(ref v) => serializer.serialize_str(v),
InputValue::List(ref v) => v
impl<T: Serialize> Serialize for InputValue<T> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
match self {
Self::Null | Self::Variable(_) => ser.serialize_unit(),
Self::Scalar(s) => s.serialize(ser),
Self::Enum(e) => ser.serialize_str(e),
Self::List(l) => l.iter().map(|x| &x.item).collect::<Vec<_>>().serialize(ser),
Self::Object(o) => o
.iter()
.map(|x| x.item.clone())
.collect::<Vec<_>>()
.serialize(serializer),
InputValue::Object(ref v) => v
.iter()
.map(|&(ref k, ref v)| (k.item.clone(), v.item.clone()))
.map(|(k, v)| (k.item.as_str(), &v.item))
.collect::<IndexMap<_, _>>()
.serialize(serializer),
.serialize(ser),
}
}
}
impl ser::Serialize for RuleError {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let mut map = serializer.serialize_map(Some(2))?;
impl Serialize for RuleError {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let mut map = ser.serialize_map(Some(2))?;
map.serialize_key("message")?;
map.serialize_value(self.message())?;
@ -328,12 +231,9 @@ impl ser::Serialize for RuleError {
}
}
impl ser::Serialize for SourcePosition {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let mut map = serializer.serialize_map(Some(2))?;
impl Serialize for SourcePosition {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let mut map = ser.serialize_map(Some(2))?;
let line = self.line() + 1;
map.serialize_key("line")?;
@ -347,23 +247,19 @@ impl ser::Serialize for SourcePosition {
}
}
impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let mut map = serializer.serialize_map(Some(2))?;
impl<'a> Serialize for Spanning<ParseError<'a>> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let mut map = ser.serialize_map(Some(2))?;
let message = format!("{}", self.item);
let msg = format!("{}", self.item);
map.serialize_key("message")?;
map.serialize_value(&message)?;
map.serialize_value(&msg)?;
let mut location = IndexMap::new();
location.insert("line".to_owned(), self.start.line() + 1);
location.insert("column".to_owned(), self.start.column() + 1);
let locations = vec![location];
let mut loc = IndexMap::new();
loc.insert("line".to_owned(), self.start.line() + 1);
loc.insert("column".to_owned(), self.start.column() + 1);
let locations = vec![loc];
map.serialize_key("locations")?;
map.serialize_value(&locations)?;
@ -371,57 +267,107 @@ impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
}
}
impl<T> ser::Serialize for Object<T>
where
T: ser::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
let mut map = serializer.serialize_map(Some(self.field_count()))?;
for (ref f, ref v) in self.iter() {
impl<T: Serialize> Serialize for Object<T> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
let mut map = ser.serialize_map(Some(self.field_count()))?;
for (f, v) in self.iter() {
map.serialize_key(f)?;
map.serialize_value(v)?;
}
map.end()
}
}
impl<T> ser::Serialize for Value<T>
where
T: ser::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
match *self {
Value::Null => serializer.serialize_unit(),
Value::Scalar(ref s) => s.serialize(serializer),
Value::List(ref v) => v.serialize(serializer),
Value::Object(ref v) => v.serialize(serializer),
impl<T: Serialize> Serialize for Value<T> {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
match self {
Self::Null => ser.serialize_unit(),
Self::Scalar(s) => s.serialize(ser),
Self::List(l) => l.serialize(ser),
Self::Object(o) => o.serialize(ser),
}
}
}
impl<'de> Deserialize<'de> for DefaultScalarValue {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = DefaultScalarValue;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a valid input value")
}
fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
Ok(DefaultScalarValue::Boolean(b))
}
fn visit_i64<E: de::Error>(self, n: i64) -> Result<Self::Value, E> {
if n >= i64::from(i32::MIN) && n <= i64::from(i32::MAX) {
Ok(DefaultScalarValue::Int(n.try_into().unwrap()))
} else {
// Browser's `JSON.stringify()` serializes all numbers
// having no fractional part as integers (no decimal point),
// so we must parse large integers as floating point,
// otherwise we would error on transferring large floating
// point numbers.
// TODO: Use `FloatToInt` conversion once stabilized:
// https://github.com/rust-lang/rust/issues/67057
Ok(DefaultScalarValue::Float(n as f64))
}
}
fn visit_u64<E: de::Error>(self, n: u64) -> Result<Self::Value, E> {
if n <= u64::try_from(i32::MAX).unwrap() {
self.visit_i64(n.try_into().unwrap())
} else {
// Browser's `JSON.stringify()` serializes all numbers
// having no fractional part as integers (no decimal point),
// so we must parse large integers as floating point,
// otherwise we would error on transferring large floating
// point numbers.
// TODO: Use `FloatToInt` conversion once stabilized:
// https://github.com/rust-lang/rust/issues/67057
Ok(DefaultScalarValue::Float(n as f64))
}
}
fn visit_f64<E: de::Error>(self, f: f64) -> Result<Self::Value, E> {
Ok(DefaultScalarValue::Float(f))
}
fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
self.visit_string(s.into())
}
fn visit_string<E: de::Error>(self, s: String) -> Result<Self::Value, E> {
Ok(DefaultScalarValue::String(s))
}
}
de.deserialize_any(Visitor)
}
}
#[cfg(test)]
mod tests {
use super::{ExecutionError, GraphQLError};
use serde_json::{from_str, to_string};
use crate::{
ast::InputValue,
value::{DefaultScalarValue, Object},
FieldError, Value,
};
use serde_json::{from_str, to_string};
use super::{ExecutionError, GraphQLError};
#[test]
fn int() {
assert_eq!(
from_str::<InputValue<DefaultScalarValue>>("1235").unwrap(),
InputValue::scalar(1235)
InputValue::scalar(1235),
);
}
@ -429,12 +375,12 @@ mod tests {
fn float() {
assert_eq!(
from_str::<InputValue<DefaultScalarValue>>("2.0").unwrap(),
InputValue::scalar(2.0)
InputValue::scalar(2.0),
);
// large value without a decimal part is also float
assert_eq!(
from_str::<InputValue<DefaultScalarValue>>("123567890123").unwrap(),
InputValue::scalar(123_567_890_123.0)
InputValue::scalar(123_567_890_123.0),
);
}
@ -442,7 +388,7 @@ mod tests {
fn errors() {
assert_eq!(
to_string(&GraphQLError::UnknownOperationName).unwrap(),
r#"[{"message":"Unknown operation"}]"#
r#"[{"message":"Unknown operation"}]"#,
);
}
@ -456,7 +402,7 @@ mod tests {
Value::Object(obj),
)))
.unwrap(),
r#"{"message":"foo error","locations":[{"line":1,"column":1}],"path":[],"extensions":{"foo":"bar"}}"#
r#"{"message":"foo error","locations":[{"line":1,"column":1}],"path":[],"extensions":{"foo":"bar"}}"#,
);
}
}

View file

@ -82,7 +82,7 @@ impl<T> Spanning<T> {
}
/// Modify the contents of the spanned item
pub fn map<O: fmt::Debug, F: Fn(T) -> O>(self, f: F) -> Spanning<O> {
pub fn map<O, F: Fn(T) -> O>(self, f: F) -> Spanning<O> {
Spanning {
item: f(self.item),
start: self.start,

View file

@ -35,7 +35,7 @@ pub enum Value<S = DefaultScalarValue> {
Object(Object<S>),
}
impl<S: ScalarValue> Value<S> {
impl<S> Value<S> {
// CONSTRUCTORS
/// Construct a null value.
@ -43,30 +43,6 @@ impl<S: ScalarValue> Value<S> {
Self::Null
}
/// Construct an integer value.
#[deprecated(since = "0.11.0", note = "Use `Value::scalar` instead")]
pub fn int(i: i32) -> Self {
Self::scalar(i)
}
/// Construct a floating point value.
#[deprecated(since = "0.11.0", note = "Use `Value::scalar` instead")]
pub fn float(f: f64) -> Self {
Self::scalar(f)
}
/// Construct a string value.
#[deprecated(since = "0.11.0", note = "Use `Value::scalar` instead")]
pub fn string(s: &str) -> Self {
Self::scalar(s.to_owned())
}
/// Construct a boolean value.
#[deprecated(since = "0.11.0", note = "Use `Value::scalar` instead")]
pub fn boolean(b: bool) -> Self {
Self::scalar(b)
}
/// Construct a list value.
pub fn list(l: Vec<Self>) -> Self {
Self::List(l)
@ -80,7 +56,7 @@ impl<S: ScalarValue> Value<S> {
/// Construct a scalar value
pub fn scalar<T>(s: T) -> Self
where
T: Into<S>,
S: From<T>,
{
Self::Scalar(s.into())
}
@ -95,26 +71,29 @@ impl<S: ScalarValue> Value<S> {
/// View the underlying scalar value if present
pub fn as_scalar_value<'a, T>(&'a self) -> Option<&'a T>
where
&'a S: Into<Option<&'a T>>,
Option<&'a T>: From<&'a S>,
{
match *self {
Self::Scalar(ref s) => s.into(),
match self {
Self::Scalar(s) => s.into(),
_ => None,
}
}
/// View the underlying float value, if present.
pub fn as_float_value(&self) -> Option<f64> {
pub fn as_float_value(&self) -> Option<f64>
where
S: ScalarValue,
{
match self {
Self::Scalar(ref s) => s.as_float(),
Self::Scalar(s) => s.as_float(),
_ => None,
}
}
/// View the underlying object value, if present.
pub fn as_object_value(&self) -> Option<&Object<S>> {
match *self {
Self::Object(ref o) => Some(o),
match self {
Self::Object(o) => Some(o),
_ => None,
}
}
@ -131,24 +110,24 @@ impl<S: ScalarValue> Value<S> {
/// Mutable view into the underlying object value, if present.
pub fn as_mut_object_value(&mut self) -> Option<&mut Object<S>> {
match *self {
Self::Object(ref mut o) => Some(o),
match self {
Self::Object(o) => Some(o),
_ => None,
}
}
/// View the underlying list value, if present.
pub fn as_list_value(&self) -> Option<&Vec<Self>> {
match *self {
Self::List(ref l) => Some(l),
match self {
Self::List(l) => Some(l),
_ => None,
}
}
/// View the underlying scalar value, if present
pub fn as_scalar(&self) -> Option<&S> {
match *self {
Self::Scalar(ref s) => Some(s),
match self {
Self::Scalar(s) => Some(s),
_ => None,
}
}
@ -158,11 +137,15 @@ impl<S: ScalarValue> Value<S> {
where
Option<&'a String>: From<&'a S>,
{
self.as_scalar_value::<String>().map(|s| s as &str)
self.as_scalar_value::<String>().map(String::as_str)
}
/// Maps the [`ScalarValue`] type of this [`Value`] into the specified one.
pub fn map_scalar_value<Into: ScalarValue>(self) -> Value<Into> {
pub fn map_scalar_value<Into>(self) -> Value<Into>
where
S: ScalarValue,
Into: ScalarValue,
{
if TypeId::of::<Into>() == TypeId::of::<S>() {
// SAFETY: This is safe, because we're transmuting the value into
// itself, so no invariants may change and we're just
@ -187,17 +170,17 @@ impl<S: ScalarValue> Value<S> {
}
}
impl<S: ScalarValue> ToInputValue<S> for Value<S> {
impl<S: Clone> ToInputValue<S> for Value<S> {
fn to_input_value(&self) -> InputValue<S> {
match *self {
Value::Null => InputValue::Null,
Value::Scalar(ref s) => InputValue::Scalar(s.clone()),
Value::List(ref l) => InputValue::List(
match self {
Self::Null => InputValue::Null,
Self::Scalar(s) => InputValue::Scalar(s.clone()),
Self::List(l) => InputValue::List(
l.iter()
.map(|x| Spanning::unlocated(x.to_input_value()))
.collect(),
),
Value::Object(ref o) => InputValue::Object(
Self::Object(o) => InputValue::Object(
o.iter()
.map(|(k, v)| {
(
@ -214,15 +197,15 @@ impl<S: ScalarValue> ToInputValue<S> for Value<S> {
impl<S: ScalarValue> Display for Value<S> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Value::Null => write!(f, "null"),
Value::Scalar(s) => {
Self::Null => write!(f, "null"),
Self::Scalar(s) => {
if let Some(string) = s.as_string() {
write!(f, "\"{}\"", string)
} else {
write!(f, "{}", s)
}
}
Value::List(list) => {
Self::List(list) => {
write!(f, "[")?;
for (idx, item) in list.iter().enumerate() {
write!(f, "{}", item)?;
@ -234,7 +217,7 @@ impl<S: ScalarValue> Display for Value<S> {
Ok(())
}
Value::Object(obj) => {
Self::Object(obj) => {
write!(f, "{{")?;
for (idx, (key, value)) in obj.iter().enumerate() {
write!(f, "\"{}\": {}", key, value)?;
@ -253,59 +236,43 @@ impl<S: ScalarValue> Display for Value<S> {
impl<S, T> From<Option<T>> for Value<S>
where
S: ScalarValue,
Value<S>: From<T>,
Self: From<T>,
{
fn from(v: Option<T>) -> Value<S> {
fn from(v: Option<T>) -> Self {
match v {
Some(v) => v.into(),
None => Value::null(),
None => Self::Null,
}
}
}
impl<'a, S> From<&'a str> for Value<S>
where
S: ScalarValue,
{
impl<'a, S: From<String>> From<&'a str> for Value<S> {
fn from(s: &'a str) -> Self {
Value::scalar(s.to_owned())
Self::scalar(s.to_owned())
}
}
impl<S> From<String> for Value<S>
where
S: ScalarValue,
{
impl<S: From<String>> From<String> for Value<S> {
fn from(s: String) -> Self {
Value::scalar(s)
Self::scalar(s)
}
}
impl<S> From<i32> for Value<S>
where
S: ScalarValue,
{
impl<S: From<i32>> From<i32> for Value<S> {
fn from(i: i32) -> Self {
Value::scalar(i)
Self::scalar(i)
}
}
impl<S> From<f64> for Value<S>
where
S: ScalarValue,
{
impl<S: From<f64>> From<f64> for Value<S> {
fn from(f: f64) -> Self {
Value::scalar(f)
Self::scalar(f)
}
}
impl<S> From<bool> for Value<S>
where
S: ScalarValue,
{
impl<S: From<bool>> From<bool> for Value<S> {
fn from(b: bool) -> Self {
Value::scalar(b)
Self::scalar(b)
}
}

View file

@ -1,6 +1,6 @@
use std::fmt;
use serde::{de, ser::Serialize};
use serde::{de::DeserializeOwned, Serialize};
use crate::{
parser::{ParseError, ScalarToken},
@ -24,9 +24,8 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
/// needs.
/// There is a custom derive (`#[derive(juniper::GraphQLScalarValue)]`) available that implements
/// most of the required traits automatically for a enum representing a scalar value.
/// This derives needs a additional annotation of the form
/// `#[juniper(visitor = "VisitorType")]` to specify a type that implements
/// `serde::de::Visitor` and that is used to deserialize the value.
/// However, [`Serialize`](trait@serde::Serialize) and [`Deserialize`](trait@serde::Deserialize)
/// implementations are expected to be provided.
///
/// # Implementing a new scalar value representation
/// The preferred way to define a new scalar value representation is
@ -34,12 +33,13 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
/// at the lowest level.
/// The following example introduces an new variant that is able to store 64 bit integers.
///
/// ```
/// # use std::fmt;
/// # use serde::{de, Deserialize, Deserializer};
/// # use juniper::ScalarValue;
/// ```rust
/// # use std::{fmt, convert::TryInto as _};
/// # use serde::{de, Deserialize, Deserializer, Serialize};
/// # use juniper::{GraphQLScalarValue, ScalarValue};
/// #
/// #[derive(Debug, Clone, PartialEq, juniper::GraphQLScalarValue)]
/// #[derive(Clone, Debug, GraphQLScalarValue, PartialEq, Serialize)]
/// #[serde(untagged)]
/// enum MyScalarValue {
/// Int(i32),
/// Long(i64),
@ -49,18 +49,16 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
/// }
///
/// impl ScalarValue for MyScalarValue {
/// type Visitor = MyScalarValueVisitor;
///
/// fn as_int(&self) -> Option<i32> {
/// match *self {
/// Self::Int(ref i) => Some(*i),
/// fn as_int(&self) -> Option<i32> {
/// match self {
/// Self::Int(i) => Some(*i),
/// _ => None,
/// }
/// }
///
/// fn as_string(&self) -> Option<String> {
/// match *self {
/// Self::String(ref s) => Some(s.clone()),
/// match self {
/// Self::String(s) => Some(s.clone()),
/// _ => None,
/// }
/// }
@ -73,110 +71,99 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
/// }
///
/// fn as_str(&self) -> Option<&str> {
/// match *self {
/// Self::String(ref s) => Some(s.as_str()),
/// match self {
/// Self::String(s) => Some(s.as_str()),
/// _ => None,
/// }
/// }
///
/// fn as_float(&self) -> Option<f64> {
/// match *self {
/// Self::Int(ref i) => Some(*i as f64),
/// Self::Float(ref f) => Some(*f),
/// match self {
/// Self::Int(i) => Some(f64::from(*i)),
/// Self::Float(f) => Some(*f),
/// _ => None,
/// }
/// }
///
/// fn as_boolean(&self) -> Option<bool> {
/// match *self {
/// Self::Boolean(ref b) => Some(*b),
/// match self {
/// Self::Boolean(b) => Some(*b),
/// _ => None,
/// }
/// }
/// }
///
/// #[derive(Default)]
/// struct MyScalarValueVisitor;
/// impl<'de> Deserialize<'de> for MyScalarValue {
/// fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
/// struct Visitor;
///
/// impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
/// type Value = MyScalarValue;
/// impl<'de> de::Visitor<'de> for Visitor {
/// type Value = MyScalarValue;
///
/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
/// formatter.write_str("a valid input value")
/// }
/// fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
/// f.write_str("a valid input value")
/// }
///
/// fn visit_bool<E>(self, value: bool) -> Result<MyScalarValue, E> {
/// Ok(MyScalarValue::Boolean(value))
/// }
/// fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
/// Ok(MyScalarValue::Boolean(b))
/// }
///
/// fn visit_i32<E>(self, value: i32) -> Result<MyScalarValue, E>
/// where
/// E: de::Error,
/// {
/// Ok(MyScalarValue::Int(value))
/// }
/// fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
/// Ok(MyScalarValue::Int(n))
/// }
///
/// fn visit_i64<E>(self, value: i64) -> Result<MyScalarValue, E>
/// where
/// E: de::Error,
/// {
/// if value <= i32::max_value() as i64 {
/// self.visit_i32(value as i32)
/// } else {
/// Ok(MyScalarValue::Long(value))
/// fn visit_i64<E: de::Error>(self, n: i64) -> Result<Self::Value, E> {
/// if n <= i64::from(i32::MAX) {
/// self.visit_i32(n.try_into().unwrap())
/// } else {
/// Ok(MyScalarValue::Long(n))
/// }
/// }
///
/// fn visit_u32<E: de::Error>(self, n: u32) -> Result<Self::Value, E> {
/// if n <= i32::MAX as u32 {
/// self.visit_i32(n.try_into().unwrap())
/// } else {
/// self.visit_u64(n.into())
/// }
/// }
///
/// fn visit_u64<E: de::Error>(self, n: u64) -> Result<Self::Value, E> {
/// if n <= i64::MAX as u64 {
/// self.visit_i64(n.try_into().unwrap())
/// } else {
/// // Browser's `JSON.stringify()` serialize all numbers
/// // having no fractional part as integers (no decimal
/// // point), so we must parse large integers as floating
/// // point, otherwise we would error on transferring large
/// // floating point numbers.
/// Ok(MyScalarValue::Float(n as f64))
/// }
/// }
///
/// fn visit_f64<E: de::Error>(self, f: f64) -> Result<Self::Value, E> {
/// Ok(MyScalarValue::Float(f))
/// }
///
/// fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
/// self.visit_string(s.into())
/// }
///
/// fn visit_string<E: de::Error>(self, s: String) -> Result<Self::Value, E> {
/// Ok(MyScalarValue::String(s))
/// }
/// }
/// }
///
/// fn visit_u32<E>(self, value: u32) -> Result<MyScalarValue, E>
/// where
/// E: de::Error,
/// {
/// if value <= i32::max_value() as u32 {
/// self.visit_i32(value as i32)
/// } else {
/// self.visit_u64(value as u64)
/// }
/// }
///
/// fn visit_u64<E>(self, value: u64) -> Result<MyScalarValue, E>
/// where
/// E: de::Error,
/// {
/// if value <= i64::max_value() as u64 {
/// self.visit_i64(value as i64)
/// } else {
/// // Browser's JSON.stringify serialize all numbers having no
/// // fractional part as integers (no decimal point), so we
/// // must parse large integers as floating point otherwise
/// // we would error on transferring large floating point
/// // numbers.
/// Ok(MyScalarValue::Float(value as f64))
/// }
/// }
///
/// fn visit_f64<E>(self, value: f64) -> Result<MyScalarValue, E> {
/// Ok(MyScalarValue::Float(value))
/// }
///
/// fn visit_str<E>(self, value: &str) -> Result<MyScalarValue, E>
/// where
/// E: de::Error,
/// {
/// self.visit_string(value.into())
/// }
///
/// fn visit_string<E>(self, value: String) -> Result<MyScalarValue, E> {
/// Ok(MyScalarValue::String(value))
/// de.deserialize_any(Visitor)
/// }
/// }
///
/// # fn main() {}
/// ```
pub trait ScalarValue:
fmt::Debug
+ fmt::Display
+ PartialEq
+ Clone
+ DeserializeOwned
+ Serialize
+ From<String>
+ From<bool>
@ -184,65 +171,68 @@ pub trait ScalarValue:
+ From<f64>
+ 'static
{
/// Serde visitor used to deserialize this scalar value
type Visitor: for<'de> de::Visitor<'de, Value = Self> + Default;
/// Checks if the current value contains the a value of the current type
/// Checks whether this [`ScalarValue`] contains the value of the given
/// type.
///
/// ```
/// # use juniper::{ScalarValue, DefaultScalarValue};
///
/// #
/// let value = DefaultScalarValue::Int(42);
///
/// assert_eq!(value.is_type::<i32>(), true);
/// assert_eq!(value.is_type::<f64>(), false);
///
/// ```
#[must_use]
fn is_type<'a, T>(&'a self) -> bool
where
T: 'a,
&'a Self: Into<Option<&'a T>>,
Option<&'a T>: From<&'a Self>,
{
self.into().is_some()
<Option<&'a T>>::from(self).is_some()
}
/// Convert the given scalar value into an integer value
/// Represents this [`ScalarValue`] as an integer value.
///
/// This function is used for implementing `GraphQLValue` for `i32` for all
/// scalar values. Implementations should convert all supported integer
/// types with 32 bit or less to an integer if requested.
/// This function is used for implementing [`GraphQLValue`] for [`i32`] for
/// all possible [`ScalarValue`]s. Implementations should convert all the
/// supported integer types with 32 bit or less to an integer, if requested.
#[must_use]
fn as_int(&self) -> Option<i32>;
/// Represents this [`ScalarValue`] a [`String`] value.
/// Represents this [`ScalarValue`] as a [`String`] value.
///
/// This function is used for implementing `GraphQLValue` for `String` for all
/// scalar values
/// This function is used for implementing [`GraphQLValue`] for [`String`]
/// for all possible [`ScalarValue`]s.
#[must_use]
fn as_string(&self) -> Option<String>;
/// Converts this [`ScalarValue`] into a [`String`] value.
///
/// Same as [`ScalarValue::as_string`], but takes ownership, so allows to omit redundant
/// cloning.
/// Same as [`ScalarValue::as_string()`], but takes ownership, so allows to
/// omit redundant cloning.
#[must_use]
fn into_string(self) -> Option<String>;
/// Convert the given scalar value into a string value
/// Represents this [`ScalarValue`] as a [`str`] value.
///
/// This function is used for implementing `GraphQLValue` for `String` for all
/// scalar values
/// This function is used for implementing [`GraphQLValue`] for [`str`] for
/// all possible [`ScalarValue`]s.
#[must_use]
fn as_str(&self) -> Option<&str>;
/// Convert the given scalar value into a float value
/// Represents this [`ScalarValue`] as a float value.
///
/// This function is used for implementing `GraphQLValue` for `f64` for all
/// scalar values. Implementations should convert all supported integer
/// types with 64 bit or less and all floating point values with 64 bit or
/// less to a float if requested.
/// This function is used for implementing [`GraphQLValue`] for [`f64`] for
/// all possible [`ScalarValue`]s. Implementations should convert all
/// supported integer types with 64 bit or less and all floating point
/// values with 64 bit or less to a float, if requested.
#[must_use]
fn as_float(&self) -> Option<f64>;
/// Convert the given scalar value into a boolean value
/// Represents this [`ScalarValue`] as a boolean value
///
/// This function is used for implementing `GraphQLValue` for `bool` for all
/// scalar values.
/// This function is used for implementing [`GraphQLValue`] for [`bool`] for
/// all possible [`ScalarValue`]s.
fn as_boolean(&self) -> Option<bool>;
/// Converts this [`ScalarValue`] into another one.
@ -261,46 +251,64 @@ pub trait ScalarValue:
}
}
/// The default scalar value representation in juniper
/// The default [`ScalarValue`] representation in [`juniper`].
///
/// This types closely follows the graphql specification.
#[derive(Debug, PartialEq, Clone, GraphQLScalarValue)]
#[allow(missing_docs)]
/// These types closely follow the [GraphQL specification][0].
///
/// [0]: https://spec.graphql.org/June2018
#[derive(Clone, Debug, GraphQLScalarValue, PartialEq, Serialize)]
#[serde(untagged)]
pub enum DefaultScalarValue {
/// [`Int` scalar][0] as a signed 32bit numeric nonfractional value.
///
/// [0]: https://spec.graphql.org/June2018/#sec-Int
Int(i32),
/// [`Float` scalar][0] as a signed doubleprecision fractional values as
/// specified by [IEEE 754].
///
/// [0]: https://spec.graphql.org/June2018/#sec-Float
/// [IEEE 754]: https://en.wikipedia.org/wiki/IEEE_floating_point
Float(f64),
/// [`String` scalar][0] as a textual data, represented as UTF8 character
/// sequences.
///
/// [0]: https://spec.graphql.org/June2018/#sec-String
String(String),
/// [`Boolean` scalar][0] as a `true` or `false` value.
///
/// [0]: https://spec.graphql.org/June2018/#sec-Boolean
Boolean(bool),
}
impl ScalarValue for DefaultScalarValue {
type Visitor = DefaultScalarValueVisitor;
fn as_int(&self) -> Option<i32> {
match *self {
Self::Int(ref i) => Some(*i),
match self {
Self::Int(i) => Some(*i),
_ => None,
}
}
fn as_float(&self) -> Option<f64> {
match *self {
Self::Int(ref i) => Some(*i as f64),
Self::Float(ref f) => Some(*f),
match self {
Self::Int(i) => Some(f64::from(*i)),
Self::Float(f) => Some(*f),
_ => None,
}
}
fn as_str(&self) -> Option<&str> {
match *self {
Self::String(ref s) => Some(s.as_str()),
match self {
Self::String(s) => Some(s.as_str()),
_ => None,
}
}
fn as_string(&self) -> Option<String> {
match *self {
Self::String(ref s) => Some(s.clone()),
match self {
Self::String(s) => Some(s.clone()),
_ => None,
}
}
@ -313,8 +321,8 @@ impl ScalarValue for DefaultScalarValue {
}
fn as_boolean(&self) -> Option<bool> {
match *self {
Self::Boolean(ref b) => Some(*b),
match self {
Self::Boolean(b) => Some(*b),
_ => None,
}
}
@ -334,65 +342,3 @@ impl<'a> From<&'a str> for DefaultScalarValue {
Self::String(s.into())
}
}
#[derive(Default, Clone, Copy, Debug)]
pub struct DefaultScalarValueVisitor;
impl<'de> de::Visitor<'de> for DefaultScalarValueVisitor {
type Value = DefaultScalarValue;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a valid input value")
}
fn visit_bool<E>(self, value: bool) -> Result<DefaultScalarValue, E> {
Ok(DefaultScalarValue::Boolean(value))
}
fn visit_i64<E>(self, value: i64) -> Result<DefaultScalarValue, E>
where
E: de::Error,
{
if value >= i64::from(i32::min_value()) && value <= i64::from(i32::max_value()) {
Ok(DefaultScalarValue::Int(value as i32))
} else {
// Browser's JSON.stringify serialize all numbers having no
// fractional part as integers (no decimal point), so we
// must parse large integers as floating point otherwise
// we would error on transferring large floating point
// numbers.
Ok(DefaultScalarValue::Float(value as f64))
}
}
fn visit_u64<E>(self, value: u64) -> Result<DefaultScalarValue, E>
where
E: de::Error,
{
if value <= i32::max_value() as u64 {
self.visit_i64(value as i64)
} else {
// Browser's JSON.stringify serialize all numbers having no
// fractional part as integers (no decimal point), so we
// must parse large integers as floating point otherwise
// we would error on transferring large floating point
// numbers.
Ok(DefaultScalarValue::Float(value as f64))
}
}
fn visit_f64<E>(self, value: f64) -> Result<DefaultScalarValue, E> {
Ok(DefaultScalarValue::Float(value))
}
fn visit_str<E>(self, value: &str) -> Result<DefaultScalarValue, E>
where
E: de::Error,
{
self.visit_string(value.into())
}
fn visit_string<E>(self, value: String) -> Result<DefaultScalarValue, E> {
Ok(DefaultScalarValue::String(value))
}
}

View file

@ -236,14 +236,11 @@ fn impl_scalar_enum(
.map(|v| derive_from_variant(v, ident, &error))
.collect::<Result<Vec<_>, _>>()?;
let serialize = derive_serialize(data.variants.iter(), ident);
let display = derive_display(data.variants.iter(), ident);
Ok(quote! {
#(#froms)*
#serialize
#display
})
}
@ -268,28 +265,6 @@ where
}
}
fn derive_serialize<'a, I>(variants: I, ident: &Ident) -> TokenStream
where
I: Iterator<Item = &'a Variant>,
{
let arms = variants.map(|v| {
let variant = &v.ident;
quote!(#ident::#variant(ref v) => v.serialize(serializer),)
});
quote! {
impl ::juniper::serde::Serialize for #ident {
fn serialize<S>(&self, serializer: S) -> ::std::result::Result<S::Ok, S::Error>
where S: ::juniper::serde::Serializer
{
match *self {
#(#arms)*
}
}
}
}
}
fn derive_from_variant(
variant: &Variant,
ident: &Ident,

View file

@ -1,4 +1,4 @@
use juniper::{ScalarValue, Variables};
use juniper::Variables;
use serde::Deserialize;
use crate::utils::default_for_null;
@ -6,9 +6,9 @@ use crate::utils::default_for_null;
/// The payload for a client's "start" message. This triggers execution of a query, mutation, or
/// subscription.
#[derive(Debug, Deserialize, PartialEq)]
#[serde(bound(deserialize = "S: ScalarValue"))]
#[serde(bound(deserialize = "S: Deserialize<'de>"))]
#[serde(rename_all = "camelCase")]
pub struct StartPayload<S: ScalarValue> {
pub struct StartPayload<S> {
/// The document body.
pub query: String,
@ -22,10 +22,10 @@ pub struct StartPayload<S: ScalarValue> {
/// ClientMessage defines the message types that clients can send.
#[derive(Debug, Deserialize, PartialEq)]
#[serde(bound(deserialize = "S: ScalarValue"))]
#[serde(bound(deserialize = "S: Deserialize<'de>"))]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
pub enum ClientMessage<S: ScalarValue> {
pub enum ClientMessage<S> {
/// ConnectionInit is sent by the client upon connecting.
ConnectionInit {
/// Optional parameters of any type sent from the client. These are often used for

View file

@ -1,6 +1,6 @@
use std::{any::Any, fmt, marker::PhantomPinned, mem};
use juniper::{ExecutionError, GraphQLError, ScalarValue, Value};
use juniper::{ExecutionError, GraphQLError, Value};
use serde::{Serialize, Serializer};
/// The payload for errors that are not associated with a GraphQL operation.
@ -14,7 +14,6 @@ pub struct ConnectionErrorPayload {
/// Sent after execution of an operation. For queries and mutations, this is sent to the client
/// once. For subscriptions, this is sent for every event in the event stream.
#[derive(Debug, Serialize, PartialEq)]
#[serde(bound(serialize = "S: ScalarValue"))]
#[serde(rename_all = "camelCase")]
pub struct DataPayload<S> {
/// The result data.
@ -90,10 +89,9 @@ impl From<GraphQLError<'static>> for ErrorPayload {
/// ServerMessage defines the message types that servers can send.
#[derive(Debug, Serialize, PartialEq)]
#[serde(bound(serialize = "S: ScalarValue"))]
#[serde(rename_all = "snake_case")]
#[serde(tag = "type")]
pub enum ServerMessage<S: ScalarValue> {
pub enum ServerMessage<S> {
/// ConnectionError is used for errors that are not associated with a GraphQL operation. For
/// example, this will be used when:
///

View file

@ -185,15 +185,12 @@ fn parse_variable_param<S>(params: Option<Vec<String>>) -> IronResult<Option<Inp
where
S: ScalarValue,
{
if let Some(values) = params {
Ok(
serde_json::from_str::<InputValue<S>>(get_single_value(values)?.as_ref())
.map(Some)
.map_err(GraphQLIronError::Serde)?,
)
} else {
Ok(None)
}
params
.map(|vals| {
serde_json::from_str::<InputValue<S>>(get_single_value(vals)?.as_ref())
.map_err(|e| GraphQLIronError::Serde(e).into())
})
.transpose()
}
impl<'a, CtxFactory, Query, Mutation, Subscription, CtxT, S>

View file

@ -40,13 +40,14 @@ Check the LICENSE file for details.
#![deny(warnings)]
#![doc(html_root_url = "https://docs.rs/juniper_warp/0.2.0")]
use std::{collections::HashMap, str, sync::Arc};
use anyhow::anyhow;
use futures::{FutureExt as _, TryFutureExt};
use juniper::{
http::{GraphQLBatchRequest, GraphQLRequest},
ScalarValue,
};
use std::{collections::HashMap, str, sync::Arc};
use tokio::task;
use warp::{body, filters::BoxedFilter, http, hyper::body::Bytes, query, Filter};
@ -381,6 +382,8 @@ fn playground_response(
/// [1]: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md
#[cfg(feature = "subscriptions")]
pub mod subscriptions {
use std::{convert::Infallible, fmt, sync::Arc};
use juniper::{
futures::{
future::{self, Either},
@ -390,7 +393,6 @@ pub mod subscriptions {
GraphQLSubscriptionType, GraphQLTypeAsync, RootNode, ScalarValue,
};
use juniper_graphql_ws::{ArcSchema, ClientMessage, Connection, Init};
use std::{convert::Infallible, fmt, sync::Arc};
struct Message(warp::ws::Message);