2021-03-25 08:33:11 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
use async_graphql::extensions::{
|
2021-04-05 04:21:02 +00:00
|
|
|
Extension, ExtensionContext, ExtensionFactory, NextExecute, NextParseQuery, NextPrepareRequest,
|
|
|
|
NextRequest, NextResolve, NextSubscribe, NextValidation, ResolveInfo,
|
2021-04-04 04:05:54 +00:00
|
|
|
};
|
|
|
|
use async_graphql::futures_util::stream::BoxStream;
|
2021-03-25 08:33:11 +00:00
|
|
|
use async_graphql::parser::types::ExecutableDocument;
|
2020-10-18 03:24:16 +00:00
|
|
|
use async_graphql::*;
|
2021-03-25 08:33:11 +00:00
|
|
|
use async_graphql_value::ConstValue;
|
2021-04-04 04:05:54 +00:00
|
|
|
use futures_util::lock::Mutex;
|
2021-03-25 08:33:11 +00:00
|
|
|
use futures_util::stream::Stream;
|
|
|
|
use futures_util::StreamExt;
|
2020-10-18 03:24:16 +00:00
|
|
|
|
2021-03-12 04:47:24 +00:00
|
|
|
#[tokio::test]
|
2020-10-18 03:24:16 +00:00
|
|
|
pub async fn test_extension_ctx() {
|
|
|
|
#[derive(Default, Clone)]
|
|
|
|
struct MyData(Arc<Mutex<i32>>);
|
|
|
|
|
|
|
|
struct Query;
|
|
|
|
|
|
|
|
#[Object]
|
|
|
|
impl Query {
|
2021-03-25 08:33:11 +00:00
|
|
|
async fn value(&self, ctx: &Context<'_>) -> i32 {
|
2021-04-04 04:05:54 +00:00
|
|
|
*ctx.data_unchecked::<MyData>().0.lock().await
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Subscription;
|
|
|
|
|
|
|
|
#[Subscription]
|
|
|
|
impl Subscription {
|
|
|
|
async fn value(&self, ctx: &Context<'_>) -> impl Stream<Item = i32> {
|
2021-04-04 04:05:54 +00:00
|
|
|
let data = *ctx.data_unchecked::<MyData>().0.lock().await;
|
2021-03-25 08:33:11 +00:00
|
|
|
futures_util::stream::once(async move { data })
|
2020-10-18 03:24:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MyExtensionImpl;
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
impl Extension for MyExtensionImpl {
|
2021-04-04 04:05:54 +00:00
|
|
|
async fn parse_query(
|
|
|
|
&self,
|
2020-10-18 03:24:16 +00:00
|
|
|
ctx: &ExtensionContext<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
query: &str,
|
|
|
|
variables: &Variables,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextParseQuery<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> ServerResult<ExecutableDocument> {
|
2021-03-25 08:33:11 +00:00
|
|
|
if let Ok(data) = ctx.data::<MyData>() {
|
2021-04-04 04:05:54 +00:00
|
|
|
*data.0.lock().await = 100;
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
2021-04-05 04:21:02 +00:00
|
|
|
next.run(ctx, query, variables).await
|
2020-10-18 03:24:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MyExtension;
|
|
|
|
|
|
|
|
impl ExtensionFactory for MyExtension {
|
2021-04-04 04:05:54 +00:00
|
|
|
fn create(&self) -> Arc<dyn Extension> {
|
|
|
|
Arc::new(MyExtensionImpl)
|
2020-10-18 03:24:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// data in schema
|
|
|
|
{
|
|
|
|
let data = MyData::default();
|
|
|
|
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
|
|
|
|
.data(data.clone())
|
|
|
|
.extension(MyExtension)
|
|
|
|
.finish();
|
2021-03-25 08:33:11 +00:00
|
|
|
assert_eq!(
|
|
|
|
schema
|
|
|
|
.execute("{ value }")
|
|
|
|
.await
|
|
|
|
.into_result()
|
|
|
|
.unwrap()
|
|
|
|
.data,
|
|
|
|
value! ({
|
|
|
|
"value": 100
|
|
|
|
})
|
|
|
|
);
|
2020-10-18 03:24:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// data in request
|
|
|
|
{
|
|
|
|
let data = MyData::default();
|
|
|
|
let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
|
|
|
|
.extension(MyExtension)
|
|
|
|
.finish();
|
|
|
|
|
2021-03-25 08:33:11 +00:00
|
|
|
assert_eq!(
|
|
|
|
schema
|
|
|
|
.execute(Request::new("{ value }").data(data.clone()))
|
|
|
|
.await
|
|
|
|
.into_result()
|
|
|
|
.unwrap()
|
|
|
|
.data,
|
|
|
|
value! ({
|
|
|
|
"value": 100
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// data in session
|
|
|
|
{
|
|
|
|
let schema = Schema::build(Query, EmptyMutation, Subscription)
|
|
|
|
.extension(MyExtension)
|
|
|
|
.finish();
|
|
|
|
|
|
|
|
let mut data = Data::default();
|
|
|
|
data.insert(MyData::default());
|
2021-04-04 04:05:54 +00:00
|
|
|
let mut stream = schema.execute_stream_with_session_data(
|
|
|
|
Request::new("subscription { value }"),
|
|
|
|
Arc::new(data),
|
|
|
|
);
|
2021-03-25 08:33:11 +00:00
|
|
|
assert_eq!(
|
|
|
|
stream.next().await.unwrap().into_result().unwrap().data,
|
|
|
|
value! ({
|
|
|
|
"value": 100
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
pub async fn test_extension_call_order() {
|
|
|
|
struct MyExtensionImpl {
|
|
|
|
calls: Arc<Mutex<Vec<&'static str>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait::async_trait]
|
|
|
|
#[allow(unused_variables)]
|
|
|
|
impl Extension for MyExtensionImpl {
|
2021-04-05 04:21:02 +00:00
|
|
|
async fn request(&self, ctx: &ExtensionContext<'_>, next: NextRequest<'_>) -> Response {
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("request_start");
|
2021-04-05 04:21:02 +00:00
|
|
|
let res = next.run(ctx).await;
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("request_end");
|
|
|
|
res
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
fn subscribe<'s>(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
mut stream: BoxStream<'s, Response>,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextSubscribe<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> BoxStream<'s, Response> {
|
|
|
|
let calls = self.calls.clone();
|
2021-04-05 04:21:02 +00:00
|
|
|
next.run(
|
|
|
|
ctx,
|
|
|
|
Box::pin(async_stream::stream! {
|
|
|
|
calls.lock().await.push("subscribe_start");
|
|
|
|
while let Some(item) = stream.next().await {
|
|
|
|
yield item;
|
|
|
|
}
|
|
|
|
calls.lock().await.push("subscribe_end");
|
|
|
|
}),
|
|
|
|
)
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async fn prepare_request(
|
2021-04-04 04:05:54 +00:00
|
|
|
&self,
|
2021-03-25 08:33:11 +00:00
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
request: Request,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextPrepareRequest<'_>,
|
2021-03-25 08:33:11 +00:00
|
|
|
) -> ServerResult<Request> {
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("prepare_request_start");
|
2021-04-05 04:21:02 +00:00
|
|
|
let res = next.run(ctx, request).await;
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("prepare_request_end");
|
|
|
|
res
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
async fn parse_query(
|
|
|
|
&self,
|
2021-03-25 08:33:11 +00:00
|
|
|
ctx: &ExtensionContext<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
query: &str,
|
2021-03-25 08:33:11 +00:00
|
|
|
variables: &Variables,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextParseQuery<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> ServerResult<ExecutableDocument> {
|
|
|
|
self.calls.lock().await.push("parse_query_start");
|
2021-04-05 04:21:02 +00:00
|
|
|
let res = next.run(ctx, query, variables).await;
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("parse_query_end");
|
|
|
|
res
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
async fn validation(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextValidation<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> Result<ValidationResult, Vec<ServerError>> {
|
|
|
|
self.calls.lock().await.push("validation_start");
|
2021-04-05 04:21:02 +00:00
|
|
|
let res = next.run(ctx).await;
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("validation_end");
|
|
|
|
res
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
|
2021-06-10 02:17:33 +00:00
|
|
|
async fn execute(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
operation_name: Option<&str>,
|
|
|
|
next: NextExecute<'_>,
|
|
|
|
) -> Response {
|
|
|
|
assert_eq!(operation_name, Some("Abc"));
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("execute_start");
|
2021-06-10 02:17:33 +00:00
|
|
|
let res = next.run(ctx, operation_name).await;
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("execute_end");
|
|
|
|
res
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
|
2021-04-04 04:05:54 +00:00
|
|
|
async fn resolve(
|
|
|
|
&self,
|
|
|
|
ctx: &ExtensionContext<'_>,
|
|
|
|
info: ResolveInfo<'_>,
|
2021-04-05 04:21:02 +00:00
|
|
|
next: NextResolve<'_>,
|
2021-04-04 04:05:54 +00:00
|
|
|
) -> ServerResult<Option<ConstValue>> {
|
|
|
|
self.calls.lock().await.push("resolve_start");
|
2021-04-05 04:21:02 +00:00
|
|
|
let res = next.run(ctx, info).await;
|
2021-04-04 04:05:54 +00:00
|
|
|
self.calls.lock().await.push("resolve_end");
|
|
|
|
res
|
2021-03-25 08:33:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct MyExtension {
|
|
|
|
calls: Arc<Mutex<Vec<&'static str>>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ExtensionFactory for MyExtension {
|
2021-04-04 04:05:54 +00:00
|
|
|
fn create(&self) -> Arc<dyn Extension> {
|
|
|
|
Arc::new(MyExtensionImpl {
|
2021-03-25 08:33:11 +00:00
|
|
|
calls: self.calls.clone(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Query;
|
|
|
|
|
|
|
|
#[Object]
|
|
|
|
impl Query {
|
|
|
|
async fn value1(&self) -> i32 {
|
|
|
|
10
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn value2(&self) -> i32 {
|
|
|
|
10
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Subscription;
|
|
|
|
|
|
|
|
#[Subscription]
|
|
|
|
impl Subscription {
|
|
|
|
async fn value(&self) -> impl Stream<Item = i32> {
|
|
|
|
futures_util::stream::iter(vec![1, 2, 3])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let calls: Arc<Mutex<Vec<&'static str>>> = Default::default();
|
|
|
|
let schema = Schema::build(Query, EmptyMutation, Subscription)
|
|
|
|
.extension(MyExtension {
|
|
|
|
calls: calls.clone(),
|
|
|
|
})
|
|
|
|
.finish();
|
|
|
|
let _ = schema
|
2021-06-10 02:17:33 +00:00
|
|
|
.execute("query Abc { value1 value2 }")
|
2020-10-18 03:24:16 +00:00
|
|
|
.await
|
|
|
|
.into_result()
|
|
|
|
.unwrap();
|
2021-04-04 04:05:54 +00:00
|
|
|
let calls = calls.lock().await;
|
2021-03-25 08:33:11 +00:00
|
|
|
assert_eq!(
|
|
|
|
&*calls,
|
|
|
|
&vec![
|
2021-04-04 04:05:54 +00:00
|
|
|
"request_start",
|
|
|
|
"prepare_request_start",
|
|
|
|
"prepare_request_end",
|
|
|
|
"parse_query_start",
|
|
|
|
"parse_query_end",
|
2021-03-25 08:33:11 +00:00
|
|
|
"validation_start",
|
|
|
|
"validation_end",
|
2021-04-04 04:05:54 +00:00
|
|
|
"execute_start",
|
2021-03-25 08:33:11 +00:00
|
|
|
"resolve_start",
|
|
|
|
"resolve_end",
|
|
|
|
"resolve_start",
|
|
|
|
"resolve_end",
|
2021-04-04 04:05:54 +00:00
|
|
|
"execute_end",
|
|
|
|
"request_end",
|
2021-03-25 08:33:11 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let calls: Arc<Mutex<Vec<&'static str>>> = Default::default();
|
|
|
|
let schema = Schema::build(Query, EmptyMutation, Subscription)
|
|
|
|
.extension(MyExtension {
|
|
|
|
calls: calls.clone(),
|
|
|
|
})
|
|
|
|
.finish();
|
2021-06-10 02:17:33 +00:00
|
|
|
let mut stream = schema.execute_stream("subscription Abc { value }");
|
2021-07-31 15:54:16 +00:00
|
|
|
while stream.next().await.is_some() {}
|
2021-04-04 04:05:54 +00:00
|
|
|
let calls = calls.lock().await;
|
2021-03-25 08:33:11 +00:00
|
|
|
assert_eq!(
|
|
|
|
&*calls,
|
|
|
|
&vec![
|
2021-04-04 04:05:54 +00:00
|
|
|
"subscribe_start",
|
|
|
|
"prepare_request_start",
|
|
|
|
"prepare_request_end",
|
|
|
|
"parse_query_start",
|
|
|
|
"parse_query_end",
|
2021-03-25 08:33:11 +00:00
|
|
|
"validation_start",
|
|
|
|
"validation_end",
|
2021-04-04 04:05:54 +00:00
|
|
|
// push 1
|
|
|
|
"execute_start",
|
2021-03-25 08:33:11 +00:00
|
|
|
"resolve_start",
|
|
|
|
"resolve_end",
|
2021-04-04 04:05:54 +00:00
|
|
|
"execute_end",
|
|
|
|
// push 2
|
|
|
|
"execute_start",
|
2021-03-25 08:33:11 +00:00
|
|
|
"resolve_start",
|
|
|
|
"resolve_end",
|
2021-04-04 04:05:54 +00:00
|
|
|
"execute_end",
|
|
|
|
// push 3
|
|
|
|
"execute_start",
|
2021-03-25 08:33:11 +00:00
|
|
|
"resolve_start",
|
|
|
|
"resolve_end",
|
2021-04-04 04:05:54 +00:00
|
|
|
"execute_end",
|
|
|
|
// end
|
|
|
|
"subscribe_end",
|
2021-03-25 08:33:11 +00:00
|
|
|
]
|
|
|
|
);
|
2020-10-18 03:24:16 +00:00
|
|
|
}
|
|
|
|
}
|