Skip to content

Commit 87df09b

Browse files
alambtustvold
andauthored
Improve docs and add examples for Visitor (#778)
* Improve docs and add examples for Visitor * Update src/ast/visitor.rs Co-authored-by: Raphael Taylor-Davies <[email protected]> * Update src/ast/visitor.rs Co-authored-by: Raphael Taylor-Davies <[email protected]> Co-authored-by: Raphael Taylor-Davies <[email protected]>
1 parent fc503e0 commit 87df09b

File tree

1 file changed

+159
-5
lines changed

1 file changed

+159
-5
lines changed

src/ast/visitor.rs

Lines changed: 159 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,22 @@
1010
// See the License for the specific language governing permissions and
1111
// limitations under the License.
1212

13+
//! Recursive visitors for ast Nodes. See [`Visitor`] for more details.
14+
1315
use crate::ast::{Expr, ObjectName, Statement};
1416
use core::ops::ControlFlow;
1517

16-
/// A type that can be visited by a `visitor`
18+
/// A type that can be visited by a [`Visitor`]. See [`Visitor`] for
19+
/// recursively visiting parsed SQL statements.
20+
///
21+
/// # Note
22+
///
23+
/// This trait should be automatically derived for sqlparser AST nodes
24+
/// using the [Visit](sqlparser_derive::Visit) proc macro.
25+
///
26+
/// ```text
27+
/// #[cfg_attr(feature = "visitor", derive(Visit))]
28+
/// ```
1729
pub trait Visit {
1830
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break>;
1931
}
@@ -57,8 +69,70 @@ visit_noop!(u8, u16, u32, u64, i8, i16, i32, i64, char, bool, String);
5769
#[cfg(feature = "bigdecimal")]
5870
visit_noop!(bigdecimal::BigDecimal);
5971

60-
/// A visitor that can be used to walk an AST tree
72+
/// A visitor that can be used to walk an AST tree.
73+
///
74+
/// `previst_` methods are invoked before visiting all children of the
75+
/// node and `postvisit_` methods are invoked after visiting all
76+
/// children of the node.
77+
///
78+
/// # See also
79+
///
80+
/// These methods provide a more concise way of visiting nodes of a certain type:
81+
/// * [visit_relations]
82+
/// * [visit_expressions]
83+
/// * [visit_statements]
84+
///
85+
/// # Example
86+
/// ```
87+
/// # use sqlparser::parser::Parser;
88+
/// # use sqlparser::dialect::GenericDialect;
89+
/// # use sqlparser::ast::{Visit, Visitor, ObjectName, Expr};
90+
/// # use core::ops::ControlFlow;
91+
/// // A structure that records statements and relations
92+
/// #[derive(Default)]
93+
/// struct V {
94+
/// visited: Vec<String>,
95+
/// }
96+
///
97+
/// // Visit relations and exprs before children are visited (depth first walk)
98+
/// // Note you can also visit statements and visit exprs after children have been visitoed
99+
/// impl Visitor for V {
100+
/// type Break = ();
101+
///
102+
/// fn pre_visit_relation(&mut self, relation: &ObjectName) -> ControlFlow<Self::Break> {
103+
/// self.visited.push(format!("PRE: RELATION: {}", relation));
104+
/// ControlFlow::Continue(())
105+
/// }
106+
///
107+
/// fn pre_visit_expr(&mut self, expr: &Expr) -> ControlFlow<Self::Break> {
108+
/// self.visited.push(format!("PRE: EXPR: {}", expr));
109+
/// ControlFlow::Continue(())
110+
/// }
111+
/// }
112+
///
113+
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar)";
114+
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
115+
/// .unwrap();
116+
///
117+
/// // Drive the visitor through the AST
118+
/// let mut visitor = V::default();
119+
/// statements.visit(&mut visitor);
120+
///
121+
/// // The visitor has visited statements and expressions in pre-traversal order
122+
/// let expected : Vec<_> = [
123+
/// "PRE: EXPR: a",
124+
/// "PRE: RELATION: foo",
125+
/// "PRE: EXPR: x IN (SELECT y FROM bar)",
126+
/// "PRE: EXPR: x",
127+
/// "PRE: EXPR: y",
128+
/// "PRE: RELATION: bar",
129+
/// ]
130+
/// .into_iter().map(|s| s.to_string()).collect();
131+
///
132+
/// assert_eq!(visitor.visited, expected);
133+
/// ```
61134
pub trait Visitor {
135+
/// Type returned when the recursion returns early.
62136
type Break;
63137

64138
/// Invoked for any relations (e.g. tables) that appear in the AST before visiting children
@@ -102,7 +176,33 @@ impl<E, F: FnMut(&ObjectName) -> ControlFlow<E>> Visitor for RelationVisitor<F>
102176
}
103177
}
104178

