async_graphql/extensions/
analyzer.rs1use std::sync::Arc;
2
3use futures_util::lock::Mutex;
4
5use crate::{
6 extensions::{Extension, ExtensionContext, ExtensionFactory, NextRequest, NextValidation},
7 value, Response, ServerError, ValidationResult,
8};
9
10pub struct Analyzer;
15
16impl ExtensionFactory for Analyzer {
17 fn create(&self) -> Arc<dyn Extension> {
18 Arc::new(AnalyzerExtension::default())
19 }
20}
21
22#[derive(Default)]
23struct AnalyzerExtension {
24 validation_result: Mutex<Option<ValidationResult>>,
25}
26
27#[async_trait::async_trait]
28impl Extension for AnalyzerExtension {
29 async fn request(&self, ctx: &ExtensionContext<'_>, next: NextRequest<'_>) -> Response {
30 let mut resp = next.run(ctx).await;
31 let validation_result = self.validation_result.lock().await.take();
32 if let Some(validation_result) = validation_result {
33 resp = resp.extension(
34 "analyzer",
35 value! ({
36 "complexity": validation_result.complexity,
37 "depth": validation_result.depth,
38 }),
39 );
40 }
41 resp
42 }
43
44 async fn validation(
45 &self,
46 ctx: &ExtensionContext<'_>,
47 next: NextValidation<'_>,
48 ) -> Result<ValidationResult, Vec<ServerError>> {
49 let res = next.run(ctx).await?;
50 *self.validation_result.lock().await = Some(res);
51 Ok(res)
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use crate::*;
58
59 struct Query;
60
61 #[derive(Copy, Clone)]
62 struct MyObj;
63
64 #[Object(internal)]
65 impl MyObj {
66 async fn value(&self) -> i32 {
67 1
68 }
69
70 async fn obj(&self) -> MyObj {
71 MyObj
72 }
73 }
74
75 #[Object(internal)]
76 impl Query {
77 async fn value(&self) -> i32 {
78 1
79 }
80
81 async fn obj(&self) -> MyObj {
82 MyObj
83 }
84
85 #[graphql(complexity = "count * child_complexity")]
86 async fn objs(&self, count: usize) -> Vec<MyObj> {
87 vec![MyObj; count]
88 }
89 }
90
91 #[tokio::test]
92 async fn analyzer() {
93 let schema = Schema::build(Query, EmptyMutation, EmptySubscription)
94 .extension(extensions::Analyzer)
95 .finish();
96
97 let res = schema
98 .execute(
99 r#"{
100 value obj {
101 value obj {
102 value
103 }
104 }
105 objs(count: 10) { value }
106 }"#,
107 )
108 .await
109 .into_result()
110 .unwrap()
111 .extensions
112 .remove("analyzer");
113 assert_eq!(
114 res,
115 Some(value!({
116 "complexity": 5 + 10,
117 "depth": 3,
118 }))
119 );
120 }
121}