From 602f6a656fce4e99f718a12a71d8ddc824f43ee4 Mon Sep 17 00:00:00 2001 From: sunli Date: Wed, 4 Mar 2020 10:38:07 +0800 Subject: [PATCH] Support default values --- README.md | 7 +-- async-graphql-derive/src/args.rs | 12 +++++ async-graphql-derive/src/enum.rs | 4 +- async-graphql-derive/src/input_object.rs | 55 +++++++++++++++---- async-graphql-derive/src/object.rs | 18 +++++-- async-graphql-derive/src/utils.rs | 69 ++++++++++++++++++++---- examples/helloworld.rs | 34 +++++++----- src/base.rs | 12 ++--- src/context.rs | 42 +++++++++++---- src/model/field.rs | 15 +++++- src/model/type.rs | 4 +- src/scalars/bool.rs | 8 +-- src/scalars/datetime.rs | 4 +- src/scalars/floats.rs | 6 +-- src/scalars/id.rs | 8 +-- src/scalars/integers.rs | 4 +- src/scalars/string.rs | 8 +-- src/scalars/uuid.rs | 4 +- src/types/enum.rs | 4 +- src/types/list.rs | 4 +- src/types/optional.rs | 4 +- 21 files changed, 235 insertions(+), 91 deletions(-) diff --git a/README.md b/README.md index e81aafaa..52d546f9 100644 --- a/README.md +++ b/README.md @@ -53,23 +53,24 @@ - [X] Non-Null - [ ] Object - [ ] Generic Types - - [X] Lifetime cycle + - [X] Lifetime cycle - [X] Enum - [X] InputObject - - [ ] Field default value + - [X] Field default value - [X] Deprecated flag - [ ] Interface - [ ] Union - [ ] Query - [X] Fields - [X] Arguments - - [ ] Default value + - [X] Default value - [X] Deprecated flag - [X] Alias - [ ] Fragments - [ ] Inline fragments - [X] Operation name - [X] Variables + - [X] Default value - [X] Parse value - [ ] Check type - [ ] Directives diff --git a/async-graphql-derive/src/args.rs b/async-graphql-derive/src/args.rs index 4f121918..48a6747f 100644 --- a/async-graphql-derive/src/args.rs +++ b/async-graphql-derive/src/args.rs @@ -176,6 +176,12 @@ impl Field { } else if nv.path.is_ident("default") { if let syn::Lit::Str(lit) = &nv.lit { match parse_value(&lit.value()) { + Ok(Value::Variable(_)) => { + return Err(Error::new_spanned( + &nv.lit, + "The default cannot be a variable", + )) + } Ok(value) => default = Some(value), Err(err) => { return Err(Error::new_spanned( @@ -406,6 +412,12 @@ impl InputField { } else if nv.path.is_ident("default") { if let syn::Lit::Str(lit) = nv.lit { match parse_value(&lit.value()) { + Ok(Value::Variable(_)) => { + return Err(Error::new_spanned( + &lit, + "The default cannot be a variable", + )) + } Ok(value) => default = Some(value), Err(err) => { return Err(Error::new_spanned( diff --git a/async-graphql-derive/src/enum.rs b/async-graphql-derive/src/enum.rs index 18394a35..600455d9 100644 --- a/async-graphql-derive/src/enum.rs +++ b/async-graphql-derive/src/enum.rs @@ -98,11 +98,11 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result Option { + fn parse(value: &#crate_name::Value) -> Option { #crate_name::GQLEnum::parse_enum(value) } - fn parse_from_json(value: #crate_name::serde_json::Value) -> Option { + fn parse_from_json(value: &#crate_name::serde_json::Value) -> Option { #crate_name::GQLEnum::parse_json_enum(value) } } diff --git a/async-graphql-derive/src/input_object.rs b/async-graphql-derive/src/input_object.rs index 7c7fcebe..c64f45d1 100644 --- a/async-graphql-derive/src/input_object.rs +++ b/async-graphql-derive/src/input_object.rs @@ -1,5 +1,5 @@ use crate::args; -use crate::utils::get_crate_name; +use crate::utils::{build_value_repr, get_crate_name}; use proc_macro::TokenStream; use quote::quote; use syn::{Data, DeriveInput, Error, Result}; @@ -63,12 +63,45 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result< quote! {Some(#s)} }) .unwrap_or_else(|| quote! {None}); - get_fields.push(quote! { - let #ident:#ty = #crate_name::GQLInputValue::parse(obj.remove(#name).unwrap_or(#crate_name::Value::Null))?; - }); - get_json_fields.push(quote! { - let #ident:#ty = #crate_name::GQLInputValue::parse_from_json(obj.remove(#name).unwrap_or(#crate_name::serde_json::Value::Null))?; - }); + + if let Some(default) = &field_args.default { + let default_repr = build_value_repr(&crate_name, default); + get_fields.push(quote! { + let #ident:#ty = { + match obj.get(#name) { + Some(value) => #crate_name::GQLInputValue::parse(value)?, + None => { + let default = #default_repr; + #crate_name::GQLInputValue::parse(&value)? + } + } + }; + }); + } else { + get_fields.push(quote! { + let #ident:#ty = #crate_name::GQLInputValue::parse(obj.get(#name).unwrap_or(&#crate_name::Value::Null))?; + }); + } + + if let Some(default) = &field_args.default { + let default_repr = build_value_repr(&crate_name, default); + get_json_fields.push(quote! { + let #ident:#ty = match obj.get(#name) { + None => { + let default_value = #default_repr; + #crate_name::GQLInputValue::parse(&default_value)? + } + Some(value) => { + #crate_name::GQLInputValue::parse_from_json(&value)? + } + }; + }); + } else { + get_json_fields.push(quote! { + let #ident:#ty = #crate_name::GQLInputValue::parse_from_json(&obj.get(#name).unwrap_or(&#crate_name::serde_json::Value::Null))?; + }); + } + fields.push(ident); schema_fields.push(quote! { #crate_name::registry::InputValue { @@ -98,10 +131,10 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result< } impl #crate_name::GQLInputValue for #ident { - fn parse(value: #crate_name::Value) -> Option { + fn parse(value: &#crate_name::Value) -> Option { use #crate_name::GQLType; - if let #crate_name::Value::Object(mut obj) = value { + if let #crate_name::Value::Object(obj) = value { #(#get_fields)* Some(Self { #(#fields),* }) } else { @@ -109,9 +142,9 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result< } } - fn parse_from_json(value: #crate_name::serde_json::Value) -> Option { + fn parse_from_json(value: &#crate_name::serde_json::Value) -> Option { use #crate_name::GQLType; - if let #crate_name::serde_json::Value::Object(mut obj) = value { + if let #crate_name::serde_json::Value::Object(obj) = value { #(#get_json_fields)* Some(Self { #(#fields),* }) } else { diff --git a/async-graphql-derive/src/object.rs b/async-graphql-derive/src/object.rs index f165a70d..92f8fc0d 100644 --- a/async-graphql-derive/src/object.rs +++ b/async-graphql-derive/src/object.rs @@ -1,5 +1,5 @@ use crate::args; -use crate::utils::get_crate_name; +use crate::utils::{build_value_repr, get_crate_name}; use inflector::Inflector; use proc_macro::TokenStream; use proc_macro2::Span; @@ -59,7 +59,7 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result Result { + let repr = build_value_repr(&crate_name, &default); + quote! {Some(|| #repr)} + } + None => quote! { None }, + }; get_params.push(quote! { - let #snake_case_name: #ty = ctx_field.param_value(#name_str)?; + let #snake_case_name: #ty = ctx_field.param_value(#name_str, #default)?; }); + use_params.push(quote! { #snake_case_name }); + schema_args.push(quote! { #crate_name::registry::InputValue { name: #name_str, description: #desc, ty: <#ty as #crate_name::GQLType>::create_type_info(registry), - default_value: #default, + default_value: #schema_default, } }); } diff --git a/async-graphql-derive/src/utils.rs b/async-graphql-derive/src/utils.rs index 1922e481..d3c4c5cb 100644 --- a/async-graphql-derive/src/utils.rs +++ b/async-graphql-derive/src/utils.rs @@ -1,3 +1,5 @@ +use graphql_parser::parse_query; +use graphql_parser::query::{Definition, OperationDefinition, ParseError, Query, Value}; use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::Ident; @@ -12,18 +14,13 @@ pub fn get_crate_name(internal: bool) -> TokenStream { } } -pub fn parse_value( - s: &str, -) -> Result { - let mut doc = - graphql_parser::query::parse_query(&format!("query ($a:Int!={}) {{ dummy }}", s))?; +pub fn parse_value(s: &str) -> Result { + let mut doc = parse_query(&format!("query ($a:Int!={}) {{ dummy }}", s))?; let definition = doc.definitions.remove(0); - if let graphql_parser::query::Definition::Operation( - graphql_parser::query::OperationDefinition::Query(graphql_parser::query::Query { - mut variable_definitions, - .. - }), - ) = definition + if let Definition::Operation(OperationDefinition::Query(Query { + mut variable_definitions, + .. + })) = definition { let var = variable_definitions.remove(0); Ok(var.default_value.unwrap()) @@ -31,3 +28,53 @@ pub fn parse_value( unreachable!() } } + +pub fn build_value_repr(crate_name: &TokenStream, value: &Value) -> TokenStream { + match value { + Value::Variable(_) => unreachable!(), + Value::Int(n) => { + let n = n.as_i64().unwrap(); + quote! { #crate_name::Value::Int((#n as i32).into()) } + } + Value::Float(n) => { + quote! { #crate_name::Value::Float(#n) } + } + Value::String(s) => { + quote! { #crate_name::Value::String(#s.to_string()) } + } + Value::Boolean(n) => { + quote! { #crate_name::Value::Boolean(#n) } + } + Value::Null => { + quote! { #crate_name::Value::Null } + } + Value::Enum(n) => { + quote! { #crate_name::Value::Enum(#n.to_string()) } + } + Value::List(ls) => { + let members = ls + .iter() + .map(|v| build_value_repr(crate_name, v)) + .collect::>(); + quote! { #crate_name::Value::List(vec![#(#members),*]) } + } + Value::Object(obj) => { + let members = obj + .iter() + .map(|(n, v)| { + let value = build_value_repr(crate_name, v); + quote! { + obj.insert(#n.to_string(), #value); + } + }) + .collect::>(); + quote! { + { + let mut obj = std::collections::BTreeMap::new(); + #(#members)* + obj + } + } + } + } +} diff --git a/examples/helloworld.rs b/examples/helloworld.rs index e4546a7c..c1c7685f 100644 --- a/examples/helloworld.rs +++ b/examples/helloworld.rs @@ -10,9 +10,15 @@ struct MyInputObj { a: i32, b: i32, } + #[async_graphql::Object( field(name = "a", type = "i32"), - field(owned, name = "b", type = "i32"), + field( + owned, + name = "b", + type = "i32", + arg(name = "v", type = "i32", default = "123") + ), field(owned, name = "c", type = "Option") )] struct MyObj { @@ -25,8 +31,8 @@ impl MyObjFields for MyObj { Ok(&self.value) } - async fn b(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result { - Ok(999) + async fn b(&self, ctx: &async_graphql::Context<'_>, v: i32) -> async_graphql::Result { + Ok(v) } async fn c(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result> { @@ -37,14 +43,16 @@ impl MyObjFields for MyObj { #[async_std::main] async fn main() { let schema = async_graphql::Schema::::new(); - let res = schema - .query( - MyObj { value: 100 }, - async_graphql::GQLEmptyMutation, - "{ a b c __schema { types { kind name description } } }", - ) - .execute() - .await - .unwrap(); - serde_json::to_writer_pretty(std::io::stdout(), &res).unwrap(); + for _ in 0..1000 { + let res = schema + .query( + MyObj { value: 100 }, + async_graphql::GQLEmptyMutation, + "{ a b c __schema { types { kind name description fields(includeDeprecated: false) { name args { name defaultValue } } } } }", + ) + .execute() + .await + .unwrap(); + } + // serde_json::to_writer_pretty(std::io::stdout(), &res).unwrap(); } diff --git a/src/base.rs b/src/base.rs index 8b215ccf..302ba204 100644 --- a/src/base.rs +++ b/src/base.rs @@ -15,8 +15,8 @@ pub trait GQLType { #[doc(hidden)] pub trait GQLInputValue: GQLType + Sized { - fn parse(value: Value) -> Option; - fn parse_from_json(value: serde_json::Value) -> Option; + fn parse(value: &Value) -> Option; + fn parse_from_json(value: &serde_json::Value) -> Option; } #[doc(hidden)] @@ -36,8 +36,8 @@ pub trait Scalar: Sized + Send { fn description() -> Option<&'static str> { None } - fn parse(value: Value) -> Option; - fn parse_from_json(value: serde_json::Value) -> Option; + fn parse(value: &Value) -> Option; + fn parse_from_json(value: &serde_json::Value) -> Option; fn to_json(&self) -> Result; } @@ -55,11 +55,11 @@ impl GQLType for T { } impl GQLInputValue for T { - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { T::parse(value) } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { T::parse_from_json(value) } } diff --git a/src/context.rs b/src/context.rs index 41daabc5..3daeae9d 100644 --- a/src/context.rs +++ b/src/context.rs @@ -77,7 +77,11 @@ impl<'a, T> ContextBase<'a, T> { impl<'a> ContextBase<'a, &'a Field> { #[doc(hidden)] - pub fn param_value(&self, name: &str) -> Result { + pub fn param_value Value>( + &self, + name: &str, + default: Option, + ) -> Result { let value = self .arguments .iter() @@ -88,26 +92,42 @@ impl<'a> ContextBase<'a, &'a Field> { if let Some(Value::Variable(var_name)) = &value { if let Some(vars) = &self.variables { if let Some(var_value) = vars.get(&*var_name).cloned() { - let res = - GQLInputValue::parse_from_json(var_value.clone()).ok_or_else(|| { - QueryError::ExpectedJsonType { - expect: T::qualified_type_name(), - actual: var_value, - } - .with_position(self.item.position) - })?; + let res = GQLInputValue::parse_from_json(&var_value).ok_or_else(|| { + QueryError::ExpectedJsonType { + expect: T::qualified_type_name(), + actual: var_value, + } + .with_position(self.item.position) + })?; return Ok(res); } } + if let Some(default) = default { + let value = default(); + let res = GQLInputValue::parse(&value).ok_or_else(|| { + QueryError::ExpectedType { + expect: T::qualified_type_name(), + actual: value, + } + .with_position(self.item.position) + })?; + return Ok(res); + } + return Err(QueryError::VarNotDefined { var_name: var_name.clone(), } .into()); }; - let value = value.unwrap_or(Value::Null); - let res = GQLInputValue::parse(value.clone()).ok_or_else(|| { + let value = if let (Some(default), None) = (default, &value) { + default() + } else { + value.unwrap_or(Value::Null) + }; + + let res = GQLInputValue::parse(&value).ok_or_else(|| { QueryError::ExpectedType { expect: T::qualified_type_name(), actual: value, diff --git a/src/model/field.rs b/src/model/field.rs index d809122a..48581eaf 100644 --- a/src/model/field.rs +++ b/src/model/field.rs @@ -1,4 +1,4 @@ -use crate::model::__Type; +use crate::model::{__InputValue, __Type}; use crate::{registry, Context, Result}; use async_graphql_derive::Object; @@ -7,6 +7,7 @@ use async_graphql_derive::Object; desc = "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", field(name = "name", type = "String", owned), field(name = "description", type = "Option", owned), + field(name = "args", type = "Vec<__InputValue>", owned), field(name = "type", resolver = "ty", type = "__Type", owned), field(name = "isDeprecated", type = "bool", owned), field(name = "deprecationReason", type = "Option", owned) @@ -27,6 +28,18 @@ impl<'a> __FieldFields for __Field<'a> { Ok(self.field.description.map(|s| s.to_string())) } + async fn args<'b>(&'b self, _: &Context<'_>) -> Result>> { + Ok(self + .field + .args + .iter() + .map(|input_value| __InputValue { + registry: self.registry, + input_value, + }) + .collect()) + } + async fn ty<'b>(&'b self, _: &Context<'_>) -> Result<__Type<'b>> { Ok(__Type { registry: self.registry, diff --git a/src/model/type.rs b/src/model/type.rs index f353515e..9ed1e659 100644 --- a/src/model/type.rs +++ b/src/model/type.rs @@ -17,7 +17,7 @@ Depending on the kind of a type, certain fields describe information about that name = "fields", type = "Option>", owned, - arg(name = "includeDeprecated", type = "bool") + arg(name = "includeDeprecated", type = "bool", default="false") ), field(name = "interfaces", type = "Option>", owned), field(name = "possibleTypes", type = "Option>", owned), @@ -25,7 +25,7 @@ Depending on the kind of a type, certain fields describe information about that name = "enumValues", type = "Option>", owned, - arg(name = "includeDeprecated", type = "bool") + arg(name = "includeDeprecated", type = "bool", default="false") ), field(name = "inputFields", type = "Option>", owned), field(name = "ofType", type = "Option<__Type>", owned) diff --git a/src/scalars/bool.rs b/src/scalars/bool.rs index 2671f465..cbf1e9b7 100644 --- a/src/scalars/bool.rs +++ b/src/scalars/bool.rs @@ -9,16 +9,16 @@ impl Scalar for bool { Some("The `Boolean` scalar type represents `true` or `false`.") } - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { - Value::Boolean(n) => Some(n), + Value::Boolean(n) => Some(*n), _ => None, } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { - serde_json::Value::Bool(n) => Some(n), + serde_json::Value::Bool(n) => Some(*n), _ => None, } } diff --git a/src/scalars/datetime.rs b/src/scalars/datetime.rs index b2279a65..b7784f73 100644 --- a/src/scalars/datetime.rs +++ b/src/scalars/datetime.rs @@ -6,14 +6,14 @@ impl Scalar for DateTime { "DateTime" } - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { Value::String(s) => Some(Utc.datetime_from_str(&s, "%+").ok()?), _ => None, } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { serde_json::Value::String(s) => Some(Utc.datetime_from_str(&s, "%+").ok()?), _ => None, diff --git a/src/scalars/floats.rs b/src/scalars/floats.rs index 86e2cf01..5752f3f8 100644 --- a/src/scalars/floats.rs +++ b/src/scalars/floats.rs @@ -12,15 +12,15 @@ macro_rules! impl_float_scalars { Some("The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).") } - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { Value::Int(n) => Some(n.as_i64().unwrap() as Self), - Value::Float(n) => Some(n as Self), + Value::Float(n) => Some(*n as Self), _ => None } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { serde_json::Value::Number(n) => Some(n.as_f64().unwrap() as Self), _ => None diff --git a/src/scalars/id.rs b/src/scalars/id.rs index f7766b14..0b8b3caf 100644 --- a/src/scalars/id.rs +++ b/src/scalars/id.rs @@ -23,18 +23,18 @@ impl Scalar for ID { "ID" } - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { Value::Int(n) => Some(ID(n.as_i64().unwrap().to_string())), - Value::String(s) => Some(ID(s)), + Value::String(s) => Some(ID(s.clone())), _ => None, } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { serde_json::Value::Number(n) if n.is_i64() => Some(ID(n.as_i64().unwrap().to_string())), - serde_json::Value::String(s) => Some(ID(s)), + serde_json::Value::String(s) => Some(ID(s.clone())), _ => None, } } diff --git a/src/scalars/integers.rs b/src/scalars/integers.rs index 681fea80..def161e7 100644 --- a/src/scalars/integers.rs +++ b/src/scalars/integers.rs @@ -12,14 +12,14 @@ macro_rules! impl_integer_scalars { Some("The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.") } - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { Value::Int(n) => Some(n.as_i64().unwrap() as Self), _ => None } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { serde_json::Value::Number(n) if n.is_i64() => Some(n.as_i64().unwrap() as Self), serde_json::Value::Number(n) => Some(n.as_f64().unwrap() as Self), diff --git a/src/scalars/string.rs b/src/scalars/string.rs index 919ef462..5e2f51d1 100644 --- a/src/scalars/string.rs +++ b/src/scalars/string.rs @@ -13,16 +13,16 @@ impl Scalar for String { Some(STRING_DESC) } - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { - Value::String(s) => Some(s), + Value::String(s) => Some(s.clone()), _ => None, } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { - serde_json::Value::String(s) => Some(s), + serde_json::Value::String(s) => Some(s.clone()), _ => None, } } diff --git a/src/scalars/uuid.rs b/src/scalars/uuid.rs index 413efa46..70164d95 100644 --- a/src/scalars/uuid.rs +++ b/src/scalars/uuid.rs @@ -6,14 +6,14 @@ impl Scalar for Uuid { "UUID" } - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { Value::String(s) => Some(Uuid::parse_str(&s).ok()?), _ => None, } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { serde_json::Value::String(s) => Some(Uuid::parse_str(&s).ok()?), _ => None, diff --git a/src/types/enum.rs b/src/types/enum.rs index 18d35271..63ee0911 100644 --- a/src/types/enum.rs +++ b/src/types/enum.rs @@ -12,7 +12,7 @@ pub struct GQLEnumItem { pub trait GQLEnum: GQLType + Sized + Eq + Send + Copy + Sized + 'static { fn items() -> &'static [GQLEnumItem]; - fn parse_enum(value: Value) -> Option { + fn parse_enum(value: &Value) -> Option { match value { Value::Enum(s) => { let items = Self::items(); @@ -27,7 +27,7 @@ pub trait GQLEnum: GQLType + Sized + Eq + Send + Copy + Sized + 'static { None } - fn parse_json_enum(value: serde_json::Value) -> Option { + fn parse_json_enum(value: &serde_json::Value) -> Option { match value { serde_json::Value::String(s) => { let items = Self::items(); diff --git a/src/types/list.rs b/src/types/list.rs index eff529c9..8a250ca6 100644 --- a/src/types/list.rs +++ b/src/types/list.rs @@ -12,7 +12,7 @@ impl GQLType for Vec { } impl GQLInputValue for Vec { - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { Value::List(values) => { let mut result = Vec::new(); @@ -25,7 +25,7 @@ impl GQLInputValue for Vec { } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { serde_json::Value::Array(values) => { let mut result = Vec::new(); diff --git a/src/types/optional.rs b/src/types/optional.rs index 7125b5f4..865d12f1 100644 --- a/src/types/optional.rs +++ b/src/types/optional.rs @@ -16,14 +16,14 @@ impl GQLType for Option { } impl GQLInputValue for Option { - fn parse(value: Value) -> Option { + fn parse(value: &Value) -> Option { match value { Value::Null => Some(None), _ => Some(GQLInputValue::parse(value)?), } } - fn parse_from_json(value: serde_json::Value) -> Option { + fn parse_from_json(value: &serde_json::Value) -> Option { match value { serde_json::Value::Null => Some(None), _ => Some(GQLInputValue::parse_from_json(value)?),