fix #33
This commit is contained in:
parent
001319776f
commit
4659da9c30
|
@ -219,7 +219,6 @@ pub struct Field {
|
|||
|
||||
impl Field {
|
||||
pub fn parse(attrs: &[Attribute]) -> Result<Option<Self>> {
|
||||
let mut is_field = false;
|
||||
let mut name = None;
|
||||
let mut desc = None;
|
||||
let mut deprecation = None;
|
||||
|
@ -231,13 +230,12 @@ impl Field {
|
|||
|
||||
for attr in attrs {
|
||||
match attr.parse_meta()? {
|
||||
Meta::Path(p) if p.is_ident("field") => {
|
||||
is_field = true;
|
||||
}
|
||||
Meta::List(ls) if ls.path.is_ident("field") => {
|
||||
is_field = true;
|
||||
for meta in &ls.nested {
|
||||
match meta {
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("skip") => {
|
||||
return Ok(None);
|
||||
}
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("external") => {
|
||||
external = true;
|
||||
}
|
||||
|
@ -305,20 +303,16 @@ impl Field {
|
|||
}
|
||||
}
|
||||
|
||||
if is_field {
|
||||
Ok(Some(Self {
|
||||
name,
|
||||
desc,
|
||||
deprecation,
|
||||
cache_control,
|
||||
external,
|
||||
provides,
|
||||
requires,
|
||||
is_ref,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
Ok(Some(Self {
|
||||
name,
|
||||
desc,
|
||||
deprecation,
|
||||
cache_control,
|
||||
external,
|
||||
provides,
|
||||
requires,
|
||||
is_ref,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -452,49 +446,58 @@ impl InputField {
|
|||
if attr.path.is_ident("field") {
|
||||
if let Meta::List(args) = &attr.parse_meta()? {
|
||||
for meta in &args.nested {
|
||||
if let NestedMeta::Meta(Meta::NameValue(nv)) = meta {
|
||||
if nv.path.is_ident("name") {
|
||||
if let syn::Lit::Str(lit) = &nv.lit {
|
||||
name = Some(lit.value());
|
||||
} else {
|
||||
return Err(Error::new_spanned(
|
||||
&nv.lit,
|
||||
"Attribute 'name' should be a string.",
|
||||
));
|
||||
}
|
||||
} else if nv.path.is_ident("desc") {
|
||||
if let syn::Lit::Str(lit) = &nv.lit {
|
||||
desc = Some(lit.value());
|
||||
} else {
|
||||
return Err(Error::new_spanned(
|
||||
&nv.lit,
|
||||
"Attribute 'desc' should be a string.",
|
||||
));
|
||||
}
|
||||
} 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(
|
||||
&lit,
|
||||
format!("Invalid value: {}", err),
|
||||
));
|
||||
}
|
||||
match meta {
|
||||
NestedMeta::Meta(Meta::Path(p)) if p.is_ident("skip") => {
|
||||
return Err(Error::new_spanned(
|
||||
meta,
|
||||
"Fields on InputObject are not allowed to be skipped",
|
||||
));
|
||||
}
|
||||
NestedMeta::Meta(Meta::NameValue(nv)) => {
|
||||
if nv.path.is_ident("name") {
|
||||
if let syn::Lit::Str(lit) = &nv.lit {
|
||||
name = Some(lit.value());
|
||||
} else {
|
||||
return Err(Error::new_spanned(
|
||||
&nv.lit,
|
||||
"Attribute 'name' should be a string.",
|
||||
));
|
||||
}
|
||||
} else if nv.path.is_ident("desc") {
|
||||
if let syn::Lit::Str(lit) = &nv.lit {
|
||||
desc = Some(lit.value());
|
||||
} else {
|
||||
return Err(Error::new_spanned(
|
||||
&nv.lit,
|
||||
"Attribute 'desc' should be a string.",
|
||||
));
|
||||
}
|
||||
} 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(
|
||||
&lit,
|
||||
format!("Invalid value: {}", err),
|
||||
));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new_spanned(
|
||||
&nv.lit,
|
||||
"Attribute 'default' should be a string.",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new_spanned(
|
||||
&nv.lit,
|
||||
"Attribute 'default' should be a string.",
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,130 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
|
||||
for item in &mut item_impl.items {
|
||||
if let ImplItem::Method(method) = item {
|
||||
if let Some(field) = args::Field::parse(&method.attrs)? {
|
||||
if method.attrs.iter().any(|attr| attr.path.is_ident("entity")) {
|
||||
let ty = match &method.sig.output {
|
||||
ReturnType::Type(_, ty) => OutputType::parse(ty)?,
|
||||
ReturnType::Default => {
|
||||
return Err(Error::new_spanned(&method.sig.output, "Missing type"))
|
||||
}
|
||||
};
|
||||
let mut arg_ctx = false;
|
||||
let mut args = Vec::new();
|
||||
|
||||
for (idx, arg) in method.sig.inputs.iter_mut().enumerate() {
|
||||
if let FnArg::Receiver(receiver) = arg {
|
||||
if idx != 0 {
|
||||
return Err(Error::new_spanned(
|
||||
receiver,
|
||||
"The self receiver must be the first parameter.",
|
||||
));
|
||||
}
|
||||
} else if let FnArg::Typed(pat) = arg {
|
||||
if idx == 0 {
|
||||
return Err(Error::new_spanned(
|
||||
pat,
|
||||
"The self receiver must be the first parameter.",
|
||||
));
|
||||
}
|
||||
|
||||
match (&*pat.pat, &*pat.ty) {
|
||||
(Pat::Ident(arg_ident), Type::Path(arg_ty)) => {
|
||||
args.push((
|
||||
arg_ident,
|
||||
arg_ty,
|
||||
args::Argument::parse(&crate_name, &pat.attrs)?,
|
||||
));
|
||||
pat.attrs.clear();
|
||||
}
|
||||
(_, Type::Reference(TypeReference { elem, .. })) => {
|
||||
if let Type::Path(path) = elem.as_ref() {
|
||||
if idx != 1
|
||||
|| path.path.segments.last().unwrap().ident != "Context"
|
||||
{
|
||||
return Err(Error::new_spanned(
|
||||
arg,
|
||||
"The Context must be the second argument.",
|
||||
));
|
||||
}
|
||||
arg_ctx = true;
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::new_spanned(arg, "Invalid argument type.")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let entity_type = ty.value_type();
|
||||
let mut key_pat = Vec::new();
|
||||
let mut key_getter = Vec::new();
|
||||
let mut use_keys = Vec::new();
|
||||
let mut keys = Vec::new();
|
||||
let mut keys_str = String::new();
|
||||
|
||||
for (ident, ty, args::Argument { name, .. }) in &args {
|
||||
let name = name
|
||||
.clone()
|
||||
.unwrap_or_else(|| ident.ident.to_string().to_camel_case());
|
||||
|
||||
if !keys_str.is_empty() {
|
||||
keys_str.push(' ');
|
||||
}
|
||||
keys_str.push_str(&name);
|
||||
|
||||
key_pat.push(quote! {
|
||||
Some(#ident)
|
||||
});
|
||||
key_getter.push(quote! {
|
||||
params.get(#name).and_then(|value| {
|
||||
let value: Option<#ty> = #crate_name::InputValueType::parse(value);
|
||||
value
|
||||
})
|
||||
});
|
||||
keys.push(name);
|
||||
use_keys.push(ident);
|
||||
}
|
||||
add_keys.push(quote! { registry.add_keys(&<#entity_type as #crate_name::Type>::type_name(), #keys_str); });
|
||||
create_entity_types.push(
|
||||
quote! { <#entity_type as #crate_name::Type>::create_type_info(registry); },
|
||||
);
|
||||
|
||||
let field_ident = &method.sig.ident;
|
||||
let ctx_param = if arg_ctx {
|
||||
quote! { &ctx, }
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
let do_find = match &ty {
|
||||
OutputType::Value(_) => quote! {
|
||||
self.#field_ident(#ctx_param #(#use_keys),*).await
|
||||
},
|
||||
OutputType::Result(_, _) => {
|
||||
quote! { self.#field_ident(#ctx_param #(#use_keys),*).await? }
|
||||
}
|
||||
};
|
||||
|
||||
find_entities.push((
|
||||
args.len(),
|
||||
quote! {
|
||||
if typename == &<#entity_type as #crate_name::Type>::type_name() {
|
||||
if let (#(#key_pat),*) = (#(#key_getter),*) {
|
||||
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
|
||||
return #crate_name::OutputValueType::resolve(&#do_find, &ctx_obj, pos).await;
|
||||
}
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
method.attrs.remove(
|
||||
method
|
||||
.attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, a)| a.path.is_ident("entity"))
|
||||
.map(|(idx, _)| idx)
|
||||
.unwrap(),
|
||||
);
|
||||
} else if let Some(field) = args::Field::parse(&method.attrs)? {
|
||||
if method.sig.asyncness.is_none() {
|
||||
return Err(Error::new_spanned(
|
||||
&method.sig.output,
|
||||
|
@ -240,138 +363,14 @@ pub fn generate(object_args: &args::Object, item_impl: &mut ItemImpl) -> Result<
|
|||
}
|
||||
});
|
||||
|
||||
method.attrs.remove(
|
||||
method
|
||||
.attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, a)| a.path.is_ident("field"))
|
||||
.map(|(idx, _)| idx)
|
||||
.unwrap(),
|
||||
);
|
||||
} else if method.attrs.iter().any(|attr| attr.path.is_ident("entity")) {
|
||||
let ty = match &method.sig.output {
|
||||
ReturnType::Type(_, ty) => OutputType::parse(ty)?,
|
||||
ReturnType::Default => {
|
||||
return Err(Error::new_spanned(&method.sig.output, "Missing type"))
|
||||
}
|
||||
};
|
||||
let mut arg_ctx = false;
|
||||
let mut args = Vec::new();
|
||||
|
||||
for (idx, arg) in method.sig.inputs.iter_mut().enumerate() {
|
||||
if let FnArg::Receiver(receiver) = arg {
|
||||
if idx != 0 {
|
||||
return Err(Error::new_spanned(
|
||||
receiver,
|
||||
"The self receiver must be the first parameter.",
|
||||
));
|
||||
}
|
||||
} else if let FnArg::Typed(pat) = arg {
|
||||
if idx == 0 {
|
||||
return Err(Error::new_spanned(
|
||||
pat,
|
||||
"The self receiver must be the first parameter.",
|
||||
));
|
||||
}
|
||||
|
||||
match (&*pat.pat, &*pat.ty) {
|
||||
(Pat::Ident(arg_ident), Type::Path(arg_ty)) => {
|
||||
args.push((
|
||||
arg_ident,
|
||||
arg_ty,
|
||||
args::Argument::parse(&crate_name, &pat.attrs)?,
|
||||
));
|
||||
pat.attrs.clear();
|
||||
}
|
||||
(_, Type::Reference(TypeReference { elem, .. })) => {
|
||||
if let Type::Path(path) = elem.as_ref() {
|
||||
if idx != 1
|
||||
|| path.path.segments.last().unwrap().ident != "Context"
|
||||
{
|
||||
return Err(Error::new_spanned(
|
||||
arg,
|
||||
"The Context must be the second argument.",
|
||||
));
|
||||
}
|
||||
arg_ctx = true;
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::new_spanned(arg, "Invalid argument type.")),
|
||||
}
|
||||
}
|
||||
if let Some((idx, _)) = method
|
||||
.attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, a)| a.path.is_ident("field"))
|
||||
{
|
||||
method.attrs.remove(idx);
|
||||
}
|
||||
|
||||
let entity_type = ty.value_type();
|
||||
let mut key_pat = Vec::new();
|
||||
let mut key_getter = Vec::new();
|
||||
let mut use_keys = Vec::new();
|
||||
let mut keys = Vec::new();
|
||||
let mut keys_str = String::new();
|
||||
|
||||
for (ident, ty, args::Argument { name, .. }) in &args {
|
||||
let name = name
|
||||
.clone()
|
||||
.unwrap_or_else(|| ident.ident.to_string().to_camel_case());
|
||||
|
||||
if !keys_str.is_empty() {
|
||||
keys_str.push(' ');
|
||||
}
|
||||
keys_str.push_str(&name);
|
||||
|
||||
key_pat.push(quote! {
|
||||
Some(#ident)
|
||||
});
|
||||
key_getter.push(quote! {
|
||||
params.get(#name).and_then(|value| {
|
||||
let value: Option<#ty> = #crate_name::InputValueType::parse(value);
|
||||
value
|
||||
})
|
||||
});
|
||||
keys.push(name);
|
||||
use_keys.push(ident);
|
||||
}
|
||||
add_keys.push(quote! { registry.add_keys(&<#entity_type as #crate_name::Type>::type_name(), #keys_str); });
|
||||
create_entity_types.push(
|
||||
quote! { <#entity_type as #crate_name::Type>::create_type_info(registry); },
|
||||
);
|
||||
|
||||
let field_ident = &method.sig.ident;
|
||||
let ctx_param = if arg_ctx {
|
||||
quote! { &ctx, }
|
||||
} else {
|
||||
quote! {}
|
||||
};
|
||||
let do_find = match &ty {
|
||||
OutputType::Value(_) => quote! {
|
||||
self.#field_ident(#ctx_param #(#use_keys),*).await
|
||||
},
|
||||
OutputType::Result(_, _) => {
|
||||
quote! { self.#field_ident(#ctx_param #(#use_keys),*).await? }
|
||||
}
|
||||
};
|
||||
|
||||
find_entities.push((
|
||||
args.len(),
|
||||
quote! {
|
||||
if typename == &<#entity_type as #crate_name::Type>::type_name() {
|
||||
if let (#(#key_pat),*) = (#(#key_getter),*) {
|
||||
let ctx_obj = ctx.with_selection_set(&ctx.selection_set);
|
||||
return #crate_name::OutputValueType::resolve(&#do_find, &ctx_obj, pos).await;
|
||||
}
|
||||
}
|
||||
},
|
||||
));
|
||||
|
||||
method.attrs.remove(
|
||||
method
|
||||
.attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, a)| a.path.is_ident("entity"))
|
||||
.map(|(idx, _)| idx)
|
||||
.unwrap(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,14 +114,14 @@ pub fn generate(object_args: &args::Object, input: &mut DeriveInput) -> Result<T
|
|||
}
|
||||
});
|
||||
|
||||
item.attrs.remove(
|
||||
item.attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, a)| a.path.is_ident("field"))
|
||||
.map(|(idx, _)| idx)
|
||||
.unwrap(),
|
||||
);
|
||||
if let Some((idx, _)) = item
|
||||
.attrs
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, a)| a.path.is_ident("field"))
|
||||
{
|
||||
item.attrs.remove(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,12 +17,10 @@ struct MyObject {
|
|||
|
||||
#[Object]
|
||||
impl MyObject {
|
||||
#[field]
|
||||
async fn value(&self) -> String {
|
||||
self.value.to_string()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value_from_db(
|
||||
&self,
|
||||
ctx: &Context<'_'>,
|
||||
|
|
|
@ -2,19 +2,17 @@
|
|||
|
||||
简单对象是把Rust结构的所有字段都直接映射到GraphQL对象,不支持定义单独的Resolve函数。
|
||||
|
||||
下面的例子定义了一个名称为MyObject的对象,包含字段`a`和`b`,`c`由于没有`#[field]`标记,所以不会映射到GraphQL。
|
||||
下面的例子定义了一个名称为MyObject的对象,包含字段`a`和`b`,`c`由于标记为`#[field(skip)]`,所以不会映射到GraphQL。
|
||||
|
||||
```rust
|
||||
use async_graphql::*;
|
||||
|
||||
#[SimpleObject]
|
||||
struct MyObject {
|
||||
#[field]
|
||||
a: i32,
|
||||
|
||||
#[field]
|
||||
b: i32,
|
||||
|
||||
#[field(skip)]
|
||||
c: i32,
|
||||
}
|
||||
```
|
||||
|
|
|
@ -225,7 +225,6 @@ pub use types::{EnumItem, EnumType};
|
|||
/// Ok(self.value)
|
||||
/// }
|
||||
///
|
||||
/// #[field]
|
||||
/// async fn value_with_arg(&self, #[arg(default = "1")] a: i32) -> i32 {
|
||||
/// a
|
||||
/// }
|
||||
|
@ -283,7 +282,6 @@ pub use async_graphql_derive::Object;
|
|||
///
|
||||
/// #[SimpleObject]
|
||||
/// struct QueryRoot {
|
||||
/// #[field]
|
||||
/// value: i32,
|
||||
/// }
|
||||
///
|
||||
|
@ -462,19 +460,16 @@ pub use async_graphql_derive::InputObject;
|
|||
/// #[Object]
|
||||
/// impl TypeA {
|
||||
/// /// Returns data borrowed from the context
|
||||
/// #[field]
|
||||
/// async fn value_a<'a>(&self, ctx: &'a Context<'_>) -> &'a str {
|
||||
/// ctx.data::<String>().as_str()
|
||||
/// }
|
||||
///
|
||||
/// /// Returns data borrowed self
|
||||
/// #[field]
|
||||
/// async fn value_b(&self) -> &i32 {
|
||||
/// &self.value
|
||||
/// }
|
||||
///
|
||||
/// /// With parameters
|
||||
/// #[field]
|
||||
/// async fn value_c(&self, a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
/// }
|
||||
|
@ -493,7 +488,6 @@ pub use async_graphql_derive::InputObject;
|
|||
///
|
||||
/// #[Object]
|
||||
/// impl QueryRoot {
|
||||
/// #[field]
|
||||
/// async fn type_a(&self) -> MyInterface {
|
||||
/// TypeA { value: 10 }.into()
|
||||
/// }
|
||||
|
@ -571,7 +565,6 @@ pub use async_graphql_derive::Union;
|
|||
///
|
||||
/// #[Subscription]
|
||||
/// impl SubscriptionRoot {
|
||||
/// #[field]
|
||||
/// async fn value(&self, event: &Event, condition: i32) -> bool {
|
||||
/// // Push when value is greater than condition
|
||||
/// event.value > condition
|
||||
|
|
|
@ -79,22 +79,18 @@ pub struct __Directive<'a> {
|
|||
In some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor."#
|
||||
)]
|
||||
impl<'a> __Directive<'a> {
|
||||
#[field]
|
||||
async fn name(&self) -> String {
|
||||
self.directive.name.to_string()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn description(&self) -> Option<String> {
|
||||
self.directive.description.map(|s| s.to_string())
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn locations(&self) -> &Vec<__DirectiveLocation> {
|
||||
&self.directive.locations
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn args(&self) -> Vec<__InputValue<'a>> {
|
||||
self.directive
|
||||
.args
|
||||
|
|
|
@ -11,22 +11,18 @@ pub struct __EnumValue<'a> {
|
|||
desc = "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string."
|
||||
)]
|
||||
impl<'a> __EnumValue<'a> {
|
||||
#[field]
|
||||
async fn name(&self, _: &Context<'_>) -> String {
|
||||
self.value.name.to_string()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn description(&self, _: &Context<'_>) -> Option<String> {
|
||||
self.value.description.map(|s| s.to_string())
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn is_deprecated(&self, _: &Context<'_>) -> bool {
|
||||
self.value.deprecation.is_some()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn deprecation_reason(&self, _: &Context<'_>) -> Option<String> {
|
||||
self.value.deprecation.map(|s| s.to_string())
|
||||
}
|
||||
|
|
|
@ -13,17 +13,14 @@ pub struct __Field<'a> {
|
|||
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."
|
||||
)]
|
||||
impl<'a> __Field<'a> {
|
||||
#[field]
|
||||
async fn name(&self) -> String {
|
||||
self.field.name.to_string()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn description(&self) -> Option<String> {
|
||||
self.field.description.map(|s| s.to_string())
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn args(&self) -> Vec<__InputValue<'a>> {
|
||||
let mut args = self
|
||||
.field
|
||||
|
@ -43,12 +40,10 @@ impl<'a> __Field<'a> {
|
|||
__Type::new(self.registry, &self.field.ty)
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn is_deprecated(&self) -> bool {
|
||||
self.field.deprecation.is_some()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn deprecation_reason(&self) -> Option<String> {
|
||||
self.field.deprecation.map(|s| s.to_string())
|
||||
}
|
||||
|
|
|
@ -12,12 +12,10 @@ pub struct __InputValue<'a> {
|
|||
desc = "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value."
|
||||
)]
|
||||
impl<'a> __InputValue<'a> {
|
||||
#[field]
|
||||
async fn name(&self) -> String {
|
||||
self.input_value.name.to_string()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn description(&self) -> Option<String> {
|
||||
self.input_value.description.map(|s| s.to_string())
|
||||
}
|
||||
|
@ -27,7 +25,6 @@ impl<'a> __InputValue<'a> {
|
|||
__Type::new(self.registry, &self.input_value.ty)
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn default_value(&self) -> Option<String> {
|
||||
self.input_value.default_value.map(|s| s.to_string())
|
||||
}
|
||||
|
|
|
@ -49,7 +49,6 @@ Depending on the kind of a type, certain fields describe information about that
|
|||
"#
|
||||
)]
|
||||
impl<'a> __Type<'a> {
|
||||
#[field]
|
||||
async fn kind(&self) -> __TypeKind {
|
||||
match &self.detail {
|
||||
TypeDetail::Named(ty) => match ty {
|
||||
|
@ -65,7 +64,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn name(&self) -> Option<String> {
|
||||
match &self.detail {
|
||||
TypeDetail::Named(ty) => Some(ty.name().to_string()),
|
||||
|
@ -74,7 +72,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn description(&self) -> Option<String> {
|
||||
match &self.detail {
|
||||
TypeDetail::Named(ty) => match ty {
|
||||
|
@ -92,7 +89,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn fields(
|
||||
&self,
|
||||
#[arg(default = "false")] include_deprecated: bool,
|
||||
|
@ -118,7 +114,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn interfaces(&self) -> Option<Vec<__Type<'a>>> {
|
||||
if let TypeDetail::Named(registry::Type::Object { name, .. }) = &self.detail {
|
||||
Some(
|
||||
|
@ -135,7 +130,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn possible_types(&self) -> Option<Vec<__Type<'a>>> {
|
||||
if let TypeDetail::Named(registry::Type::Interface { possible_types, .. }) = &self.detail {
|
||||
Some(
|
||||
|
@ -157,7 +151,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn enum_values(
|
||||
&self,
|
||||
#[arg(default = "false")] include_deprecated: bool,
|
||||
|
@ -178,7 +171,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn input_fields(&self) -> Option<Vec<__InputValue<'a>>> {
|
||||
if let TypeDetail::Named(registry::Type::InputObject { input_fields, .. }) = &self.detail {
|
||||
Some(
|
||||
|
@ -195,7 +187,6 @@ impl<'a> __Type<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn of_type(&self) -> Option<__Type<'a>> {
|
||||
if let TypeDetail::List(ty) = &self.detail {
|
||||
Some(__Type::new(self.registry, &ty))
|
||||
|
|
|
@ -48,7 +48,6 @@ pub struct EmptyEdgeFields;
|
|||
///
|
||||
/// #[SimpleObject]
|
||||
/// struct DiffFields {
|
||||
/// #[field]
|
||||
/// diff: i32,
|
||||
/// }
|
||||
///
|
||||
|
@ -85,7 +84,6 @@ pub struct EmptyEdgeFields;
|
|||
///
|
||||
/// #[Object]
|
||||
/// impl QueryRoot {
|
||||
/// #[field]
|
||||
/// async fn numbers(&self, ctx: &Context<'_>,
|
||||
/// after: Option<String>,
|
||||
/// before: Option<String>,
|
||||
|
|
|
@ -12,7 +12,6 @@ use std::collections::HashMap;
|
|||
/// Federation service
|
||||
#[SimpleObject(internal)]
|
||||
struct Service {
|
||||
#[field]
|
||||
sdl: Option<String>,
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ use std::path::PathBuf;
|
|||
///
|
||||
/// #[async_graphql::Object]
|
||||
/// impl MutationRoot {
|
||||
/// #[field]
|
||||
/// async fn upload(&self, file: Upload) -> bool {
|
||||
/// println!("upload: filename={}", file.filename);
|
||||
/// true
|
||||
|
|
|
@ -22,37 +22,30 @@ struct Dog;
|
|||
|
||||
#[Object(internal)]
|
||||
impl Dog {
|
||||
#[field]
|
||||
async fn name(&self, surname: Option<bool>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn nickname(&self) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn bark_volume(&self) -> Option<i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn barks(&self) -> Option<bool> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn does_know_command(&self, dog_command: Option<DogCommand>) -> Option<bool> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn is_housetrained(&self, #[arg(default = "true")] at_other_homes: bool) -> Option<bool> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn is_at_location(&self, x: Option<i32>, y: Option<i32>) -> Option<bool> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -70,27 +63,22 @@ struct Cat;
|
|||
|
||||
#[Object(internal)]
|
||||
impl Cat {
|
||||
#[field]
|
||||
async fn name(&self, surname: Option<bool>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn nickname(&self) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn meows(&self) -> Option<bool> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn meow_volume(&self) -> Option<i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn fur_color(&self) -> Option<FurColor> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -103,22 +91,18 @@ struct Human;
|
|||
|
||||
#[Object(internal)]
|
||||
impl Human {
|
||||
#[field]
|
||||
async fn name(&self, surname: Option<bool>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn pets(&self) -> Option<Vec<Option<Pet>>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn relatives(&self) -> Option<Vec<Human>> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn iq(&self) -> Option<i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -128,17 +112,14 @@ struct Alien;
|
|||
|
||||
#[Object(internal)]
|
||||
impl Alien {
|
||||
#[field]
|
||||
async fn name(&self, surname: Option<bool>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn iq(&self) -> Option<i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn num_eyes(&self) -> Option<i32> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -185,19 +166,10 @@ struct Intelligent(Human, Alien);
|
|||
|
||||
#[InputObject(internal)]
|
||||
struct ComplexInput {
|
||||
#[field]
|
||||
required_field: bool,
|
||||
|
||||
#[field]
|
||||
int_field: Option<i32>,
|
||||
|
||||
#[field]
|
||||
string_field: Option<String>,
|
||||
|
||||
#[field]
|
||||
boolean_field: Option<bool>,
|
||||
|
||||
#[field]
|
||||
string_list_field: Option<Vec<Option<String>>>,
|
||||
}
|
||||
|
||||
|
@ -205,42 +177,34 @@ struct ComplicatedArgs;
|
|||
|
||||
#[Object(internal)]
|
||||
impl ComplicatedArgs {
|
||||
#[field]
|
||||
async fn int_arg_field(&self, int_arg: Option<i32>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn non_null_int_arg_field(&self, non_null_int_arg: i32) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn string_arg_field(&self, string_arg: Option<String>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn boolean_arg_field(&self, boolean_arg: Option<bool>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn enum_arg_field(&self, enum_arg: Option<FurColor>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn float_arg_field(&self, float_arg: Option<f64>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn id_arg_field(&self, id_arg: Option<ID>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn string_list_arg_field(
|
||||
&self,
|
||||
string_list_arg: Option<Vec<Option<String>>>,
|
||||
|
@ -248,17 +212,14 @@ impl ComplicatedArgs {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn complex_arg_field(&self, complex_arg: Option<ComplexInput>) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn multiple_reqs(&self, req1: i32, req2: i32) -> Option<String> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn multiple_opts(
|
||||
&self,
|
||||
#[arg(default = "0")] opt1: i32,
|
||||
|
@ -267,7 +228,6 @@ impl ComplicatedArgs {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn multiple_opt_and_req(
|
||||
&self,
|
||||
req1: i32,
|
||||
|
@ -283,57 +243,46 @@ pub struct QueryRoot;
|
|||
|
||||
#[Object(internal)]
|
||||
impl QueryRoot {
|
||||
#[field]
|
||||
async fn human(&self, id: Option<ID>) -> Option<Human> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn alien(&self) -> Option<Alien> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn dog(&self) -> Option<Dog> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn cat(&self) -> Option<Cat> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn pet(&self) -> Option<Pet> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn being(&self) -> Option<Being> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn intelligent(&self) -> Option<Intelligent> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn cat_or_dog(&self) -> Option<CatOrDog> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn dog_or_human(&self) -> Option<DogOrHuman> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn human_or_alien(&self) -> Option<HumanOrAlien> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn complicated_args(&self) -> Option<ComplicatedArgs> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -343,7 +292,6 @@ pub struct MutationRoot;
|
|||
|
||||
#[Object(internal)]
|
||||
impl MutationRoot {
|
||||
#[field]
|
||||
async fn test_input(
|
||||
&self,
|
||||
#[arg(default = r#"{id: 423, name: "foo"}"#)] input: TestInput,
|
||||
|
|
|
@ -23,19 +23,16 @@ pub use string_validators::{Email, StringMaxLength, StringMinLength, MAC};
|
|||
/// #[Object]
|
||||
/// impl QueryRoot {
|
||||
/// // Input is email address
|
||||
/// #[field]
|
||||
/// async fn value1(&self, #[arg(validator(Email))] email: String) -> i32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// // Input is email or MAC address
|
||||
/// #[field]
|
||||
/// async fn value2(&self, #[arg(validator(or(Email, MAC(colon = false))))] email_or_mac: String) -> i32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
///
|
||||
/// // Input is integer between 100 and 200
|
||||
/// #[field]
|
||||
/// async fn value3(&self, #[arg(validator(IntRange(min = 100, max = 200)))] value: i32) -> i32 {
|
||||
/// unimplemented!()
|
||||
/// }
|
||||
|
|
|
@ -6,7 +6,6 @@ pub async fn test_directive_skip() {
|
|||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
#[field]
|
||||
pub async fn value(&self) -> i32 {
|
||||
10
|
||||
}
|
||||
|
@ -38,7 +37,6 @@ pub async fn test_directive_include() {
|
|||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
#[field]
|
||||
pub async fn value(&self) -> i32 {
|
||||
10
|
||||
}
|
||||
|
|
|
@ -19,17 +19,14 @@ pub async fn test_enum_type() {
|
|||
|
||||
#[Object]
|
||||
impl Root {
|
||||
#[field]
|
||||
async fn value(&self) -> MyEnum {
|
||||
self.value
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_arg(&self, input: MyEnum) -> MyEnum {
|
||||
input
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_input<'a>(&self, input: MyInput) -> MyEnum {
|
||||
input.value
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ impl User {
|
|||
&self.id
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn reviews(&self) -> Vec<Review> {
|
||||
todo!()
|
||||
}
|
||||
|
@ -21,7 +20,6 @@ struct Review;
|
|||
|
||||
#[Object]
|
||||
impl Review {
|
||||
#[field]
|
||||
async fn body(&self) -> String {
|
||||
todo!()
|
||||
}
|
||||
|
@ -31,7 +29,6 @@ impl Review {
|
|||
todo!()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn product(&self) -> Product {
|
||||
todo!()
|
||||
}
|
||||
|
@ -48,7 +45,6 @@ impl Product {
|
|||
&self.upc
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn reviews(&self) -> Vec<Review> {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -30,27 +30,22 @@ pub async fn test_input_object_default_value() {
|
|||
|
||||
#[Object]
|
||||
impl MyOutput {
|
||||
#[field]
|
||||
async fn a(&self) -> i32 {
|
||||
self.a
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn b(&self) -> &Vec<i32> {
|
||||
&self.b
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn c(&self) -> &String {
|
||||
&self.c
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn d(&self) -> &Option<i32> {
|
||||
&self.d
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn e(&self) -> &Option<i32> {
|
||||
&self.e
|
||||
}
|
||||
|
@ -60,7 +55,6 @@ pub async fn test_input_object_default_value() {
|
|||
|
||||
#[Object]
|
||||
impl Root {
|
||||
#[field]
|
||||
async fn a(&self, input: MyInput) -> MyOutput {
|
||||
MyOutput {
|
||||
a: input.a,
|
||||
|
|
|
@ -4,9 +4,7 @@ use async_graphql::*;
|
|||
pub async fn test_interface_simple_object() {
|
||||
#[async_graphql::SimpleObject]
|
||||
struct MyObj {
|
||||
#[field]
|
||||
id: i32,
|
||||
#[field]
|
||||
title: String,
|
||||
}
|
||||
|
||||
|
@ -17,7 +15,6 @@ pub async fn test_interface_simple_object() {
|
|||
|
||||
#[Object]
|
||||
impl Query {
|
||||
#[field]
|
||||
async fn node(&self) -> Node {
|
||||
MyObj {
|
||||
id: 33,
|
||||
|
@ -27,15 +24,13 @@ pub async fn test_interface_simple_object() {
|
|||
}
|
||||
}
|
||||
|
||||
let query = format!(
|
||||
r#"{{
|
||||
node {{
|
||||
... on Node {{
|
||||
let query = r#"{
|
||||
node {
|
||||
... on Node {
|
||||
id
|
||||
}}
|
||||
}}
|
||||
}}"#
|
||||
);
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.unwrap().data,
|
||||
|
@ -53,7 +48,6 @@ pub async fn test_interface_simple_object2() {
|
|||
struct MyObj {
|
||||
#[field(ref)]
|
||||
id: i32,
|
||||
#[field]
|
||||
title: String,
|
||||
}
|
||||
|
||||
|
@ -64,7 +58,6 @@ pub async fn test_interface_simple_object2() {
|
|||
|
||||
#[Object]
|
||||
impl Query {
|
||||
#[field]
|
||||
async fn node(&self) -> Node {
|
||||
MyObj {
|
||||
id: 33,
|
||||
|
@ -74,15 +67,13 @@ pub async fn test_interface_simple_object2() {
|
|||
}
|
||||
}
|
||||
|
||||
let query = format!(
|
||||
r#"{{
|
||||
node {{
|
||||
... on Node {{
|
||||
let query = r#"{
|
||||
node {
|
||||
... on Node {
|
||||
id
|
||||
}}
|
||||
}}
|
||||
}}"#
|
||||
);
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.unwrap().data,
|
||||
|
@ -100,17 +91,14 @@ pub async fn test_multiple_interfaces() {
|
|||
|
||||
#[async_graphql::Object]
|
||||
impl MyObj {
|
||||
#[field]
|
||||
async fn value_a(&self) -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value_b(&self) -> i32 {
|
||||
2
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value_c(&self) -> i32 {
|
||||
3
|
||||
}
|
||||
|
@ -126,7 +114,6 @@ pub async fn test_multiple_interfaces() {
|
|||
|
||||
#[Object]
|
||||
impl Query {
|
||||
#[field]
|
||||
async fn my_obj(&self) -> InterfaceB {
|
||||
MyObj.into()
|
||||
}
|
||||
|
@ -135,21 +122,19 @@ pub async fn test_multiple_interfaces() {
|
|||
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
|
||||
.register_type::<InterfaceA>() // `InterfaceA` is not directly referenced, so manual registration is required.
|
||||
.finish();
|
||||
let query = format!(
|
||||
r#"{{
|
||||
myObj {{
|
||||
... on InterfaceA {{
|
||||
let query = r#"{
|
||||
myObj {
|
||||
... on InterfaceA {
|
||||
valueA
|
||||
}}
|
||||
... on InterfaceB {{
|
||||
}
|
||||
... on InterfaceB {
|
||||
valueB
|
||||
}}
|
||||
... on MyObj {{
|
||||
}
|
||||
... on MyObj {
|
||||
valueC
|
||||
}}
|
||||
}}
|
||||
}}"#
|
||||
);
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.unwrap().data,
|
||||
serde_json::json!({
|
||||
|
@ -168,17 +153,14 @@ pub async fn test_multiple_objects_in_multiple_interfaces() {
|
|||
|
||||
#[async_graphql::Object]
|
||||
impl MyObjOne {
|
||||
#[field]
|
||||
async fn value_a(&self) -> i32 {
|
||||
1
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value_b(&self) -> i32 {
|
||||
2
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value_c(&self) -> i32 {
|
||||
3
|
||||
}
|
||||
|
@ -188,7 +170,6 @@ pub async fn test_multiple_objects_in_multiple_interfaces() {
|
|||
|
||||
#[async_graphql::Object]
|
||||
impl MyObjTwo {
|
||||
#[field]
|
||||
async fn value_a(&self) -> i32 {
|
||||
1
|
||||
}
|
||||
|
@ -204,7 +185,6 @@ pub async fn test_multiple_objects_in_multiple_interfaces() {
|
|||
|
||||
#[Object]
|
||||
impl Query {
|
||||
#[field]
|
||||
async fn my_obj(&self) -> Vec<InterfaceA> {
|
||||
vec![MyObjOne.into(), MyObjTwo.into()]
|
||||
}
|
||||
|
@ -213,21 +193,19 @@ pub async fn test_multiple_objects_in_multiple_interfaces() {
|
|||
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
|
||||
.register_type::<InterfaceB>() // `InterfaceB` is not directly referenced, so manual registration is required.
|
||||
.finish();
|
||||
let query = format!(
|
||||
r#"{{
|
||||
myObj {{
|
||||
... on InterfaceA {{
|
||||
let query = r#"{
|
||||
myObj {
|
||||
... on InterfaceA {
|
||||
valueA
|
||||
}}
|
||||
... on InterfaceB {{
|
||||
}
|
||||
... on InterfaceB {
|
||||
valueB
|
||||
}}
|
||||
... on MyObjOne {{
|
||||
}
|
||||
... on MyObjOne {
|
||||
valueC
|
||||
}}
|
||||
}}
|
||||
}}"#
|
||||
);
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.unwrap().data,
|
||||
serde_json::json!({
|
||||
|
@ -248,7 +226,6 @@ pub async fn test_interface_field_result() {
|
|||
|
||||
#[async_graphql::Object]
|
||||
impl MyObj {
|
||||
#[field]
|
||||
async fn value(&self) -> FieldResult<i32> {
|
||||
Ok(10)
|
||||
}
|
||||
|
@ -261,21 +238,18 @@ pub async fn test_interface_field_result() {
|
|||
|
||||
#[Object]
|
||||
impl Query {
|
||||
#[field]
|
||||
async fn node(&self) -> Node {
|
||||
MyObj.into()
|
||||
}
|
||||
}
|
||||
|
||||
let query = format!(
|
||||
r#"{{
|
||||
node {{
|
||||
... on Node {{
|
||||
let query = r#"{
|
||||
node {
|
||||
... on Node {
|
||||
value
|
||||
}}
|
||||
}}
|
||||
}}"#
|
||||
);
|
||||
}
|
||||
}
|
||||
}"#;
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
assert_eq!(
|
||||
schema.execute(&query).await.unwrap().data,
|
||||
|
|
|
@ -13,27 +13,22 @@ pub async fn test_list_type() {
|
|||
|
||||
#[Object]
|
||||
impl Root {
|
||||
#[field]
|
||||
async fn value_vec(&self) -> Vec<i32> {
|
||||
self.value.clone()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value_slice(&self) -> &[i32] {
|
||||
&self.value
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value_input_slice(&self, a: Vec<i32>) -> Vec<i32> {
|
||||
a
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_arg(&self, input: Vec<i32>) -> Vec<i32> {
|
||||
input
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_input<'a>(&self, input: MyInput) -> Vec<i32> {
|
||||
input.value
|
||||
}
|
||||
|
|
|
@ -14,14 +14,12 @@ pub async fn test_mutation_execution_order() {
|
|||
|
||||
#[Object]
|
||||
impl MutationRoot {
|
||||
#[field]
|
||||
async fn append1(&self, ctx: &Context<'_>) -> bool {
|
||||
async_std::task::sleep(Duration::from_secs(1)).await;
|
||||
ctx.data::<List>().lock().await.push(1);
|
||||
true
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn append2(&self, ctx: &Context<'_>) -> bool {
|
||||
async_std::task::sleep(Duration::from_millis(500)).await;
|
||||
ctx.data::<List>().lock().await.push(2);
|
||||
|
@ -50,7 +48,6 @@ pub async fn test_mutation_fragment() {
|
|||
|
||||
#[Object]
|
||||
impl MutationRoot {
|
||||
#[field]
|
||||
async fn action(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
|
|
@ -14,32 +14,26 @@ pub async fn test_optional_type() {
|
|||
|
||||
#[Object]
|
||||
impl Root {
|
||||
#[field]
|
||||
async fn value1(&self) -> Option<i32> {
|
||||
self.value1.clone()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value1_ref(&self) -> &Option<i32> {
|
||||
&self.value1
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value2(&self) -> Option<i32> {
|
||||
self.value2.clone()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn value2_ref(&self) -> &Option<i32> {
|
||||
&self.value2
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_arg(&self, input: Option<i32>) -> Option<i32> {
|
||||
input
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_input<'a>(&self, input: MyInput) -> Option<i32> {
|
||||
input.value.clone()
|
||||
}
|
||||
|
|
|
@ -15,17 +15,14 @@ macro_rules! test_scalars {
|
|||
|
||||
#[Object]
|
||||
impl Root {
|
||||
#[field]
|
||||
async fn value(&self) -> $ty {
|
||||
self.value
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_arg(&self, input: $ty) -> $ty {
|
||||
input
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn test_input(&self, input: MyInput) -> $ty {
|
||||
input.value
|
||||
}
|
||||
|
|
|
@ -8,10 +8,7 @@ pub async fn test_subscription() {
|
|||
|
||||
#[SimpleObject]
|
||||
struct Event {
|
||||
#[field]
|
||||
a: i32,
|
||||
|
||||
#[field]
|
||||
b: i32,
|
||||
}
|
||||
|
||||
|
@ -22,12 +19,10 @@ pub async fn test_subscription() {
|
|||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
#[field]
|
||||
async fn values(&self, start: i32, end: i32) -> impl Stream<Item = i32> {
|
||||
futures::stream::iter(start..end)
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn events(&self, start: i32, end: i32) -> impl Stream<Item = Event> {
|
||||
futures::stream::iter((start..end).map(|n| Event { a: n, b: n * 10 }))
|
||||
}
|
||||
|
@ -81,14 +76,12 @@ pub async fn test_simple_broker() {
|
|||
#[SimpleObject]
|
||||
#[derive(Clone)]
|
||||
struct Event1 {
|
||||
#[field]
|
||||
value: i32,
|
||||
}
|
||||
|
||||
#[SimpleObject]
|
||||
#[derive(Clone)]
|
||||
struct Event2 {
|
||||
#[field]
|
||||
value: i32,
|
||||
}
|
||||
|
||||
|
@ -99,12 +92,10 @@ pub async fn test_simple_broker() {
|
|||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
#[field]
|
||||
async fn events1(&self) -> impl Stream<Item = Event1> {
|
||||
SimpleBroker::<Event1>::subscribe()
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn events2(&self) -> impl Stream<Item = Event2> {
|
||||
SimpleBroker::<Event2>::subscribe()
|
||||
}
|
||||
|
@ -165,7 +156,6 @@ pub async fn test_subscription_with_ctx_data() {
|
|||
|
||||
#[Object]
|
||||
impl MyObject {
|
||||
#[field]
|
||||
async fn value(&self, ctx: &Context<'_>) -> i32 {
|
||||
*ctx.data::<i32>()
|
||||
}
|
||||
|
@ -175,13 +165,11 @@ pub async fn test_subscription_with_ctx_data() {
|
|||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
#[field]
|
||||
async fn values(&self, ctx: &Context<'_>) -> impl Stream<Item = i32> {
|
||||
let value = *ctx.data::<i32>();
|
||||
futures::stream::once(async move { value })
|
||||
}
|
||||
|
||||
#[field]
|
||||
async fn objects(&self) -> impl Stream<Item = MyObject> {
|
||||
futures::stream::once(async move { MyObject })
|
||||
}
|
||||
|
@ -228,7 +216,6 @@ pub async fn test_subscription_with_token() {
|
|||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
#[field]
|
||||
async fn values(&self, ctx: &Context<'_>) -> FieldResult<impl Stream<Item = i32>> {
|
||||
if ctx.data::<Token>().0 != "123456" {
|
||||
return Err("forbidden".into());
|
||||
|
@ -288,7 +275,6 @@ pub async fn test_subscription_ws_transport() {
|
|||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
#[field]
|
||||
async fn values(&self) -> impl Stream<Item = i32> {
|
||||
futures::stream::iter(0..10)
|
||||
}
|
||||
|
@ -354,7 +340,6 @@ pub async fn test_subscription_ws_transport_with_token() {
|
|||
|
||||
#[Subscription]
|
||||
impl SubscriptionRoot {
|
||||
#[field]
|
||||
async fn values(&self, ctx: &Context<'_>) -> FieldResult<impl Stream<Item = i32>> {
|
||||
if ctx.data::<Token>().0 != "123456" {
|
||||
return Err("forbidden".into());
|
||||
|
|
|
@ -6,12 +6,10 @@ pub async fn test_variables() {
|
|||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
#[field]
|
||||
pub async fn int_val(&self, value: i32) -> i32 {
|
||||
value
|
||||
}
|
||||
|
||||
#[field]
|
||||
pub async fn int_list_val(&self, value: Vec<i32>) -> Vec<i32> {
|
||||
value
|
||||
}
|
||||
|
@ -49,7 +47,6 @@ pub async fn test_variable_default_value() {
|
|||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
#[field]
|
||||
pub async fn int_val(&self, value: i32) -> i32 {
|
||||
value
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user