graphql_query/validate/context.rs
1use bumpalo::collections::Vec;
2use bumpalo::Bump;
3
4use crate::error::Error;
5use crate::{ast::ASTContext, error::ErrorType};
6
7/// The `ValidationContext` carrying a reference to the AST Context's arena and a list of errors.
8///
9/// New errors are added to the list as validation continues to issue error messages if validation
10/// has failed on a document.
11pub struct ValidationContext<'a> {
12 pub arena: &'a Bump,
13 pub errors: Vec<'a, &'a str>,
14}
15
16impl<'a> ValidationContext<'a> {
17 /// Create a new `ValidationContext` given an AST Context.
18 pub fn new(ctx: &'a ASTContext) -> Self {
19 ValidationContext {
20 arena: &ctx.arena,
21 errors: Vec::new_in(&ctx.arena),
22 }
23 }
24
25 /// Add an error to the list of errors in the `ValidationContext`.
26 ///
27 /// This is called inside of validation rules to add an error to the list and fail validation
28 /// of the currently validating document.
29 pub fn add_error<S: AsRef<str>>(&mut self, str: S) {
30 self.errors.push(self.arena.alloc_str(str.as_ref()));
31 }
32
33 /// Convert the context into a result which carries an error if validation has failed on the
34 /// current document.
35 ///
36 /// This is used by `ValidateNode` and the `ValidationRule`'s `validate` method to convert the
37 /// context into a result.
38 pub fn to_result(self) -> Result<(), Error> {
39 if self.errors.is_empty() {
40 Ok(())
41 } else {
42 let mut context = String::new();
43 let mut is_first = true;
44 for error in self.errors {
45 if is_first {
46 is_first = false;
47 } else {
48 context.push('\n');
49 }
50 context.push_str("- ");
51 context.push_str(error.as_ref());
52 }
53 Err(Error::new_with_context(
54 "Document failed validation",
55 None,
56 &context,
57 Some(ErrorType::GraphQL),
58 ))
59 }
60 }
61}