Support default values
This commit is contained in:
parent
d8c7494dec
commit
602f6a656f
|
@ -56,20 +56,21 @@
|
||||||
- [X] Lifetime cycle
|
- [X] Lifetime cycle
|
||||||
- [X] Enum
|
- [X] Enum
|
||||||
- [X] InputObject
|
- [X] InputObject
|
||||||
- [ ] Field default value
|
- [X] Field default value
|
||||||
- [X] Deprecated flag
|
- [X] Deprecated flag
|
||||||
- [ ] Interface
|
- [ ] Interface
|
||||||
- [ ] Union
|
- [ ] Union
|
||||||
- [ ] Query
|
- [ ] Query
|
||||||
- [X] Fields
|
- [X] Fields
|
||||||
- [X] Arguments
|
- [X] Arguments
|
||||||
- [ ] Default value
|
- [X] Default value
|
||||||
- [X] Deprecated flag
|
- [X] Deprecated flag
|
||||||
- [X] Alias
|
- [X] Alias
|
||||||
- [ ] Fragments
|
- [ ] Fragments
|
||||||
- [ ] Inline fragments
|
- [ ] Inline fragments
|
||||||
- [X] Operation name
|
- [X] Operation name
|
||||||
- [X] Variables
|
- [X] Variables
|
||||||
|
- [X] Default value
|
||||||
- [X] Parse value
|
- [X] Parse value
|
||||||
- [ ] Check type
|
- [ ] Check type
|
||||||
- [ ] Directives
|
- [ ] Directives
|
||||||
|
|
|
@ -176,6 +176,12 @@ impl Field {
|
||||||
} else if nv.path.is_ident("default") {
|
} else if nv.path.is_ident("default") {
|
||||||
if let syn::Lit::Str(lit) = &nv.lit {
|
if let syn::Lit::Str(lit) = &nv.lit {
|
||||||
match parse_value(&lit.value()) {
|
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),
|
Ok(value) => default = Some(value),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(Error::new_spanned(
|
return Err(Error::new_spanned(
|
||||||
|
@ -406,6 +412,12 @@ impl InputField {
|
||||||
} else if nv.path.is_ident("default") {
|
} else if nv.path.is_ident("default") {
|
||||||
if let syn::Lit::Str(lit) = nv.lit {
|
if let syn::Lit::Str(lit) = nv.lit {
|
||||||
match parse_value(&lit.value()) {
|
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),
|
Ok(value) => default = Some(value),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(Error::new_spanned(
|
return Err(Error::new_spanned(
|
||||||
|
|
|
@ -98,11 +98,11 @@ pub fn generate(enum_args: &args::Enum, input: &DeriveInput) -> Result<TokenStre
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #crate_name::GQLInputValue for #ident {
|
impl #crate_name::GQLInputValue for #ident {
|
||||||
fn parse(value: #crate_name::Value) -> Option<Self> {
|
fn parse(value: &#crate_name::Value) -> Option<Self> {
|
||||||
#crate_name::GQLEnum::parse_enum(value)
|
#crate_name::GQLEnum::parse_enum(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: #crate_name::serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &#crate_name::serde_json::Value) -> Option<Self> {
|
||||||
#crate_name::GQLEnum::parse_json_enum(value)
|
#crate_name::GQLEnum::parse_json_enum(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::args;
|
use crate::args;
|
||||||
use crate::utils::get_crate_name;
|
use crate::utils::{build_value_repr, get_crate_name};
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{Data, DeriveInput, Error, Result};
|
use syn::{Data, DeriveInput, Error, Result};
|
||||||
|
@ -63,12 +63,45 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result<
|
||||||
quote! {Some(#s)}
|
quote! {Some(#s)}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| quote! {None});
|
.unwrap_or_else(|| quote! {None});
|
||||||
|
|
||||||
|
if let Some(default) = &field_args.default {
|
||||||
|
let default_repr = build_value_repr(&crate_name, default);
|
||||||
get_fields.push(quote! {
|
get_fields.push(quote! {
|
||||||
let #ident:#ty = #crate_name::GQLInputValue::parse(obj.remove(#name).unwrap_or(#crate_name::Value::Null))?;
|
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! {
|
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))?;
|
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);
|
fields.push(ident);
|
||||||
schema_fields.push(quote! {
|
schema_fields.push(quote! {
|
||||||
#crate_name::registry::InputValue {
|
#crate_name::registry::InputValue {
|
||||||
|
@ -98,10 +131,10 @@ pub fn generate(object_args: &args::InputObject, input: &DeriveInput) -> Result<
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #crate_name::GQLInputValue for #ident {
|
impl #crate_name::GQLInputValue for #ident {
|
||||||
fn parse(value: #crate_name::Value) -> Option<Self> {
|
fn parse(value: &#crate_name::Value) -> Option<Self> {
|
||||||
use #crate_name::GQLType;
|
use #crate_name::GQLType;
|
||||||
|
|
||||||
if let #crate_name::Value::Object(mut obj) = value {
|
if let #crate_name::Value::Object(obj) = value {
|
||||||
#(#get_fields)*
|
#(#get_fields)*
|
||||||
Some(Self { #(#fields),* })
|
Some(Self { #(#fields),* })
|
||||||
} else {
|
} 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<Self> {
|
fn parse_from_json(value: &#crate_name::serde_json::Value) -> Option<Self> {
|
||||||
use #crate_name::GQLType;
|
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)*
|
#(#get_json_fields)*
|
||||||
Some(Self { #(#fields),* })
|
Some(Self { #(#fields),* })
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::args;
|
use crate::args;
|
||||||
use crate::utils::get_crate_name;
|
use crate::utils::{build_value_repr, get_crate_name};
|
||||||
use inflector::Inflector;
|
use inflector::Inflector;
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use proc_macro2::Span;
|
use proc_macro2::Span;
|
||||||
|
@ -59,7 +59,7 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| quote! { Some(#s) })
|
.map(|s| quote! { Some(#s) })
|
||||||
.unwrap_or_else(|| quote! {None});
|
.unwrap_or_else(|| quote! {None});
|
||||||
let default = arg
|
let schema_default = arg
|
||||||
.default
|
.default
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
|
@ -69,16 +69,26 @@ pub fn generate(object_args: &args::Object, input: &DeriveInput) -> Result<Token
|
||||||
.unwrap_or_else(|| quote! {None});
|
.unwrap_or_else(|| quote! {None});
|
||||||
|
|
||||||
decl_params.push(quote! { #snake_case_name: #ty });
|
decl_params.push(quote! { #snake_case_name: #ty });
|
||||||
|
|
||||||
|
let default = match &arg.default {
|
||||||
|
Some(default) => {
|
||||||
|
let repr = build_value_repr(&crate_name, &default);
|
||||||
|
quote! {Some(|| #repr)}
|
||||||
|
}
|
||||||
|
None => quote! { None },
|
||||||
|
};
|
||||||
get_params.push(quote! {
|
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 });
|
use_params.push(quote! { #snake_case_name });
|
||||||
|
|
||||||
schema_args.push(quote! {
|
schema_args.push(quote! {
|
||||||
#crate_name::registry::InputValue {
|
#crate_name::registry::InputValue {
|
||||||
name: #name_str,
|
name: #name_str,
|
||||||
description: #desc,
|
description: #desc,
|
||||||
ty: <#ty as #crate_name::GQLType>::create_type_info(registry),
|
ty: <#ty as #crate_name::GQLType>::create_type_info(registry),
|
||||||
default_value: #default,
|
default_value: #schema_default,
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use graphql_parser::parse_query;
|
||||||
|
use graphql_parser::query::{Definition, OperationDefinition, ParseError, Query, Value};
|
||||||
use proc_macro2::{Span, TokenStream};
|
use proc_macro2::{Span, TokenStream};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::Ident;
|
use syn::Ident;
|
||||||
|
@ -12,18 +14,13 @@ pub fn get_crate_name(internal: bool) -> TokenStream {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_value(
|
pub fn parse_value(s: &str) -> Result<Value, ParseError> {
|
||||||
s: &str,
|
let mut doc = parse_query(&format!("query ($a:Int!={}) {{ dummy }}", s))?;
|
||||||
) -> Result<graphql_parser::query::Value, graphql_parser::query::ParseError> {
|
|
||||||
let mut doc =
|
|
||||||
graphql_parser::query::parse_query(&format!("query ($a:Int!={}) {{ dummy }}", s))?;
|
|
||||||
let definition = doc.definitions.remove(0);
|
let definition = doc.definitions.remove(0);
|
||||||
if let graphql_parser::query::Definition::Operation(
|
if let Definition::Operation(OperationDefinition::Query(Query {
|
||||||
graphql_parser::query::OperationDefinition::Query(graphql_parser::query::Query {
|
|
||||||
mut variable_definitions,
|
mut variable_definitions,
|
||||||
..
|
..
|
||||||
}),
|
})) = definition
|
||||||
) = definition
|
|
||||||
{
|
{
|
||||||
let var = variable_definitions.remove(0);
|
let var = variable_definitions.remove(0);
|
||||||
Ok(var.default_value.unwrap())
|
Ok(var.default_value.unwrap())
|
||||||
|
@ -31,3 +28,53 @@ pub fn parse_value(
|
||||||
unreachable!()
|
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::<Vec<_>>();
|
||||||
|
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::<Vec<_>>();
|
||||||
|
quote! {
|
||||||
|
{
|
||||||
|
let mut obj = std::collections::BTreeMap::new();
|
||||||
|
#(#members)*
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,9 +10,15 @@ struct MyInputObj {
|
||||||
a: i32,
|
a: i32,
|
||||||
b: i32,
|
b: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_graphql::Object(
|
#[async_graphql::Object(
|
||||||
field(name = "a", type = "i32"),
|
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<String>")
|
field(owned, name = "c", type = "Option<String>")
|
||||||
)]
|
)]
|
||||||
struct MyObj {
|
struct MyObj {
|
||||||
|
@ -25,8 +31,8 @@ impl MyObjFields for MyObj {
|
||||||
Ok(&self.value)
|
Ok(&self.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn b(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<i32> {
|
async fn b(&self, ctx: &async_graphql::Context<'_>, v: i32) -> async_graphql::Result<i32> {
|
||||||
Ok(999)
|
Ok(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn c(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<Option<String>> {
|
async fn c(&self, ctx: &async_graphql::Context<'_>) -> async_graphql::Result<Option<String>> {
|
||||||
|
@ -37,14 +43,16 @@ impl MyObjFields for MyObj {
|
||||||
#[async_std::main]
|
#[async_std::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let schema = async_graphql::Schema::<MyObj, async_graphql::GQLEmptyMutation>::new();
|
let schema = async_graphql::Schema::<MyObj, async_graphql::GQLEmptyMutation>::new();
|
||||||
|
for _ in 0..1000 {
|
||||||
let res = schema
|
let res = schema
|
||||||
.query(
|
.query(
|
||||||
MyObj { value: 100 },
|
MyObj { value: 100 },
|
||||||
async_graphql::GQLEmptyMutation,
|
async_graphql::GQLEmptyMutation,
|
||||||
"{ a b c __schema { types { kind name description } } }",
|
"{ a b c __schema { types { kind name description fields(includeDeprecated: false) { name args { name defaultValue } } } } }",
|
||||||
)
|
)
|
||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
serde_json::to_writer_pretty(std::io::stdout(), &res).unwrap();
|
}
|
||||||
|
// serde_json::to_writer_pretty(std::io::stdout(), &res).unwrap();
|
||||||
}
|
}
|
||||||
|
|
12
src/base.rs
12
src/base.rs
|
@ -15,8 +15,8 @@ pub trait GQLType {
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub trait GQLInputValue: GQLType + Sized {
|
pub trait GQLInputValue: GQLType + Sized {
|
||||||
fn parse(value: Value) -> Option<Self>;
|
fn parse(value: &Value) -> Option<Self>;
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self>;
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -36,8 +36,8 @@ pub trait Scalar: Sized + Send {
|
||||||
fn description() -> Option<&'static str> {
|
fn description() -> Option<&'static str> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
fn parse(value: Value) -> Option<Self>;
|
fn parse(value: &Value) -> Option<Self>;
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self>;
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self>;
|
||||||
fn to_json(&self) -> Result<serde_json::Value>;
|
fn to_json(&self) -> Result<serde_json::Value>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,11 +55,11 @@ impl<T: Scalar> GQLType for T {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Scalar> GQLInputValue for T {
|
impl<T: Scalar> GQLInputValue for T {
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
T::parse(value)
|
T::parse(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
T::parse_from_json(value)
|
T::parse_from_json(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,11 @@ impl<'a, T> ContextBase<'a, T> {
|
||||||
|
|
||||||
impl<'a> ContextBase<'a, &'a Field> {
|
impl<'a> ContextBase<'a, &'a Field> {
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn param_value<T: GQLInputValue>(&self, name: &str) -> Result<T> {
|
pub fn param_value<T: GQLInputValue, F: FnOnce() -> Value>(
|
||||||
|
&self,
|
||||||
|
name: &str,
|
||||||
|
default: Option<F>,
|
||||||
|
) -> Result<T> {
|
||||||
let value = self
|
let value = self
|
||||||
.arguments
|
.arguments
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -88,8 +92,7 @@ impl<'a> ContextBase<'a, &'a Field> {
|
||||||
if let Some(Value::Variable(var_name)) = &value {
|
if let Some(Value::Variable(var_name)) = &value {
|
||||||
if let Some(vars) = &self.variables {
|
if let Some(vars) = &self.variables {
|
||||||
if let Some(var_value) = vars.get(&*var_name).cloned() {
|
if let Some(var_value) = vars.get(&*var_name).cloned() {
|
||||||
let res =
|
let res = GQLInputValue::parse_from_json(&var_value).ok_or_else(|| {
|
||||||
GQLInputValue::parse_from_json(var_value.clone()).ok_or_else(|| {
|
|
||||||
QueryError::ExpectedJsonType {
|
QueryError::ExpectedJsonType {
|
||||||
expect: T::qualified_type_name(),
|
expect: T::qualified_type_name(),
|
||||||
actual: var_value,
|
actual: var_value,
|
||||||
|
@ -100,14 +103,31 @@ impl<'a> ContextBase<'a, &'a Field> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
return Err(QueryError::VarNotDefined {
|
||||||
var_name: var_name.clone(),
|
var_name: var_name.clone(),
|
||||||
}
|
}
|
||||||
.into());
|
.into());
|
||||||
};
|
};
|
||||||
|
|
||||||
let value = value.unwrap_or(Value::Null);
|
let value = if let (Some(default), None) = (default, &value) {
|
||||||
let res = GQLInputValue::parse(value.clone()).ok_or_else(|| {
|
default()
|
||||||
|
} else {
|
||||||
|
value.unwrap_or(Value::Null)
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = GQLInputValue::parse(&value).ok_or_else(|| {
|
||||||
QueryError::ExpectedType {
|
QueryError::ExpectedType {
|
||||||
expect: T::qualified_type_name(),
|
expect: T::qualified_type_name(),
|
||||||
actual: value,
|
actual: value,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::model::__Type;
|
use crate::model::{__InputValue, __Type};
|
||||||
use crate::{registry, Context, Result};
|
use crate::{registry, Context, Result};
|
||||||
use async_graphql_derive::Object;
|
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.",
|
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 = "name", type = "String", owned),
|
||||||
field(name = "description", type = "Option<String>", owned),
|
field(name = "description", type = "Option<String>", owned),
|
||||||
|
field(name = "args", type = "Vec<__InputValue>", owned),
|
||||||
field(name = "type", resolver = "ty", type = "__Type", owned),
|
field(name = "type", resolver = "ty", type = "__Type", owned),
|
||||||
field(name = "isDeprecated", type = "bool", owned),
|
field(name = "isDeprecated", type = "bool", owned),
|
||||||
field(name = "deprecationReason", type = "Option<String>", owned)
|
field(name = "deprecationReason", type = "Option<String>", owned)
|
||||||
|
@ -27,6 +28,18 @@ impl<'a> __FieldFields for __Field<'a> {
|
||||||
Ok(self.field.description.map(|s| s.to_string()))
|
Ok(self.field.description.map(|s| s.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn args<'b>(&'b self, _: &Context<'_>) -> Result<Vec<__InputValue<'b>>> {
|
||||||
|
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>> {
|
async fn ty<'b>(&'b self, _: &Context<'_>) -> Result<__Type<'b>> {
|
||||||
Ok(__Type {
|
Ok(__Type {
|
||||||
registry: self.registry,
|
registry: self.registry,
|
||||||
|
|
|
@ -17,7 +17,7 @@ Depending on the kind of a type, certain fields describe information about that
|
||||||
name = "fields",
|
name = "fields",
|
||||||
type = "Option<Vec<__Field>>",
|
type = "Option<Vec<__Field>>",
|
||||||
owned,
|
owned,
|
||||||
arg(name = "includeDeprecated", type = "bool")
|
arg(name = "includeDeprecated", type = "bool", default="false")
|
||||||
),
|
),
|
||||||
field(name = "interfaces", type = "Option<Vec<__Type>>", owned),
|
field(name = "interfaces", type = "Option<Vec<__Type>>", owned),
|
||||||
field(name = "possibleTypes", type = "Option<Vec<__Type>>", owned),
|
field(name = "possibleTypes", type = "Option<Vec<__Type>>", owned),
|
||||||
|
@ -25,7 +25,7 @@ Depending on the kind of a type, certain fields describe information about that
|
||||||
name = "enumValues",
|
name = "enumValues",
|
||||||
type = "Option<Vec<__EnumValue>>",
|
type = "Option<Vec<__EnumValue>>",
|
||||||
owned,
|
owned,
|
||||||
arg(name = "includeDeprecated", type = "bool")
|
arg(name = "includeDeprecated", type = "bool", default="false")
|
||||||
),
|
),
|
||||||
field(name = "inputFields", type = "Option<Vec<__InputValue>>", owned),
|
field(name = "inputFields", type = "Option<Vec<__InputValue>>", owned),
|
||||||
field(name = "ofType", type = "Option<__Type>", owned)
|
field(name = "ofType", type = "Option<__Type>", owned)
|
||||||
|
|
|
@ -9,16 +9,16 @@ impl Scalar for bool {
|
||||||
Some("The `Boolean` scalar type represents `true` or `false`.")
|
Some("The `Boolean` scalar type represents `true` or `false`.")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Boolean(n) => Some(n),
|
Value::Boolean(n) => Some(*n),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::Bool(n) => Some(n),
|
serde_json::Value::Bool(n) => Some(*n),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@ impl Scalar for DateTime<Utc> {
|
||||||
"DateTime"
|
"DateTime"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::String(s) => Some(Utc.datetime_from_str(&s, "%+").ok()?),
|
Value::String(s) => Some(Utc.datetime_from_str(&s, "%+").ok()?),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::String(s) => Some(Utc.datetime_from_str(&s, "%+").ok()?),
|
serde_json::Value::String(s) => Some(Utc.datetime_from_str(&s, "%+").ok()?),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -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).")
|
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<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Int(n) => Some(n.as_i64().unwrap() as Self),
|
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
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::Number(n) => Some(n.as_f64().unwrap() as Self),
|
serde_json::Value::Number(n) => Some(n.as_f64().unwrap() as Self),
|
||||||
_ => None
|
_ => None
|
||||||
|
|
|
@ -23,18 +23,18 @@ impl Scalar for ID {
|
||||||
"ID"
|
"ID"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Int(n) => Some(ID(n.as_i64().unwrap().to_string())),
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::Number(n) if n.is_i64() => Some(ID(n.as_i64().unwrap().to_string())),
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.")
|
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<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Int(n) => Some(n.as_i64().unwrap() as Self),
|
Value::Int(n) => Some(n.as_i64().unwrap() as Self),
|
||||||
_ => None
|
_ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::Number(n) if n.is_i64() => Some(n.as_i64().unwrap() as Self),
|
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),
|
serde_json::Value::Number(n) => Some(n.as_f64().unwrap() as Self),
|
||||||
|
|
|
@ -13,16 +13,16 @@ impl Scalar for String {
|
||||||
Some(STRING_DESC)
|
Some(STRING_DESC)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::String(s) => Some(s),
|
Value::String(s) => Some(s.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::String(s) => Some(s),
|
serde_json::Value::String(s) => Some(s.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,14 @@ impl Scalar for Uuid {
|
||||||
"UUID"
|
"UUID"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::String(s) => Some(Uuid::parse_str(&s).ok()?),
|
Value::String(s) => Some(Uuid::parse_str(&s).ok()?),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::String(s) => Some(Uuid::parse_str(&s).ok()?),
|
serde_json::Value::String(s) => Some(Uuid::parse_str(&s).ok()?),
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -12,7 +12,7 @@ pub struct GQLEnumItem<T> {
|
||||||
pub trait GQLEnum: GQLType + Sized + Eq + Send + Copy + Sized + 'static {
|
pub trait GQLEnum: GQLType + Sized + Eq + Send + Copy + Sized + 'static {
|
||||||
fn items() -> &'static [GQLEnumItem<Self>];
|
fn items() -> &'static [GQLEnumItem<Self>];
|
||||||
|
|
||||||
fn parse_enum(value: Value) -> Option<Self> {
|
fn parse_enum(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Enum(s) => {
|
Value::Enum(s) => {
|
||||||
let items = Self::items();
|
let items = Self::items();
|
||||||
|
@ -27,7 +27,7 @@ pub trait GQLEnum: GQLType + Sized + Eq + Send + Copy + Sized + 'static {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_json_enum(value: serde_json::Value) -> Option<Self> {
|
fn parse_json_enum(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::String(s) => {
|
serde_json::Value::String(s) => {
|
||||||
let items = Self::items();
|
let items = Self::items();
|
||||||
|
|
|
@ -12,7 +12,7 @@ impl<T: GQLType> GQLType for Vec<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GQLInputValue> GQLInputValue for Vec<T> {
|
impl<T: GQLInputValue> GQLInputValue for Vec<T> {
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::List(values) => {
|
Value::List(values) => {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
@ -25,7 +25,7 @@ impl<T: GQLInputValue> GQLInputValue for Vec<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::Array(values) => {
|
serde_json::Value::Array(values) => {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
|
|
|
@ -16,14 +16,14 @@ impl<T: GQLType> GQLType for Option<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GQLInputValue> GQLInputValue for Option<T> {
|
impl<T: GQLInputValue> GQLInputValue for Option<T> {
|
||||||
fn parse(value: Value) -> Option<Self> {
|
fn parse(value: &Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
Value::Null => Some(None),
|
Value::Null => Some(None),
|
||||||
_ => Some(GQLInputValue::parse(value)?),
|
_ => Some(GQLInputValue::parse(value)?),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_from_json(value: serde_json::Value) -> Option<Self> {
|
fn parse_from_json(value: &serde_json::Value) -> Option<Self> {
|
||||||
match value {
|
match value {
|
||||||
serde_json::Value::Null => Some(None),
|
serde_json::Value::Null => Some(None),
|
||||||
_ => Some(GQLInputValue::parse_from_json(value)?),
|
_ => Some(GQLInputValue::parse_from_json(value)?),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user