use std::future::Future;
use async_graphql::PathSegment;
use itertools::Itertools;
use crate::matchers::MatcherError;
use crate::script::Script;
pub async fn execute_script<F, Fut>(
mut execute_request: F,
script: Script,
) -> Vec<async_graphql::Response>
where
F: FnMut(async_graphql::Request) -> Fut,
Fut: Future<Output = async_graphql::Response>,
{
let requests = script.requests;
let mut acc = Vec::with_capacity(requests.len());
if requests.is_empty() {
panic!("at least one query or mutation must be present");
}
for mut req in requests {
let op = req
.parsed_query()
.unwrap()
.operations
.iter()
.next()
.unwrap()
.1
.clone();
let op_type = op.node.ty;
let op_name = req.operation_name.take().unwrap_or_default();
let failure_causes_panic = op_name.starts_with('_');
let res = execute_request(req).await;
let has_matcher_err = res
.errors
.iter()
.any(|err| err.source::<MatcherError>().is_some());
if res.is_err() && (has_matcher_err || failure_causes_panic) {
if let Some(err) = res.errors.first() {
let path = GraphQLPathSegments(&err.path);
let source = err.source.as_deref();
eprintln!(
"{:?} '{}' ({}) raised an error at line {}\n\n{}\n\nSource:\n{:?}\n",
op_type, op_name, path, err.locations[0], err.message, source,
);
panic!();
}
}
if !failure_causes_panic || acc.len() == 1 {
acc.push(res);
}
}
acc
}
struct GraphQLPathSegments<'a>(&'a [PathSegment]);
impl std::fmt::Display for GraphQLPathSegments<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0
.iter()
.format_with(".", |segment, f| match segment {
PathSegment::Field(name) => f(name),
PathSegment::Index(idx) => f(&format_args!("[{idx}]")),
})
.fmt(f)
}
}