105-
/// Invokes the provided closure on all relations present in v
179+
/// Invokes the provided closure on all relations (e.g. table names) present in `v`
180+
///
181+
/// # Example
182+
/// ```
183+
/// # use sqlparser::parser::Parser;
184+
/// # use sqlparser::dialect::GenericDialect;
185+
/// # use sqlparser::ast::{visit_relations};
186+
/// # use core::ops::ControlFlow;
187+
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar)";
188+
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
189+
/// .unwrap();
190+
///
191+
/// // visit statements, capturing relations (table names)
192+
/// let mut visited = vec![];
193+
/// visit_relations(&statements, |relation| {
194+
/// visited.push(format!("RELATION: {}", relation));
195+
/// ControlFlow::<()>::Continue(())
196+
/// });
197+
///
198+
/// let expected : Vec<_> = [
199+
/// "RELATION: foo",
200+
/// "RELATION: bar",
201+
/// ]
202+
/// .into_iter().map(|s| s.to_string()).collect();
203+
///
204+
/// assert_eq!(visited, expected);
205+
/// ```
106206
pub fn visit_relations<V, E, F>(v: &V, f: F) -> ControlFlow<E>
107207
where
108208
V: Visit,
@@ -123,7 +223,35 @@ impl<E, F: FnMut(&Expr) -> ControlFlow<E>> Visitor for ExprVisitor<F> {
123223
}
124224
}
125225

126-
/// Invokes the provided closure on all expressions present in v
226+
/// Invokes the provided closure on all expressions (e.g. `1 + 2`) present in `v`
227+
///
228+
/// # Example
229+
/// ```
230+
/// # use sqlparser::parser::Parser;
231+
/// # use sqlparser::dialect::GenericDialect;
232+
/// # use sqlparser::ast::{visit_expressions};
233+
/// # use core::ops::ControlFlow;
234+
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar)";
235+
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
236+
/// .unwrap();
237+
///
238+
/// // visit all expressions
239+
/// let mut visited = vec![];
240+
/// visit_expressions(&statements, |expr| {
241+
/// visited.push(format!("EXPR: {}", expr));
242+
/// ControlFlow::<()>::Continue(())
243+
/// });
244+
///
245+
/// let expected : Vec<_> = [
246+
/// "EXPR: a",
247+
/// "EXPR: x IN (SELECT y FROM bar)",
248+
/// "EXPR: x",
249+
/// "EXPR: y",
250+
/// ]
251+
/// .into_iter().map(|s| s.to_string()).collect();
252+
///
253+
/// assert_eq!(visited, expected);
254+
/// ```
127255
pub fn visit_expressions<V, E, F>(v: &V, f: F) -> ControlFlow<E>
128256
where
129257
V: Visit,
@@ -144,7 +272,33 @@ impl<E, F: FnMut(&Statement) -> ControlFlow<E>> Visitor for StatementVisitor<F>
144272
}
145273
}
146274

147-
/// Invokes the provided closure on all statements present in v
275+
/// Invokes the provided closure on all statements (e.g. `SELECT`, `CREATE TABLE`, etc) present in `v`
276+
///
277+
/// # Example
278+
/// ```
279+
/// # use sqlparser::parser::Parser;
280+
/// # use sqlparser::dialect::GenericDialect;
281+
/// # use sqlparser::ast::{visit_statements};
282+
/// # use core::ops::ControlFlow;
283+
/// let sql = "SELECT a FROM foo where x IN (SELECT y FROM bar); CREATE TABLE baz(q int)";
284+
/// let statements = Parser::parse_sql(&GenericDialect{}, sql)
285+
/// .unwrap();
286+
///
287+
/// // visit all statements
288+
/// let mut visited = vec![];
289+
/// visit_statements(&statements, |stmt| {
290+
/// visited.push(format!("STATEMENT: {}", stmt));
291+
/// ControlFlow::<()>::Continue(())
292+
/// });
293+
///
294+
/// let expected : Vec<_> = [
295+
/// "STATEMENT: SELECT a FROM foo WHERE x IN (SELECT y FROM bar)",
296+
/// "STATEMENT: CREATE TABLE baz (q INT)"
297+
/// ]
298+
/// .into_iter().map(|s| s.to_string()).collect();
299+
///
300+
/// assert_eq!(visited, expected);
301+
/// ```
148302
pub fn visit_statements<V, E, F>(v: &V, f: F) -> ControlFlow<E>
149303
where
150304
V: Visit,

0 commit comments

Comments
 (0)