graphql_query/visit/mod.rs
1//! # Visiting and Transforming GraphQL ASTs
2//!
3//! The `graphql_query::visit` module contains utilities to traverse and transform GraphQL ASTs.
4//! Mainly, this module exposes two traits relevant to this task:
5//!
6//! - The [Visitor] trait can be used to implement a visitor.
7//! - The [Folder] trait can be used to implement a folder to transform an AST.
8//!
9//! This works via the [`VisitNode`] trait and [`FoldNode`] trait that most AST nodes implement and
10//! where visiting and folding can start.
11//!
12//! Typically, a visitor is used in GraphQL to gain information about the AST and inspect it for
13//! certain features. It may also be used to collect information about the AST before it's
14//! transformed in a second folder step, if a single pass over the AST isn't enough.
15//!
16//! In this example we'll define a visitor that counts all operations in a document:
17//!
18//! ```
19//! use graphql_query::{ast::*, visit::*};
20//!
21//! #[derive(Default)]
22//! struct CountOperations {
23//! operations: usize,
24//! }
25//!
26//! impl<'a> Visitor<'a> for CountOperations {
27//! fn enter_fragment(
28//! &mut self,
29//! _ctx: &mut (),
30//! _fragment: &'a FragmentDefinition<'a>,
31//! _info: &VisitInfo
32//! ) -> VisitFlow {
33//! // We can skip over fragment nodes and never traverse its children,
34//! // since we're only interested in counting operations
35//! VisitFlow::Skip
36//! }
37//!
38//! fn enter_operation(
39//! &mut self,
40//! _ctx: &mut (),
41//! operation: &'a OperationDefinition<'a>,
42//! _info: &VisitInfo
43//! ) -> VisitFlow {
44//! self.operations += 1;
45//! VisitFlow::Next
46//! }
47//! }
48//! ```
49//!
50//! We may then execute this visitor using `Document::visit`,
51//! e.g. `document.visit(&ctx, &mut CountOperations::default())`.
52//!
53//! Of course, it's often necessary to ensure that while the context is mutated inside the visitor,
54//! its results should still later on be made accessible.
55//!
56//! [More information on the Visitor trait](Visitor)
57//!
58//! A folder is very similar but instead receives and returns AST nodes to create a new copy of an
59//! AST while transforming it. A simple folder that changes all names to `"oomph"` may look like
60//! such:
61//!
62//! ```
63//! use graphql_query::{ast::*, visit::*};
64//!
65//! #[derive(Default)]
66//! struct OomphRename {}
67//!
68//! impl<'a> SimpleFolder<'a> for OomphRename {
69//! fn named_type(&mut self, _name: NamedType<'a>) -> NamedType<'a> {
70//! NamedType { name: "oomph" }
71//! }
72//! }
73//! ```
74//!
75//! Which we may then execute using `Document::fold`,
76//! e.g. `document.fold(&ctx, &mut OomphRename::default()).unwrap()`.
77//!
78//! Notably, we've used the [`SimpleFolder`] trait in this example, since it allows us to write less
79//! code than with the [Folder] trait when a folder is really straightforward.
80//!
81//! [More information on the Folder trait](Folder)
82
83mod compose;
84mod folder;
85mod folder_simple;
86mod path;
87mod visitor;
88
89pub use compose::ComposedVisitor;
90pub use folder::*;
91pub use path::*;
92pub use visitor::*;