Skip to main content

async_graphql_test/
script.rs

1use async_graphql::parser::types::{DocumentOperations, ExecutableDocument};
2use itertools::Itertools;
3
4/// A a sequence of several GraphQL queries or mutations.
5///
6/// It can be parsed from a string, then optionally enriched with
7/// [variables][Self::variables] and [executed][crate::execute_script].
8///
9/// Queries and mutations starting with `_` are not returned in the final list
10/// of responses. This is useful for ommiting the feedback from the initial
11/// "populate the DB" boilerplate in the response snapshot.
12#[derive(Debug)]
13pub struct Script {
14    pub(crate) requests: Vec<async_graphql::Request>,
15}
16
17impl From<async_graphql::Request> for Script {
18    fn from(value: async_graphql::Request) -> Self {
19        Self {
20            requests: vec![value],
21        }
22    }
23}
24
25impl From<&str> for Script {
26    fn from(value: &str) -> Self {
27        Self::parse(value)
28    }
29}
30
31impl From<String> for Script {
32    fn from(value: String) -> Self {
33        Self::parse(value.as_str())
34    }
35}
36
37impl Script {
38    /// Set variable values for all inner operations in the [`Script`].
39    pub fn variables(mut self, map: async_graphql::Value) -> Self {
40        for req in self.requests.iter_mut() {
41            req.variables = async_graphql::Variables::from_value(map.clone());
42        }
43        self
44    }
45
46    pub fn upload(mut self, var_path: &str, upload: async_graphql::UploadValue) -> Self {
47        for req in self.requests.iter_mut() {
48            req.set_upload(var_path, upload.try_clone().unwrap())
49        }
50        self
51    }
52
53    fn parse(source_code: &str) -> Self {
54        Self {
55            requests: match async_graphql::parser::parse_query(source_code).unwrap() {
56                doc @ ExecutableDocument {
57                    operations: DocumentOperations::Single(_),
58                    ..
59                } => {
60                    let mut req = async_graphql::Request::new(source_code);
61                    req.set_parsed_query(doc);
62                    [req].into()
63                }
64                ExecutableDocument {
65                    operations: DocumentOperations::Multiple(map),
66                    fragments,
67                } => map
68                    .into_iter()
69                    // preserve the order of inner requests
70                    .sorted_by_key(|(_, def)| def.pos)
71                    .map(|(name, def)| {
72                        let doc = ExecutableDocument {
73                            operations: DocumentOperations::Single(def),
74                            fragments: fragments.clone(),
75                        };
76                        let mut req =
77                            async_graphql::Request::new(source_code).operation_name(&*name);
78                        req.set_parsed_query(doc);
79                        req
80                    })
81                    .collect(),
82            },
83        }
84    }
85}