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]
|
[dev-dependencies]
|
||||||
async-trait = "0.1.39"
|
async-trait = "0.1.39"
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
fnv = "1.0"
|
fnv = "1.0"
|
||||||
tokio = { version = "1", features = ["rt", "macros", "time"] }
|
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 futures::{stream, Stream};
|
||||||
use juniper::{
|
use juniper::{
|
||||||
execute, graphql_object, graphql_scalar, graphql_subscription,
|
execute, graphql_object, graphql_scalar, graphql_subscription,
|
||||||
parser::{ParseError, ScalarToken, Spanning, Token},
|
parser::{ParseError, ScalarToken, Spanning, Token},
|
||||||
serde::de,
|
serde::{de, Deserialize, Deserializer, Serialize},
|
||||||
EmptyMutation, FieldResult, GraphQLScalarValue, InputValue, Object, ParseScalarResult,
|
EmptyMutation, FieldResult, GraphQLScalarValue, InputValue, Object, ParseScalarResult,
|
||||||
RootNode, ScalarValue, Value, Variables,
|
RootNode, ScalarValue, Value, Variables,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(GraphQLScalarValue, Clone, Debug, PartialEq)]
|
#[derive(GraphQLScalarValue, Clone, Debug, PartialEq, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
pub(crate) enum MyScalarValue {
|
pub(crate) enum MyScalarValue {
|
||||||
Int(i32),
|
Int(i32),
|
||||||
Long(i64),
|
Long(i64),
|
||||||
|
@ -19,18 +20,16 @@ pub(crate) enum MyScalarValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScalarValue for MyScalarValue {
|
impl ScalarValue for MyScalarValue {
|
||||||
type Visitor = MyScalarValueVisitor;
|
|
||||||
|
|
||||||
fn as_int(&self) -> Option<i32> {
|
fn as_int(&self) -> Option<i32> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Int(ref i) => Some(*i),
|
Self::Int(i) => Some(*i),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self) -> Option<String> {
|
fn as_string(&self) -> Option<String> {
|
||||||
match *self {
|
match self {
|
||||||
Self::String(ref s) => Some(s.clone()),
|
Self::String(s) => Some(s.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,100 +42,92 @@ impl ScalarValue for MyScalarValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_str(&self) -> Option<&str> {
|
fn as_str(&self) -> Option<&str> {
|
||||||
match *self {
|
match self {
|
||||||
Self::String(ref s) => Some(s.as_str()),
|
Self::String(s) => Some(s.as_str()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_float(&self) -> Option<f64> {
|
fn as_float(&self) -> Option<f64> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Int(ref i) => Some(f64::from(*i)),
|
Self::Int(i) => Some(f64::from(*i)),
|
||||||
Self::Float(ref f) => Some(*f),
|
Self::Float(f) => Some(*f),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_boolean(&self) -> Option<bool> {
|
fn as_boolean(&self) -> Option<bool> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Boolean(ref b) => Some(*b),
|
Self::Boolean(b) => Some(*b),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
impl<'de> Deserialize<'de> for MyScalarValue {
|
||||||
pub(crate) struct MyScalarValueVisitor;
|
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
|
||||||
|
struct Visitor;
|
||||||
|
|
||||||
impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
|
impl<'de> de::Visitor<'de> for Visitor {
|
||||||
type Value = MyScalarValue;
|
type Value = MyScalarValue;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
formatter.write_str("a valid input value")
|
f.write_str("a valid input value")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bool<E>(self, value: bool) -> Result<MyScalarValue, E> {
|
fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
|
||||||
Ok(MyScalarValue::Boolean(value))
|
Ok(MyScalarValue::Boolean(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_i32<E>(self, value: i32) -> Result<MyScalarValue, E>
|
fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
|
||||||
where
|
Ok(MyScalarValue::Int(n))
|
||||||
E: de::Error,
|
}
|
||||||
{
|
|
||||||
Ok(MyScalarValue::Int(value))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_i64<E>(self, value: i64) -> Result<MyScalarValue, E>
|
fn visit_i64<E: de::Error>(self, b: i64) -> Result<Self::Value, E> {
|
||||||
where
|
if b <= i64::from(i32::MAX) {
|
||||||
E: de::Error,
|
self.visit_i32(b.try_into().unwrap())
|
||||||
{
|
} else {
|
||||||
if value <= i64::from(i32::max_value()) {
|
Ok(MyScalarValue::Long(b))
|
||||||
self.visit_i32(value as i32)
|
}
|
||||||
} else {
|
}
|
||||||
Ok(MyScalarValue::Long(value))
|
|
||||||
|
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>
|
de.deserialize_any(Visitor)
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +160,7 @@ struct TestType;
|
||||||
#[graphql_object(scalar = MyScalarValue)]
|
#[graphql_object(scalar = MyScalarValue)]
|
||||||
impl TestType {
|
impl TestType {
|
||||||
fn long_field() -> i64 {
|
fn long_field() -> i64 {
|
||||||
i64::from(i32::max_value()) + 1
|
i64::from(i32::MAX) + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn long_with_arg(long_arg: i64) -> i64 {
|
fn long_with_arg(long_arg: i64) -> i64 {
|
||||||
|
|
|
@ -2,15 +2,17 @@
|
||||||
|
|
||||||
## Breaking Changes
|
## 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)
|
- Replaced `Visitor` associated type with `DeserializeOwned` requirement in `ScalarValue` trait. ([#985](https://github.com/graphql-rust/juniper/pull/985))
|
||||||
- `rename = "<policy>"` attribute's argument renamed to `rename_all = "<policy>"`. ([#971](https://github.com/graphql-rust/juniper/pull/971)
|
- Removed `Serialize` implementation from `#[derive(GraphQLScalarValue)]`macro, now should be provided explicitly. ([#985](https://github.com/graphql-rust/juniper/pull/985))
|
||||||
- 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)
|
- `#[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
|
## 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))
|
- 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))
|
- 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
|
## Fixes
|
||||||
|
|
||||||
|
|
|
@ -214,80 +214,53 @@ impl<'a> fmt::Display for Type<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> InputValue<S>
|
impl<S> InputValue<S> {
|
||||||
where
|
/// Construct a `null` value.
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
/// Construct a null value.
|
|
||||||
pub fn null() -> Self {
|
pub fn null() -> Self {
|
||||||
InputValue::Null
|
Self::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())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a scalar value
|
/// Construct a scalar value
|
||||||
pub fn scalar<T>(v: T) -> Self
|
pub fn scalar<T>(v: T) -> Self
|
||||||
where
|
where
|
||||||
T: Into<S>,
|
S: From<T>,
|
||||||
{
|
{
|
||||||
InputValue::Scalar(v.into())
|
Self::Scalar(v.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct an enum value.
|
/// Construct an enum value.
|
||||||
pub fn enum_value<T: AsRef<str>>(s: T) -> Self {
|
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.
|
/// Construct a variable value.
|
||||||
pub fn variable<T: AsRef<str>>(v: T) -> Self {
|
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
|
/// Convenience function to make each [`InputValue`] in the input vector
|
||||||
/// not contain any location information. Can be used from `ToInputValue`
|
/// not contain any location information. Can be used from [`ToInputValue`]
|
||||||
/// implementations, where no source code position information is available.
|
/// implementations, where no source code position information is available.
|
||||||
pub fn list(l: Vec<Self>) -> Self {
|
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.
|
/// Construct a located list.
|
||||||
pub fn parsed_list(l: Vec<Spanning<Self>>) -> Self {
|
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
|
/// Similarly to [`InputValue::list`] it makes each key and value in the
|
||||||
/// hash map not contain any location information.
|
/// given hash map not contain any location information.
|
||||||
pub fn object<K>(o: IndexMap<K, Self>) -> Self
|
pub fn object<K>(o: IndexMap<K, Self>) -> Self
|
||||||
where
|
where
|
||||||
K: AsRef<str> + Eq + Hash,
|
K: AsRef<str> + Eq + Hash,
|
||||||
{
|
{
|
||||||
InputValue::Object(
|
Self::Object(
|
||||||
o.into_iter()
|
o.into_iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
(
|
(
|
||||||
|
@ -301,19 +274,22 @@ where
|
||||||
|
|
||||||
/// Construct a located object.
|
/// Construct a located object.
|
||||||
pub fn parsed_object(o: Vec<(Spanning<String>, Spanning<Self>)>) -> Self {
|
pub fn parsed_object(o: Vec<(Spanning<String>, Spanning<Self>)>) -> Self {
|
||||||
InputValue::Object(o)
|
Self::Object(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve all variables to their values.
|
/// 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 {
|
match self {
|
||||||
InputValue::Variable(v) => vars.get(&v).map_or_else(InputValue::null, Clone::clone),
|
Self::Variable(v) => vars.get(&v).map_or_else(InputValue::null, Clone::clone),
|
||||||
InputValue::List(l) => InputValue::List(
|
Self::List(l) => Self::List(
|
||||||
l.into_iter()
|
l.into_iter()
|
||||||
.map(|s| s.map(|v| v.into_const(vars)))
|
.map(|s| s.map(|v| v.into_const(vars)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
InputValue::Object(o) => InputValue::Object(
|
Self::Object(o) => Self::Object(
|
||||||
o.into_iter()
|
o.into_iter()
|
||||||
.map(|(sk, sv)| (sk, sv.map(|v| v.into_const(vars))))
|
.map(|(sk, sv)| (sk, sv.map(|v| v.into_const(vars))))
|
||||||
.collect(),
|
.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>
|
pub fn convert<T>(&self) -> Option<T>
|
||||||
where
|
where
|
||||||
T: FromInputValue<S>,
|
T: FromInputValue<S>,
|
||||||
|
@ -330,43 +306,52 @@ where
|
||||||
<T as FromInputValue<S>>::from_input_value(self)
|
<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 {
|
pub fn is_null(&self) -> bool {
|
||||||
matches!(*self, InputValue::Null)
|
matches!(self, Self::Null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Does the value represent a variable?
|
/// Does the value represent a variable?
|
||||||
pub fn is_variable(&self) -> bool {
|
pub fn is_variable(&self) -> bool {
|
||||||
matches!(*self, InputValue::Variable(_))
|
matches!(self, Self::Variable(_))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying enum value, if present.
|
/// View the underlying enum value, if present.
|
||||||
pub fn as_enum_value(&self) -> Option<&str> {
|
pub fn as_enum_value(&self) -> Option<&str> {
|
||||||
match *self {
|
match self {
|
||||||
InputValue::Enum(ref e) => Some(e),
|
Self::Enum(e) => Some(e.as_str()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying int value, if present.
|
/// 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())
|
self.as_scalar_value().and_then(|s| s.as_int())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying float value, if present.
|
/// 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())
|
self.as_scalar_value().and_then(|s| s.as_float())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying string value, if present.
|
/// 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())
|
self.as_scalar_value().and_then(|s| s.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying scalar value, if present.
|
/// View the underlying scalar value, if present.
|
||||||
pub fn as_scalar(&self) -> Option<&S> {
|
pub fn as_scalar(&self) -> Option<&S> {
|
||||||
match *self {
|
match self {
|
||||||
InputValue::Scalar(ref s) => Some(s),
|
Self::Scalar(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -375,69 +360,71 @@ where
|
||||||
pub fn as_scalar_value<'a, T>(&'a self) -> Option<&'a T>
|
pub fn as_scalar_value<'a, T>(&'a self) -> Option<&'a T>
|
||||||
where
|
where
|
||||||
T: 'a,
|
T: 'a,
|
||||||
&'a S: Into<Option<&'a T>>,
|
Option<&'a T>: From<&'a S>,
|
||||||
{
|
{
|
||||||
self.as_scalar().and_then(Into::into)
|
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
|
/// This constructs a new [`IndexMap`] containing references to the keys
|
||||||
/// and values in `self`.
|
/// and values of `self`.
|
||||||
pub fn to_object_value(&self) -> Option<IndexMap<&str, &Self>> {
|
pub fn to_object_value(&self) -> Option<IndexMap<&str, &Self>> {
|
||||||
match *self {
|
match self {
|
||||||
InputValue::Object(ref o) => Some(
|
Self::Object(o) => Some(
|
||||||
o.iter()
|
o.iter()
|
||||||
.map(|&(ref sk, ref sv)| (sk.item.as_str(), &sv.item))
|
.map(|(sk, sv)| (sk.item.as_str(), &sv.item))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
_ => None,
|
_ => 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
|
/// This constructs a new [`Vec`] containing references to the values of
|
||||||
/// in `self`.
|
/// `self`.
|
||||||
pub fn to_list_value(&self) -> Option<Vec<&Self>> {
|
pub fn to_list_value(&self) -> Option<Vec<&Self>> {
|
||||||
match *self {
|
match self {
|
||||||
InputValue::List(ref l) => Some(l.iter().map(|s| &s.item).collect()),
|
Self::List(l) => Some(l.iter().map(|s| &s.item).collect()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recursively find all variables
|
/// Recursively finds all variables
|
||||||
pub fn referenced_variables(&self) -> Vec<&str> {
|
pub fn referenced_variables(&self) -> Vec<&str> {
|
||||||
match *self {
|
match self {
|
||||||
InputValue::Variable(ref name) => vec![name],
|
Self::Variable(name) => vec![name.as_str()],
|
||||||
InputValue::List(ref l) => l
|
Self::List(l) => l
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|v| v.item.referenced_variables())
|
.flat_map(|v| v.item.referenced_variables())
|
||||||
.collect(),
|
.collect(),
|
||||||
InputValue::Object(ref obj) => obj
|
Self::Object(o) => o
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|&(_, ref v)| v.item.referenced_variables())
|
.flat_map(|(_, v)| v.item.referenced_variables())
|
||||||
.collect(),
|
.collect(),
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compare equality with another `InputValue` ignoring any source position information.
|
/// Compares equality with another [`InputValue``] ignoring any source
|
||||||
pub fn unlocated_eq(&self, other: &Self) -> bool {
|
/// position information.
|
||||||
use crate::InputValue::*;
|
pub fn unlocated_eq(&self, other: &Self) -> bool
|
||||||
|
where
|
||||||
|
S: PartialEq,
|
||||||
|
{
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(&Null, &Null) => true,
|
(Self::Null, Self::Null) => true,
|
||||||
(&Scalar(ref s1), &Scalar(ref s2)) => s1 == s2,
|
(Self::Scalar(s1), Self::Scalar(s2)) => s1 == s2,
|
||||||
(&Enum(ref s1), &Enum(ref s2)) | (&Variable(ref s1), &Variable(ref s2)) => s1 == s2,
|
(Self::Enum(s1), Self::Enum(s2)) | (Self::Variable(s1), Self::Variable(s2)) => s1 == s2,
|
||||||
(&List(ref l1), &List(ref l2)) => l1
|
(Self::List(l1), Self::List(l2)) => l1
|
||||||
.iter()
|
.iter()
|
||||||
.zip(l2.iter())
|
.zip(l2.iter())
|
||||||
.all(|(v1, v2)| v1.item.unlocated_eq(&v2.item)),
|
.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.len() == o2.len()
|
||||||
&& o1.iter().all(|&(ref sk1, ref sv1)| {
|
&& o1.iter().all(|(sk1, sv1)| {
|
||||||
o2.iter().any(|&(ref sk2, ref sv2)| {
|
o2.iter().any(|(sk2, sv2)| {
|
||||||
sk1.item == sk2.item && sv1.item.unlocated_eq(&sv2.item)
|
sk1.item == sk2.item && sv1.item.unlocated_eq(&sv2.item)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -447,23 +434,20 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> fmt::Display for InputValue<S>
|
impl<S: ScalarValue> fmt::Display for InputValue<S> {
|
||||||
where
|
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match self {
|
||||||
InputValue::Null => write!(f, "null"),
|
Self::Null => write!(f, "null"),
|
||||||
InputValue::Scalar(ref s) => {
|
Self::Scalar(s) => {
|
||||||
if let Some(s) = s.as_str() {
|
if let Some(s) = s.as_str() {
|
||||||
write!(f, "\"{}\"", s)
|
write!(f, "\"{}\"", s)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", s)
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InputValue::Enum(ref v) => write!(f, "{}", v),
|
Self::Enum(v) => write!(f, "{}", v),
|
||||||
InputValue::Variable(ref v) => write!(f, "${}", v),
|
Self::Variable(v) => write!(f, "${}", v),
|
||||||
InputValue::List(ref v) => {
|
Self::List(v) => {
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
|
|
||||||
for (i, spanning) in v.iter().enumerate() {
|
for (i, spanning) in v.iter().enumerate() {
|
||||||
|
@ -475,7 +459,7 @@ where
|
||||||
|
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
}
|
}
|
||||||
InputValue::Object(ref o) => {
|
Self::Object(o) => {
|
||||||
write!(f, "{{")?;
|
write!(f, "{{")?;
|
||||||
|
|
||||||
for (i, &(ref k, ref v)) in o.iter().enumerate() {
|
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",
|
/// For GET, you will need to parse the query string and extract "query",
|
||||||
/// "operationName", and "variables" manually.
|
/// "operationName", and "variables" manually.
|
||||||
#[derive(Deserialize, Clone, Serialize, PartialEq, Debug)]
|
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
|
||||||
pub struct GraphQLRequest<S = DefaultScalarValue>
|
pub struct GraphQLRequest<S = DefaultScalarValue>
|
||||||
where
|
where
|
||||||
S: ScalarValue,
|
S: ScalarValue,
|
||||||
|
@ -37,7 +37,10 @@ where
|
||||||
pub operation_name: Option<String>,
|
pub operation_name: Option<String>,
|
||||||
|
|
||||||
/// Optional variables to execute the GraphQL operation with.
|
/// 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>>,
|
pub variables: Option<InputValue<S>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,34 +1,27 @@
|
||||||
use indexmap::IndexMap;
|
use std::{
|
||||||
use serde::{
|
convert::{TryFrom as _, TryInto as _},
|
||||||
de,
|
fmt,
|
||||||
ser::{self, SerializeMap},
|
marker::PhantomData,
|
||||||
Serialize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::fmt;
|
use indexmap::IndexMap;
|
||||||
|
use serde::{
|
||||||
|
de::{self, Deserializer, IntoDeserializer as _},
|
||||||
|
ser::{SerializeMap as _, Serializer},
|
||||||
|
serde_if_integer128, Deserialize, Serialize,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::InputValue,
|
ast::InputValue,
|
||||||
executor::ExecutionError,
|
executor::ExecutionError,
|
||||||
parser::{ParseError, SourcePosition, Spanning},
|
parser::{ParseError, SourcePosition, Spanning},
|
||||||
validation::RuleError,
|
validation::RuleError,
|
||||||
GraphQLError, Object, ScalarValue, Value,
|
DefaultScalarValue, GraphQLError, Object, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize)]
|
impl<T: Serialize> Serialize for ExecutionError<T> {
|
||||||
struct SerializeHelper {
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
message: &'static str,
|
let mut map = ser.serialize_map(Some(4))?;
|
||||||
}
|
|
||||||
|
|
||||||
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))?;
|
|
||||||
|
|
||||||
map.serialize_key("message")?;
|
map.serialize_key("message")?;
|
||||||
map.serialize_value(self.error().message())?;
|
map.serialize_value(self.error().message())?;
|
||||||
|
@ -49,274 +42,184 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::Serialize for GraphQLError<'a> {
|
impl<'a> Serialize for GraphQLError<'a> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
where
|
#[derive(Serialize)]
|
||||||
S: ser::Serializer,
|
struct Helper {
|
||||||
{
|
message: &'static str,
|
||||||
match *self {
|
}
|
||||||
GraphQLError::ParseError(ref err) => vec![err].serialize(serializer),
|
|
||||||
GraphQLError::ValidationError(ref errs) => errs.serialize(serializer),
|
match self {
|
||||||
GraphQLError::NoOperationProvided => [SerializeHelper {
|
Self::ParseError(e) => [e].serialize(ser),
|
||||||
|
Self::ValidationError(es) => es.serialize(ser),
|
||||||
|
Self::NoOperationProvided => [Helper {
|
||||||
message: "Must provide an operation",
|
message: "Must provide an operation",
|
||||||
}]
|
}]
|
||||||
.serialize(serializer),
|
.serialize(ser),
|
||||||
GraphQLError::MultipleOperationsProvided => [SerializeHelper {
|
Self::MultipleOperationsProvided => [Helper {
|
||||||
message: "Must provide operation name \
|
message: "Must provide operation name \
|
||||||
if query contains multiple operations",
|
if query contains multiple operations",
|
||||||
}]
|
}]
|
||||||
.serialize(serializer),
|
.serialize(ser),
|
||||||
GraphQLError::UnknownOperationName => [SerializeHelper {
|
Self::UnknownOperationName => [Helper {
|
||||||
message: "Unknown operation",
|
message: "Unknown operation",
|
||||||
}]
|
}]
|
||||||
.serialize(serializer),
|
.serialize(ser),
|
||||||
GraphQLError::IsSubscription => [SerializeHelper {
|
Self::IsSubscription => [Helper {
|
||||||
message: "Expected query, got subscription",
|
message: "Expected query, got subscription",
|
||||||
}]
|
}]
|
||||||
.serialize(serializer),
|
.serialize(ser),
|
||||||
GraphQLError::NotSubscription => [SerializeHelper {
|
Self::NotSubscription => [Helper {
|
||||||
message: "Expected subscription, got query",
|
message: "Expected subscription, got query",
|
||||||
}]
|
}]
|
||||||
.serialize(serializer),
|
.serialize(ser),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de, S> de::Deserialize<'de> for InputValue<S>
|
impl<'de, S: Deserialize<'de>> Deserialize<'de> for InputValue<S> {
|
||||||
where
|
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
|
||||||
S: ScalarValue,
|
struct Visitor<S: ?Sized>(PhantomData<S>);
|
||||||
{
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<InputValue<S>, D::Error>
|
|
||||||
where
|
|
||||||
D: de::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
struct InputValueVisitor<S: ScalarValue>(S::Visitor);
|
|
||||||
|
|
||||||
impl<S: ScalarValue> Default for InputValueVisitor<S> {
|
impl<'de, S: Deserialize<'de>> de::Visitor<'de> for Visitor<S> {
|
||||||
fn default() -> Self {
|
|
||||||
InputValueVisitor(S::Visitor::default())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'de, S> de::Visitor<'de> for InputValueVisitor<S>
|
|
||||||
where
|
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
type Value = InputValue<S>;
|
type Value = InputValue<S>;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
formatter.write_str("a valid input value")
|
f.write_str("a valid input value")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bool<E>(self, value: bool) -> Result<InputValue<S>, E>
|
fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(b.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_bool(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_i8<E>(self, value: i8) -> Result<InputValue<S>, E>
|
fn visit_i8<E: de::Error>(self, n: i8) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i8(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_i16<E>(self, value: i16) -> Result<InputValue<S>, E>
|
fn visit_i16<E: de::Error>(self, n: i16) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i16(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_i32<E>(self, value: i32) -> Result<InputValue<S>, E>
|
fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i32(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_i64<E>(self, value: i64) -> Result<InputValue<S>, E>
|
fn visit_i64<E: de::Error>(self, n: i64) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i64(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serde::serde_if_integer128! {
|
serde_if_integer128! {
|
||||||
fn visit_i128<E>(self, value: i128) -> Result<InputValue<S>, E>
|
fn visit_i128<E: de::Error>(self, n: i128) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_i128(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_u8<E>(self, value: u8) -> Result<InputValue<S>, E>
|
fn visit_u8<E: de::Error>(self, n: u8) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u8(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_u16<E>(self, value: u16) -> Result<InputValue<S>, E>
|
fn visit_u16<E: de::Error>(self, n: u16) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u16(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_u32<E>(self, value: u32) -> Result<InputValue<S>, E>
|
fn visit_u32<E: de::Error>(self, n: u32) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u32(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_u64<E>(self, value: u64) -> Result<InputValue<S>, E>
|
fn visit_u64<E: de::Error>(self, n: u64) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u64(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serde::serde_if_integer128! {
|
serde_if_integer128! {
|
||||||
fn visit_u128<E>(self, value: u128) -> Result<InputValue<S>, E>
|
fn visit_u128<E: de::Error>(self, n: u128) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_u128(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_f32<E>(self, value: f32) -> Result<InputValue<S>, E>
|
fn visit_f32<E: de::Error>(self, n: f32) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_f32(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_f64<E>(self, value: f64) -> Result<InputValue<S>, E>
|
fn visit_f64<E: de::Error>(self, n: f64) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(n.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_f64(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_char<E>(self, value: char) -> Result<InputValue<S>, E>
|
fn visit_char<E: de::Error>(self, c: char) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(c.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_char(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<InputValue<S>, E>
|
fn visit_str<E: de::Error>(self, s: &str) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(s.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_str(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_string<E>(self, value: String) -> Result<InputValue<S>, E>
|
fn visit_string<E: de::Error>(self, s: String) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(s.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_string(value).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bytes<E>(self, bytes: &[u8]) -> Result<InputValue<S>, E>
|
fn visit_bytes<E: de::Error>(self, b: &[u8]) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(b.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_bytes(bytes).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_byte_buf<E>(self, bytes: Vec<u8>) -> Result<InputValue<S>, E>
|
fn visit_byte_buf<E: de::Error>(self, b: Vec<u8>) -> Result<Self::Value, E> {
|
||||||
where
|
S::deserialize(b.into_deserializer()).map(InputValue::Scalar)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
self.0.visit_byte_buf(bytes).map(InputValue::Scalar)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_none<E>(self) -> Result<InputValue<S>, E>
|
fn visit_none<E: de::Error>(self) -> Result<Self::Value, E> {
|
||||||
where
|
Ok(InputValue::Null)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
Ok(InputValue::null())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_unit<E>(self) -> Result<InputValue<S>, E>
|
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
|
||||||
where
|
Ok(InputValue::Null)
|
||||||
E: de::Error,
|
|
||||||
{
|
|
||||||
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
|
where
|
||||||
V: de::SeqAccess<'de>,
|
V: de::SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut values = Vec::new();
|
let mut vals = Vec::new();
|
||||||
|
while let Some(v) = visitor.next_element()? {
|
||||||
while let Some(el) = visitor.next_element()? {
|
vals.push(v);
|
||||||
values.push(el);
|
|
||||||
}
|
}
|
||||||
|
Ok(InputValue::list(vals))
|
||||||
Ok(InputValue::list(values))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
where
|
||||||
V: de::MapAccess<'de>,
|
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),
|
visitor.size_hint().unwrap_or(0),
|
||||||
);
|
);
|
||||||
|
while let Some((key, val)) = visitor.next_entry()? {
|
||||||
while let Some((key, value)) = visitor.next_entry()? {
|
obj.insert(key, val);
|
||||||
object.insert(key, value);
|
|
||||||
}
|
}
|
||||||
|
Ok(InputValue::object(obj))
|
||||||
Ok(InputValue::object(object))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializer.deserialize_any(InputValueVisitor::default())
|
de.deserialize_any(Visitor(PhantomData))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ser::Serialize for InputValue<T>
|
impl<T: Serialize> Serialize for InputValue<T> {
|
||||||
where
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
T: ScalarValue,
|
match self {
|
||||||
{
|
Self::Null | Self::Variable(_) => ser.serialize_unit(),
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
Self::Scalar(s) => s.serialize(ser),
|
||||||
where
|
Self::Enum(e) => ser.serialize_str(e),
|
||||||
S: ser::Serializer,
|
Self::List(l) => l.iter().map(|x| &x.item).collect::<Vec<_>>().serialize(ser),
|
||||||
{
|
Self::Object(o) => o
|
||||||
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
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| x.item.clone())
|
.map(|(k, v)| (k.item.as_str(), &v.item))
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.serialize(serializer),
|
|
||||||
InputValue::Object(ref v) => v
|
|
||||||
.iter()
|
|
||||||
.map(|&(ref k, ref v)| (k.item.clone(), v.item.clone()))
|
|
||||||
.collect::<IndexMap<_, _>>()
|
.collect::<IndexMap<_, _>>()
|
||||||
.serialize(serializer),
|
.serialize(ser),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ser::Serialize for RuleError {
|
impl Serialize for RuleError {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
where
|
let mut map = ser.serialize_map(Some(2))?;
|
||||||
S: ser::Serializer,
|
|
||||||
{
|
|
||||||
let mut map = serializer.serialize_map(Some(2))?;
|
|
||||||
|
|
||||||
map.serialize_key("message")?;
|
map.serialize_key("message")?;
|
||||||
map.serialize_value(self.message())?;
|
map.serialize_value(self.message())?;
|
||||||
|
@ -328,12 +231,9 @@ impl ser::Serialize for RuleError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ser::Serialize for SourcePosition {
|
impl Serialize for SourcePosition {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
where
|
let mut map = ser.serialize_map(Some(2))?;
|
||||||
S: ser::Serializer,
|
|
||||||
{
|
|
||||||
let mut map = serializer.serialize_map(Some(2))?;
|
|
||||||
|
|
||||||
let line = self.line() + 1;
|
let line = self.line() + 1;
|
||||||
map.serialize_key("line")?;
|
map.serialize_key("line")?;
|
||||||
|
@ -347,23 +247,19 @@ impl ser::Serialize for SourcePosition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
|
impl<'a> Serialize for Spanning<ParseError<'a>> {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
where
|
let mut map = ser.serialize_map(Some(2))?;
|
||||||
S: ser::Serializer,
|
|
||||||
{
|
|
||||||
let mut map = serializer.serialize_map(Some(2))?;
|
|
||||||
|
|
||||||
let message = format!("{}", self.item);
|
let msg = format!("{}", self.item);
|
||||||
map.serialize_key("message")?;
|
map.serialize_key("message")?;
|
||||||
map.serialize_value(&message)?;
|
map.serialize_value(&msg)?;
|
||||||
|
|
||||||
let mut location = IndexMap::new();
|
let mut loc = IndexMap::new();
|
||||||
location.insert("line".to_owned(), self.start.line() + 1);
|
loc.insert("line".to_owned(), self.start.line() + 1);
|
||||||
location.insert("column".to_owned(), self.start.column() + 1);
|
loc.insert("column".to_owned(), self.start.column() + 1);
|
||||||
|
|
||||||
let locations = vec![location];
|
|
||||||
|
|
||||||
|
let locations = vec![loc];
|
||||||
map.serialize_key("locations")?;
|
map.serialize_key("locations")?;
|
||||||
map.serialize_value(&locations)?;
|
map.serialize_value(&locations)?;
|
||||||
|
|
||||||
|
@ -371,57 +267,107 @@ impl<'a> ser::Serialize for Spanning<ParseError<'a>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ser::Serialize for Object<T>
|
impl<T: Serialize> Serialize for Object<T> {
|
||||||
where
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
T: ser::Serialize,
|
let mut map = ser.serialize_map(Some(self.field_count()))?;
|
||||||
{
|
for (f, v) in self.iter() {
|
||||||
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() {
|
|
||||||
map.serialize_key(f)?;
|
map.serialize_key(f)?;
|
||||||
map.serialize_value(v)?;
|
map.serialize_value(v)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
map.end()
|
map.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> ser::Serialize for Value<T>
|
impl<T: Serialize> Serialize for Value<T> {
|
||||||
where
|
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||||
T: ser::Serialize,
|
match self {
|
||||||
{
|
Self::Null => ser.serialize_unit(),
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
Self::Scalar(s) => s.serialize(ser),
|
||||||
where
|
Self::List(l) => l.serialize(ser),
|
||||||
S: ser::Serializer,
|
Self::Object(o) => o.serialize(ser),
|
||||||
{
|
|
||||||
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<'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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{ExecutionError, GraphQLError};
|
use serde_json::{from_str, to_string};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::InputValue,
|
ast::InputValue,
|
||||||
value::{DefaultScalarValue, Object},
|
value::{DefaultScalarValue, Object},
|
||||||
FieldError, Value,
|
FieldError, Value,
|
||||||
};
|
};
|
||||||
use serde_json::{from_str, to_string};
|
|
||||||
|
use super::{ExecutionError, GraphQLError};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn int() {
|
fn int() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from_str::<InputValue<DefaultScalarValue>>("1235").unwrap(),
|
from_str::<InputValue<DefaultScalarValue>>("1235").unwrap(),
|
||||||
InputValue::scalar(1235)
|
InputValue::scalar(1235),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,12 +375,12 @@ mod tests {
|
||||||
fn float() {
|
fn float() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from_str::<InputValue<DefaultScalarValue>>("2.0").unwrap(),
|
from_str::<InputValue<DefaultScalarValue>>("2.0").unwrap(),
|
||||||
InputValue::scalar(2.0)
|
InputValue::scalar(2.0),
|
||||||
);
|
);
|
||||||
// large value without a decimal part is also float
|
// large value without a decimal part is also float
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
from_str::<InputValue<DefaultScalarValue>>("123567890123").unwrap(),
|
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() {
|
fn errors() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
to_string(&GraphQLError::UnknownOperationName).unwrap(),
|
to_string(&GraphQLError::UnknownOperationName).unwrap(),
|
||||||
r#"[{"message":"Unknown operation"}]"#
|
r#"[{"message":"Unknown operation"}]"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,7 +402,7 @@ mod tests {
|
||||||
Value::Object(obj),
|
Value::Object(obj),
|
||||||
)))
|
)))
|
||||||
.unwrap(),
|
.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
|
/// 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 {
|
Spanning {
|
||||||
item: f(self.item),
|
item: f(self.item),
|
||||||
start: self.start,
|
start: self.start,
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub enum Value<S = DefaultScalarValue> {
|
||||||
Object(Object<S>),
|
Object(Object<S>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: ScalarValue> Value<S> {
|
impl<S> Value<S> {
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
|
|
||||||
/// Construct a null value.
|
/// Construct a null value.
|
||||||
|
@ -43,30 +43,6 @@ impl<S: ScalarValue> Value<S> {
|
||||||
Self::Null
|
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.
|
/// Construct a list value.
|
||||||
pub fn list(l: Vec<Self>) -> Self {
|
pub fn list(l: Vec<Self>) -> Self {
|
||||||
Self::List(l)
|
Self::List(l)
|
||||||
|
@ -80,7 +56,7 @@ impl<S: ScalarValue> Value<S> {
|
||||||
/// Construct a scalar value
|
/// Construct a scalar value
|
||||||
pub fn scalar<T>(s: T) -> Self
|
pub fn scalar<T>(s: T) -> Self
|
||||||
where
|
where
|
||||||
T: Into<S>,
|
S: From<T>,
|
||||||
{
|
{
|
||||||
Self::Scalar(s.into())
|
Self::Scalar(s.into())
|
||||||
}
|
}
|
||||||
|
@ -95,26 +71,29 @@ impl<S: ScalarValue> Value<S> {
|
||||||
/// View the underlying scalar value if present
|
/// View the underlying scalar value if present
|
||||||
pub fn as_scalar_value<'a, T>(&'a self) -> Option<&'a T>
|
pub fn as_scalar_value<'a, T>(&'a self) -> Option<&'a T>
|
||||||
where
|
where
|
||||||
&'a S: Into<Option<&'a T>>,
|
Option<&'a T>: From<&'a S>,
|
||||||
{
|
{
|
||||||
match *self {
|
match self {
|
||||||
Self::Scalar(ref s) => s.into(),
|
Self::Scalar(s) => s.into(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying float value, if present.
|
/// 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 {
|
match self {
|
||||||
Self::Scalar(ref s) => s.as_float(),
|
Self::Scalar(s) => s.as_float(),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying object value, if present.
|
/// View the underlying object value, if present.
|
||||||
pub fn as_object_value(&self) -> Option<&Object<S>> {
|
pub fn as_object_value(&self) -> Option<&Object<S>> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Object(ref o) => Some(o),
|
Self::Object(o) => Some(o),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,24 +110,24 @@ impl<S: ScalarValue> Value<S> {
|
||||||
|
|
||||||
/// Mutable view into the underlying object value, if present.
|
/// Mutable view into the underlying object value, if present.
|
||||||
pub fn as_mut_object_value(&mut self) -> Option<&mut Object<S>> {
|
pub fn as_mut_object_value(&mut self) -> Option<&mut Object<S>> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Object(ref mut o) => Some(o),
|
Self::Object(o) => Some(o),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying list value, if present.
|
/// View the underlying list value, if present.
|
||||||
pub fn as_list_value(&self) -> Option<&Vec<Self>> {
|
pub fn as_list_value(&self) -> Option<&Vec<Self>> {
|
||||||
match *self {
|
match self {
|
||||||
Self::List(ref l) => Some(l),
|
Self::List(l) => Some(l),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// View the underlying scalar value, if present
|
/// View the underlying scalar value, if present
|
||||||
pub fn as_scalar(&self) -> Option<&S> {
|
pub fn as_scalar(&self) -> Option<&S> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Scalar(ref s) => Some(s),
|
Self::Scalar(s) => Some(s),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,11 +137,15 @@ impl<S: ScalarValue> Value<S> {
|
||||||
where
|
where
|
||||||
Option<&'a String>: From<&'a S>,
|
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.
|
/// 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>() {
|
if TypeId::of::<Into>() == TypeId::of::<S>() {
|
||||||
// SAFETY: This is safe, because we're transmuting the value into
|
// SAFETY: This is safe, because we're transmuting the value into
|
||||||
// itself, so no invariants may change and we're just
|
// 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> {
|
fn to_input_value(&self) -> InputValue<S> {
|
||||||
match *self {
|
match self {
|
||||||
Value::Null => InputValue::Null,
|
Self::Null => InputValue::Null,
|
||||||
Value::Scalar(ref s) => InputValue::Scalar(s.clone()),
|
Self::Scalar(s) => InputValue::Scalar(s.clone()),
|
||||||
Value::List(ref l) => InputValue::List(
|
Self::List(l) => InputValue::List(
|
||||||
l.iter()
|
l.iter()
|
||||||
.map(|x| Spanning::unlocated(x.to_input_value()))
|
.map(|x| Spanning::unlocated(x.to_input_value()))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
Value::Object(ref o) => InputValue::Object(
|
Self::Object(o) => InputValue::Object(
|
||||||
o.iter()
|
o.iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
(
|
(
|
||||||
|
@ -214,15 +197,15 @@ impl<S: ScalarValue> ToInputValue<S> for Value<S> {
|
||||||
impl<S: ScalarValue> Display for Value<S> {
|
impl<S: ScalarValue> Display for Value<S> {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Value::Null => write!(f, "null"),
|
Self::Null => write!(f, "null"),
|
||||||
Value::Scalar(s) => {
|
Self::Scalar(s) => {
|
||||||
if let Some(string) = s.as_string() {
|
if let Some(string) = s.as_string() {
|
||||||
write!(f, "\"{}\"", string)
|
write!(f, "\"{}\"", string)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "{}", s)
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::List(list) => {
|
Self::List(list) => {
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
for (idx, item) in list.iter().enumerate() {
|
for (idx, item) in list.iter().enumerate() {
|
||||||
write!(f, "{}", item)?;
|
write!(f, "{}", item)?;
|
||||||
|
@ -234,7 +217,7 @@ impl<S: ScalarValue> Display for Value<S> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Value::Object(obj) => {
|
Self::Object(obj) => {
|
||||||
write!(f, "{{")?;
|
write!(f, "{{")?;
|
||||||
for (idx, (key, value)) in obj.iter().enumerate() {
|
for (idx, (key, value)) in obj.iter().enumerate() {
|
||||||
write!(f, "\"{}\": {}", key, value)?;
|
write!(f, "\"{}\": {}", key, value)?;
|
||||||
|
@ -253,59 +236,43 @@ impl<S: ScalarValue> Display for Value<S> {
|
||||||
|
|
||||||
impl<S, T> From<Option<T>> for Value<S>
|
impl<S, T> From<Option<T>> for Value<S>
|
||||||
where
|
where
|
||||||
S: ScalarValue,
|
Self: From<T>,
|
||||||
Value<S>: From<T>,
|
|
||||||
{
|
{
|
||||||
fn from(v: Option<T>) -> Value<S> {
|
fn from(v: Option<T>) -> Self {
|
||||||
match v {
|
match v {
|
||||||
Some(v) => v.into(),
|
Some(v) => v.into(),
|
||||||
None => Value::null(),
|
None => Self::Null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, S> From<&'a str> for Value<S>
|
impl<'a, S: From<String>> From<&'a str> for Value<S> {
|
||||||
where
|
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
fn from(s: &'a str) -> Self {
|
fn from(s: &'a str) -> Self {
|
||||||
Value::scalar(s.to_owned())
|
Self::scalar(s.to_owned())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> From<String> for Value<S>
|
impl<S: From<String>> From<String> for Value<S> {
|
||||||
where
|
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
fn from(s: String) -> Self {
|
fn from(s: String) -> Self {
|
||||||
Value::scalar(s)
|
Self::scalar(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> From<i32> for Value<S>
|
impl<S: From<i32>> From<i32> for Value<S> {
|
||||||
where
|
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
fn from(i: i32) -> Self {
|
fn from(i: i32) -> Self {
|
||||||
Value::scalar(i)
|
Self::scalar(i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> From<f64> for Value<S>
|
impl<S: From<f64>> From<f64> for Value<S> {
|
||||||
where
|
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
fn from(f: f64) -> Self {
|
fn from(f: f64) -> Self {
|
||||||
Value::scalar(f)
|
Self::scalar(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> From<bool> for Value<S>
|
impl<S: From<bool>> From<bool> for Value<S> {
|
||||||
where
|
|
||||||
S: ScalarValue,
|
|
||||||
{
|
|
||||||
fn from(b: bool) -> Self {
|
fn from(b: bool) -> Self {
|
||||||
Value::scalar(b)
|
Self::scalar(b)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use serde::{de, ser::Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parser::{ParseError, ScalarToken},
|
parser::{ParseError, ScalarToken},
|
||||||
|
@ -24,9 +24,8 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
|
||||||
/// needs.
|
/// needs.
|
||||||
/// There is a custom derive (`#[derive(juniper::GraphQLScalarValue)]`) available that implements
|
/// There is a custom derive (`#[derive(juniper::GraphQLScalarValue)]`) available that implements
|
||||||
/// most of the required traits automatically for a enum representing a scalar value.
|
/// most of the required traits automatically for a enum representing a scalar value.
|
||||||
/// This derives needs a additional annotation of the form
|
/// However, [`Serialize`](trait@serde::Serialize) and [`Deserialize`](trait@serde::Deserialize)
|
||||||
/// `#[juniper(visitor = "VisitorType")]` to specify a type that implements
|
/// implementations are expected to be provided.
|
||||||
/// `serde::de::Visitor` and that is used to deserialize the value.
|
|
||||||
///
|
///
|
||||||
/// # Implementing a new scalar value representation
|
/// # Implementing a new scalar value representation
|
||||||
/// The preferred way to define a new scalar value representation is
|
/// The preferred way to define a new scalar value representation is
|
||||||
|
@ -34,12 +33,13 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
|
||||||
/// at the lowest level.
|
/// at the lowest level.
|
||||||
/// The following example introduces an new variant that is able to store 64 bit integers.
|
/// The following example introduces an new variant that is able to store 64 bit integers.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```rust
|
||||||
/// # use std::fmt;
|
/// # use std::{fmt, convert::TryInto as _};
|
||||||
/// # use serde::{de, Deserialize, Deserializer};
|
/// # use serde::{de, Deserialize, Deserializer, Serialize};
|
||||||
/// # use juniper::ScalarValue;
|
/// # use juniper::{GraphQLScalarValue, ScalarValue};
|
||||||
/// #
|
/// #
|
||||||
/// #[derive(Debug, Clone, PartialEq, juniper::GraphQLScalarValue)]
|
/// #[derive(Clone, Debug, GraphQLScalarValue, PartialEq, Serialize)]
|
||||||
|
/// #[serde(untagged)]
|
||||||
/// enum MyScalarValue {
|
/// enum MyScalarValue {
|
||||||
/// Int(i32),
|
/// Int(i32),
|
||||||
/// Long(i64),
|
/// Long(i64),
|
||||||
|
@ -49,18 +49,16 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl ScalarValue for MyScalarValue {
|
/// impl ScalarValue for MyScalarValue {
|
||||||
/// type Visitor = MyScalarValueVisitor;
|
/// fn as_int(&self) -> Option<i32> {
|
||||||
///
|
/// match self {
|
||||||
/// fn as_int(&self) -> Option<i32> {
|
/// Self::Int(i) => Some(*i),
|
||||||
/// match *self {
|
|
||||||
/// Self::Int(ref i) => Some(*i),
|
|
||||||
/// _ => None,
|
/// _ => None,
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn as_string(&self) -> Option<String> {
|
/// fn as_string(&self) -> Option<String> {
|
||||||
/// match *self {
|
/// match self {
|
||||||
/// Self::String(ref s) => Some(s.clone()),
|
/// Self::String(s) => Some(s.clone()),
|
||||||
/// _ => None,
|
/// _ => None,
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
|
@ -73,110 +71,99 @@ pub trait ParseScalarValue<S = DefaultScalarValue> {
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn as_str(&self) -> Option<&str> {
|
/// fn as_str(&self) -> Option<&str> {
|
||||||
/// match *self {
|
/// match self {
|
||||||
/// Self::String(ref s) => Some(s.as_str()),
|
/// Self::String(s) => Some(s.as_str()),
|
||||||
/// _ => None,
|
/// _ => None,
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn as_float(&self) -> Option<f64> {
|
/// fn as_float(&self) -> Option<f64> {
|
||||||
/// match *self {
|
/// match self {
|
||||||
/// Self::Int(ref i) => Some(*i as f64),
|
/// Self::Int(i) => Some(f64::from(*i)),
|
||||||
/// Self::Float(ref f) => Some(*f),
|
/// Self::Float(f) => Some(*f),
|
||||||
/// _ => None,
|
/// _ => None,
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn as_boolean(&self) -> Option<bool> {
|
/// fn as_boolean(&self) -> Option<bool> {
|
||||||
/// match *self {
|
/// match self {
|
||||||
/// Self::Boolean(ref b) => Some(*b),
|
/// Self::Boolean(b) => Some(*b),
|
||||||
/// _ => None,
|
/// _ => None,
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// #[derive(Default)]
|
/// impl<'de> Deserialize<'de> for MyScalarValue {
|
||||||
/// struct MyScalarValueVisitor;
|
/// fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
|
||||||
|
/// struct Visitor;
|
||||||
///
|
///
|
||||||
/// impl<'de> de::Visitor<'de> for MyScalarValueVisitor {
|
/// impl<'de> de::Visitor<'de> for Visitor {
|
||||||
/// type Value = MyScalarValue;
|
/// type Value = MyScalarValue;
|
||||||
///
|
///
|
||||||
/// fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
/// fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
/// formatter.write_str("a valid input value")
|
/// f.write_str("a valid input value")
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn visit_bool<E>(self, value: bool) -> Result<MyScalarValue, E> {
|
/// fn visit_bool<E: de::Error>(self, b: bool) -> Result<Self::Value, E> {
|
||||||
/// Ok(MyScalarValue::Boolean(value))
|
/// Ok(MyScalarValue::Boolean(b))
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// fn visit_i32<E>(self, value: i32) -> Result<MyScalarValue, E>
|
/// fn visit_i32<E: de::Error>(self, n: i32) -> Result<Self::Value, E> {
|
||||||
/// where
|
/// Ok(MyScalarValue::Int(n))
|
||||||
/// E: de::Error,
|
/// }
|
||||||
/// {
|
|
||||||
/// Ok(MyScalarValue::Int(value))
|
|
||||||
/// }
|
|
||||||
///
|
///
|
||||||
/// fn visit_i64<E>(self, value: i64) -> Result<MyScalarValue, E>
|
/// fn visit_i64<E: de::Error>(self, n: i64) -> Result<Self::Value, E> {
|
||||||
/// where
|
/// if n <= i64::from(i32::MAX) {
|
||||||
/// E: de::Error,
|
/// self.visit_i32(n.try_into().unwrap())
|
||||||
/// {
|
/// } else {
|
||||||
/// if value <= i32::max_value() as i64 {
|
/// Ok(MyScalarValue::Long(n))
|
||||||
/// self.visit_i32(value as i32)
|
/// }
|
||||||
/// } else {
|
/// }
|
||||||
/// Ok(MyScalarValue::Long(value))
|
///
|
||||||
|
/// 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>
|
/// de.deserialize_any(Visitor)
|
||||||
/// 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))
|
|
||||||
/// }
|
/// }
|
||||||
/// }
|
/// }
|
||||||
///
|
|
||||||
/// # fn main() {}
|
|
||||||
/// ```
|
/// ```
|
||||||
pub trait ScalarValue:
|
pub trait ScalarValue:
|
||||||
fmt::Debug
|
fmt::Debug
|
||||||
+ fmt::Display
|
+ fmt::Display
|
||||||
+ PartialEq
|
+ PartialEq
|
||||||
+ Clone
|
+ Clone
|
||||||
|
+ DeserializeOwned
|
||||||
+ Serialize
|
+ Serialize
|
||||||
+ From<String>
|
+ From<String>
|
||||||
+ From<bool>
|
+ From<bool>
|
||||||
|
@ -184,65 +171,68 @@ pub trait ScalarValue:
|
||||||
+ From<f64>
|
+ From<f64>
|
||||||
+ 'static
|
+ 'static
|
||||||
{
|
{
|
||||||
/// Serde visitor used to deserialize this scalar value
|
/// Checks whether this [`ScalarValue`] contains the value of the given
|
||||||
type Visitor: for<'de> de::Visitor<'de, Value = Self> + Default;
|
/// type.
|
||||||
|
|
||||||
/// Checks if the current value contains the a value of the current type
|
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # use juniper::{ScalarValue, DefaultScalarValue};
|
/// # use juniper::{ScalarValue, DefaultScalarValue};
|
||||||
///
|
/// #
|
||||||
/// let value = DefaultScalarValue::Int(42);
|
/// let value = DefaultScalarValue::Int(42);
|
||||||
///
|
///
|
||||||
/// assert_eq!(value.is_type::<i32>(), true);
|
/// assert_eq!(value.is_type::<i32>(), true);
|
||||||
/// assert_eq!(value.is_type::<f64>(), false);
|
/// assert_eq!(value.is_type::<f64>(), false);
|
||||||
///
|
|
||||||
/// ```
|
/// ```
|
||||||
|
#[must_use]
|
||||||
fn is_type<'a, T>(&'a self) -> bool
|
fn is_type<'a, T>(&'a self) -> bool
|
||||||
where
|
where
|
||||||
T: 'a,
|
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
|
/// This function is used for implementing [`GraphQLValue`] for [`i32`] for
|
||||||
/// scalar values. Implementations should convert all supported integer
|
/// all possible [`ScalarValue`]s. Implementations should convert all the
|
||||||
/// types with 32 bit or less to an integer if requested.
|
/// supported integer types with 32 bit or less to an integer, if requested.
|
||||||
|
#[must_use]
|
||||||
fn as_int(&self) -> Option<i32>;
|
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
|
/// This function is used for implementing [`GraphQLValue`] for [`String`]
|
||||||
/// scalar values
|
/// for all possible [`ScalarValue`]s.
|
||||||
|
#[must_use]
|
||||||
fn as_string(&self) -> Option<String>;
|
fn as_string(&self) -> Option<String>;
|
||||||
|
|
||||||
/// Converts this [`ScalarValue`] into a [`String`] value.
|
/// Converts this [`ScalarValue`] into a [`String`] value.
|
||||||
///
|
///
|
||||||
/// Same as [`ScalarValue::as_string`], but takes ownership, so allows to omit redundant
|
/// Same as [`ScalarValue::as_string()`], but takes ownership, so allows to
|
||||||
/// cloning.
|
/// omit redundant cloning.
|
||||||
|
#[must_use]
|
||||||
fn into_string(self) -> Option<String>;
|
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
|
/// This function is used for implementing [`GraphQLValue`] for [`str`] for
|
||||||
/// scalar values
|
/// all possible [`ScalarValue`]s.
|
||||||
|
#[must_use]
|
||||||
fn as_str(&self) -> Option<&str>;
|
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
|
/// This function is used for implementing [`GraphQLValue`] for [`f64`] for
|
||||||
/// scalar values. Implementations should convert all supported integer
|
/// all possible [`ScalarValue`]s. Implementations should convert all
|
||||||
/// types with 64 bit or less and all floating point values with 64 bit or
|
/// supported integer types with 64 bit or less and all floating point
|
||||||
/// less to a float if requested.
|
/// values with 64 bit or less to a float, if requested.
|
||||||
|
#[must_use]
|
||||||
fn as_float(&self) -> Option<f64>;
|
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
|
/// This function is used for implementing [`GraphQLValue`] for [`bool`] for
|
||||||
/// scalar values.
|
/// all possible [`ScalarValue`]s.
|
||||||
fn as_boolean(&self) -> Option<bool>;
|
fn as_boolean(&self) -> Option<bool>;
|
||||||
|
|
||||||
/// Converts this [`ScalarValue`] into another one.
|
/// 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.
|
/// These types closely follow the [GraphQL specification][0].
|
||||||
#[derive(Debug, PartialEq, Clone, GraphQLScalarValue)]
|
///
|
||||||
#[allow(missing_docs)]
|
/// [0]: https://spec.graphql.org/June2018
|
||||||
|
#[derive(Clone, Debug, GraphQLScalarValue, PartialEq, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
pub enum DefaultScalarValue {
|
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),
|
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),
|
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),
|
String(String),
|
||||||
|
|
||||||
|
/// [`Boolean` scalar][0] as a `true` or `false` value.
|
||||||
|
///
|
||||||
|
/// [0]: https://spec.graphql.org/June2018/#sec-Boolean
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScalarValue for DefaultScalarValue {
|
impl ScalarValue for DefaultScalarValue {
|
||||||
type Visitor = DefaultScalarValueVisitor;
|
|
||||||
|
|
||||||
fn as_int(&self) -> Option<i32> {
|
fn as_int(&self) -> Option<i32> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Int(ref i) => Some(*i),
|
Self::Int(i) => Some(*i),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_float(&self) -> Option<f64> {
|
fn as_float(&self) -> Option<f64> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Int(ref i) => Some(*i as f64),
|
Self::Int(i) => Some(f64::from(*i)),
|
||||||
Self::Float(ref f) => Some(*f),
|
Self::Float(f) => Some(*f),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_str(&self) -> Option<&str> {
|
fn as_str(&self) -> Option<&str> {
|
||||||
match *self {
|
match self {
|
||||||
Self::String(ref s) => Some(s.as_str()),
|
Self::String(s) => Some(s.as_str()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_string(&self) -> Option<String> {
|
fn as_string(&self) -> Option<String> {
|
||||||
match *self {
|
match self {
|
||||||
Self::String(ref s) => Some(s.clone()),
|
Self::String(s) => Some(s.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,8 +321,8 @@ impl ScalarValue for DefaultScalarValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_boolean(&self) -> Option<bool> {
|
fn as_boolean(&self) -> Option<bool> {
|
||||||
match *self {
|
match self {
|
||||||
Self::Boolean(ref b) => Some(*b),
|
Self::Boolean(b) => Some(*b),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,65 +342,3 @@ impl<'a> From<&'a str> for DefaultScalarValue {
|
||||||
Self::String(s.into())
|
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))
|
.map(|v| derive_from_variant(v, ident, &error))
|
||||||
.collect::<Result<Vec<_>, _>>()?;
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
|
|
||||||
let serialize = derive_serialize(data.variants.iter(), ident);
|
|
||||||
|
|
||||||
let display = derive_display(data.variants.iter(), ident);
|
let display = derive_display(data.variants.iter(), ident);
|
||||||
|
|
||||||
Ok(quote! {
|
Ok(quote! {
|
||||||
#(#froms)*
|
#(#froms)*
|
||||||
|
|
||||||
#serialize
|
|
||||||
#display
|
#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(
|
fn derive_from_variant(
|
||||||
variant: &Variant,
|
variant: &Variant,
|
||||||
ident: &Ident,
|
ident: &Ident,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use juniper::{ScalarValue, Variables};
|
use juniper::Variables;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::utils::default_for_null;
|
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
|
/// The payload for a client's "start" message. This triggers execution of a query, mutation, or
|
||||||
/// subscription.
|
/// subscription.
|
||||||
#[derive(Debug, Deserialize, PartialEq)]
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
#[serde(bound(deserialize = "S: ScalarValue"))]
|
#[serde(bound(deserialize = "S: Deserialize<'de>"))]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct StartPayload<S: ScalarValue> {
|
pub struct StartPayload<S> {
|
||||||
/// The document body.
|
/// The document body.
|
||||||
pub query: String,
|
pub query: String,
|
||||||
|
|
||||||
|
@ -22,10 +22,10 @@ pub struct StartPayload<S: ScalarValue> {
|
||||||
|
|
||||||
/// ClientMessage defines the message types that clients can send.
|
/// ClientMessage defines the message types that clients can send.
|
||||||
#[derive(Debug, Deserialize, PartialEq)]
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
#[serde(bound(deserialize = "S: ScalarValue"))]
|
#[serde(bound(deserialize = "S: Deserialize<'de>"))]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
pub enum ClientMessage<S: ScalarValue> {
|
pub enum ClientMessage<S> {
|
||||||
/// ConnectionInit is sent by the client upon connecting.
|
/// ConnectionInit is sent by the client upon connecting.
|
||||||
ConnectionInit {
|
ConnectionInit {
|
||||||
/// Optional parameters of any type sent from the client. These are often used for
|
/// 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 std::{any::Any, fmt, marker::PhantomPinned, mem};
|
||||||
|
|
||||||
use juniper::{ExecutionError, GraphQLError, ScalarValue, Value};
|
use juniper::{ExecutionError, GraphQLError, Value};
|
||||||
use serde::{Serialize, Serializer};
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
/// The payload for errors that are not associated with a GraphQL operation.
|
/// 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
|
/// 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.
|
/// once. For subscriptions, this is sent for every event in the event stream.
|
||||||
#[derive(Debug, Serialize, PartialEq)]
|
#[derive(Debug, Serialize, PartialEq)]
|
||||||
#[serde(bound(serialize = "S: ScalarValue"))]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct DataPayload<S> {
|
pub struct DataPayload<S> {
|
||||||
/// The result data.
|
/// The result data.
|
||||||
|
@ -90,10 +89,9 @@ impl From<GraphQLError<'static>> for ErrorPayload {
|
||||||
|
|
||||||
/// ServerMessage defines the message types that servers can send.
|
/// ServerMessage defines the message types that servers can send.
|
||||||
#[derive(Debug, Serialize, PartialEq)]
|
#[derive(Debug, Serialize, PartialEq)]
|
||||||
#[serde(bound(serialize = "S: ScalarValue"))]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
#[serde(tag = "type")]
|
#[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
|
/// ConnectionError is used for errors that are not associated with a GraphQL operation. For
|
||||||
/// example, this will be used when:
|
/// example, this will be used when:
|
||||||
///
|
///
|
||||||
|
|
|
@ -185,15 +185,12 @@ fn parse_variable_param<S>(params: Option<Vec<String>>) -> IronResult<Option<Inp
|
||||||
where
|
where
|
||||||
S: ScalarValue,
|
S: ScalarValue,
|
||||||
{
|
{
|
||||||
if let Some(values) = params {
|
params
|
||||||
Ok(
|
.map(|vals| {
|
||||||
serde_json::from_str::<InputValue<S>>(get_single_value(values)?.as_ref())
|
serde_json::from_str::<InputValue<S>>(get_single_value(vals)?.as_ref())
|
||||||
.map(Some)
|
.map_err(|e| GraphQLIronError::Serde(e).into())
|
||||||
.map_err(GraphQLIronError::Serde)?,
|
})
|
||||||
)
|
.transpose()
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, CtxFactory, Query, Mutation, Subscription, CtxT, S>
|
impl<'a, CtxFactory, Query, Mutation, Subscription, CtxT, S>
|
||||||
|
|
|
@ -40,13 +40,14 @@ Check the LICENSE file for details.
|
||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
#![doc(html_root_url = "https://docs.rs/juniper_warp/0.2.0")]
|
#![doc(html_root_url = "https://docs.rs/juniper_warp/0.2.0")]
|
||||||
|
|
||||||
|
use std::{collections::HashMap, str, sync::Arc};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use futures::{FutureExt as _, TryFutureExt};
|
use futures::{FutureExt as _, TryFutureExt};
|
||||||
use juniper::{
|
use juniper::{
|
||||||
http::{GraphQLBatchRequest, GraphQLRequest},
|
http::{GraphQLBatchRequest, GraphQLRequest},
|
||||||
ScalarValue,
|
ScalarValue,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, str, sync::Arc};
|
|
||||||
use tokio::task;
|
use tokio::task;
|
||||||
use warp::{body, filters::BoxedFilter, http, hyper::body::Bytes, query, Filter};
|
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
|
/// [1]: https://github.com/apollographql/subscriptions-transport-ws/blob/master/PROTOCOL.md
|
||||||
#[cfg(feature = "subscriptions")]
|
#[cfg(feature = "subscriptions")]
|
||||||
pub mod subscriptions {
|
pub mod subscriptions {
|
||||||
|
use std::{convert::Infallible, fmt, sync::Arc};
|
||||||
|
|
||||||
use juniper::{
|
use juniper::{
|
||||||
futures::{
|
futures::{
|
||||||
future::{self, Either},
|
future::{self, Either},
|
||||||
|
@ -390,7 +393,6 @@ pub mod subscriptions {
|
||||||
GraphQLSubscriptionType, GraphQLTypeAsync, RootNode, ScalarValue,
|
GraphQLSubscriptionType, GraphQLTypeAsync, RootNode, ScalarValue,
|
||||||
};
|
};
|
||||||
use juniper_graphql_ws::{ArcSchema, ClientMessage, Connection, Init};
|
use juniper_graphql_ws::{ArcSchema, ClientMessage, Connection, Init};
|
||||||
use std::{convert::Infallible, fmt, sync::Arc};
|
|
||||||
|
|
||||||
struct Message(warp::ws::Message);
|
struct Message(warp::ws::Message);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue