Replace ScalarValue::Visitor
with DeserializeOwned
requirement (#985)
- remove `Serialize` impl from `#[derive(GraphQLScalarValue)]` macro expansion
This commit is contained in:
parent
168114fcf0
commit
f66296d618
14 changed files with 576 additions and 764 deletions
|
@ -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"] }
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -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"}}"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 32‐bit numeric non‐fractional value.
|
||||
///
|
||||
/// [0]: https://spec.graphql.org/June2018/#sec-Int
|
||||
Int(i32),
|
||||
|
||||
/// [`Float` scalar][0] as a signed double‐precision 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 UTF‐8 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))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
///
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in a new issue