Add serial
attribute for MergedObject
macro. #539
This commit is contained in:
parent
0ed444654d
commit
5691f6ca71
|
@ -487,6 +487,8 @@ pub struct MergedObject {
|
|||
pub extends: bool,
|
||||
#[darling(default)]
|
||||
pub visible: Option<Visible>,
|
||||
#[darling(default)]
|
||||
pub serial: bool,
|
||||
}
|
||||
|
||||
#[derive(FromField)]
|
||||
|
|
|
@ -55,6 +55,12 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream
|
|||
};
|
||||
|
||||
let visible = visible_fn(&object_args.visible);
|
||||
let resolve_container = if object_args.serial {
|
||||
quote! { #crate_name::resolver_utils::resolve_container_serial(ctx, self).await }
|
||||
} else {
|
||||
quote! { #crate_name::resolver_utils::resolve_container(ctx, self).await }
|
||||
};
|
||||
|
||||
let expanded = quote! {
|
||||
#[allow(clippy::all, clippy::pedantic)]
|
||||
impl #impl_generics #crate_name::Type for #ident #ty_generics #where_clause {
|
||||
|
@ -105,7 +111,7 @@ pub fn generate(object_args: &args::MergedObject) -> GeneratorResult<TokenStream
|
|||
#[#crate_name::async_trait::async_trait]
|
||||
impl #impl_generics #crate_name::OutputType for #ident #ty_generics #where_clause {
|
||||
async fn resolve(&self, ctx: &#crate_name::ContextSelectionSet<'_>, _field: &#crate_name::Positioned<#crate_name::parser::types::Field>) -> #crate_name::ServerResult<#crate_name::Value> {
|
||||
#crate_name::resolver_utils::resolve_container(ctx, self).await
|
||||
#resolve_container
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1104,6 +1104,7 @@ pub use async_graphql_derive::NewType;
|
|||
/// | extends | Add fields to an entity that's defined in another service | bool | Y |
|
||||
/// | visible | If `false`, it will not be displayed in introspection. *[See also the Book](https://async-graphql.github.io/async-graphql/en/visibility.html).* | bool | Y |
|
||||
/// | visible | Call the specified function. If the return value is `false`, it will not be displayed in introspection. | string | Y |
|
||||
/// | serial | Resolve each field sequentially. | bool | Y |
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
|
|
@ -4,9 +4,8 @@ use indexmap::IndexMap;
|
|||
|
||||
use crate::parser::types::Field;
|
||||
use crate::registry::{MetaType, Registry};
|
||||
use crate::resolver_utils::resolve_container;
|
||||
use crate::{
|
||||
CacheControl, ContainerType, Context, ContextSelectionSet, ObjectType, OutputType, Positioned,
|
||||
CacheControl, ContainerType, Context, ContextSelectionSet, OutputType, Positioned,
|
||||
ServerResult, SimpleObject, Type, Value,
|
||||
};
|
||||
|
||||
|
@ -59,8 +58,8 @@ impl<A: Type, B: Type> Type for MergedObject<A, B> {
|
|||
#[async_trait::async_trait]
|
||||
impl<A, B> ContainerType for MergedObject<A, B>
|
||||
where
|
||||
A: ObjectType,
|
||||
B: ObjectType,
|
||||
A: ContainerType,
|
||||
B: ContainerType,
|
||||
{
|
||||
async fn resolve_field(&self, ctx: &Context<'_>) -> ServerResult<Option<Value>> {
|
||||
match self.0.resolve_field(ctx).await {
|
||||
|
@ -82,25 +81,18 @@ where
|
|||
#[async_trait::async_trait]
|
||||
impl<A, B> OutputType for MergedObject<A, B>
|
||||
where
|
||||
A: ObjectType,
|
||||
B: ObjectType,
|
||||
A: ContainerType,
|
||||
B: ContainerType,
|
||||
{
|
||||
async fn resolve(
|
||||
&self,
|
||||
ctx: &ContextSelectionSet<'_>,
|
||||
_ctx: &ContextSelectionSet<'_>,
|
||||
_field: &Positioned<Field>,
|
||||
) -> ServerResult<Value> {
|
||||
resolve_container(ctx, self).await
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> ObjectType for MergedObject<A, B>
|
||||
where
|
||||
A: ObjectType,
|
||||
B: ObjectType,
|
||||
{
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(SimpleObject, Default)]
|
||||
#[graphql(internal, dummy)]
|
||||
|
|
|
@ -16,45 +16,6 @@ struct Object3 {
|
|||
c: i32,
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_merged_object() {
|
||||
type MyObj =
|
||||
MergedObject<Object1, MergedObject<Object2, MergedObject<Object3, MergedObjectTail>>>;
|
||||
|
||||
struct Query;
|
||||
|
||||
#[Object]
|
||||
impl Query {
|
||||
async fn obj(&self) -> MyObj {
|
||||
MergedObject(
|
||||
Object1 { a: 10 },
|
||||
MergedObject(
|
||||
Object2 { b: 20 },
|
||||
MergedObject(Object3 { c: 30 }, MergedObjectTail),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(
|
||||
MyObj::type_name(),
|
||||
"Object1_Object2_Object3_MergedObjectTail"
|
||||
);
|
||||
|
||||
let schema = Schema::new(Query, EmptyMutation, EmptySubscription);
|
||||
let query = "{ obj { a b c } }";
|
||||
assert_eq!(
|
||||
schema.execute(query).await.into_result().unwrap().data,
|
||||
value!({
|
||||
"obj": {
|
||||
"a": 10,
|
||||
"b": 20,
|
||||
"c": 30,
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_merged_object_macro() {
|
||||
#[derive(MergedObject)]
|
||||
|
|
|
@ -4,7 +4,7 @@ use std::time::Duration;
|
|||
use tokio::sync::Mutex;
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_mutation_execution_order() {
|
||||
pub async fn test_root_mutation_execution_order() {
|
||||
type List = Arc<Mutex<Vec<i32>>>;
|
||||
|
||||
struct QueryRoot;
|
||||
|
@ -38,8 +38,7 @@ pub async fn test_mutation_execution_order() {
|
|||
.data(list.clone())
|
||||
.finish();
|
||||
schema.execute("mutation { append1 append2 }").await;
|
||||
assert_eq!(list.lock().await[0], 1);
|
||||
assert_eq!(list.lock().await[1], 2);
|
||||
assert_eq!(&*list.lock().await, &[1, 2]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -86,7 +85,7 @@ pub async fn test_mutation_fragment() {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_serial() {
|
||||
pub async fn test_serial_object() {
|
||||
type List = Arc<Mutex<Vec<i32>>>;
|
||||
|
||||
struct MyObj;
|
||||
|
@ -129,8 +128,7 @@ pub async fn test_serial() {
|
|||
.data(list.clone())
|
||||
.finish();
|
||||
schema.execute("mutation { obj { append1 append2 } }").await;
|
||||
assert_eq!(list.lock().await[0], 1);
|
||||
assert_eq!(list.lock().await[1], 2);
|
||||
assert_eq!(&*list.lock().await, &[1, 2]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
@ -181,6 +179,75 @@ pub async fn test_serial_simple_object() {
|
|||
.data(list.clone())
|
||||
.finish();
|
||||
schema.execute("mutation { obj { append1 append2 } }").await;
|
||||
assert_eq!(list.lock().await[0], 1);
|
||||
assert_eq!(list.lock().await[1], 2);
|
||||
assert_eq!(&*list.lock().await, &[1, 2]);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
pub async fn test_serial_merged_object() {
|
||||
type List = Arc<Mutex<Vec<i32>>>;
|
||||
|
||||
#[derive(MergedObject)]
|
||||
#[graphql(serial)]
|
||||
struct MyObj(MyObj1, MyObj2);
|
||||
|
||||
struct MyObj1;
|
||||
|
||||
#[Object]
|
||||
impl MyObj1 {
|
||||
async fn append1(&self, ctx: &Context<'_>) -> bool {
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
ctx.data_unchecked::<List>().lock().await.push(1);
|
||||
true
|
||||
}
|
||||
|
||||
async fn append2(&self, ctx: &Context<'_>) -> bool {
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
ctx.data_unchecked::<List>().lock().await.push(2);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct MyObj2;
|
||||
|
||||
#[Object]
|
||||
impl MyObj2 {
|
||||
async fn append3(&self, ctx: &Context<'_>) -> bool {
|
||||
tokio::time::sleep(Duration::from_millis(200)).await;
|
||||
ctx.data_unchecked::<List>().lock().await.push(3);
|
||||
true
|
||||
}
|
||||
|
||||
async fn append4(&self, ctx: &Context<'_>) -> bool {
|
||||
tokio::time::sleep(Duration::from_millis(700)).await;
|
||||
ctx.data_unchecked::<List>().lock().await.push(4);
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
struct QueryRoot;
|
||||
|
||||
#[Object]
|
||||
impl QueryRoot {
|
||||
async fn value(&self) -> i32 {
|
||||
10
|
||||
}
|
||||
}
|
||||
|
||||
struct MutationRoot;
|
||||
|
||||
#[Object]
|
||||
impl MutationRoot {
|
||||
async fn obj(&self) -> MyObj {
|
||||
MyObj(MyObj1, MyObj2)
|
||||
}
|
||||
}
|
||||
|
||||
let list = List::default();
|
||||
let schema = Schema::build(QueryRoot, MutationRoot, EmptySubscription)
|
||||
.data(list.clone())
|
||||
.finish();
|
||||
schema
|
||||
.execute("mutation { obj { append1 append2 append3 append4 } }")
|
||||
.await;
|
||||
assert_eq!(&*list.lock().await, &[1, 2, 3, 4]);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user