|
21 | 21 | use alloc::{boxed::Box, string::String, vec::Vec}; |
22 | 22 | use core::ops::ControlFlow; |
23 | 23 |
|
24 | | -use crate::ast::{Expr, ObjectName, Query, Select, Statement, TableFactor, ValueWithSpan}; |
| 24 | +use crate::ast::{Expr, Ident, ObjectName, Query, Select, Statement, TableFactor, ValueWithSpan}; |
25 | 25 |
|
26 | 26 | /// A type that can be visited by a [`Visitor`]. See [`Visitor`] for |
27 | 27 | /// recursively visiting parsed SQL statements. |
@@ -269,6 +269,16 @@ pub trait Visitor { |
269 | 269 | fn post_visit_value(&mut self, _value: &ValueWithSpan) -> ControlFlow<Self::Break> { |
270 | 270 | ControlFlow::Continue(()) |
271 | 271 | } |
| 272 | + |
| 273 | + /// Invoked for any identifiers that appear in the AST before visiting children |
| 274 | + fn pre_visit_ident(&mut self, _ident: &Ident) -> ControlFlow<Self::Break> { |
| 275 | + ControlFlow::Continue(()) |
| 276 | + } |
| 277 | + |
| 278 | + /// Invoked for any identifiers that appear in the AST after visiting children |
| 279 | + fn post_visit_ident(&mut self, _ident: &Ident) -> ControlFlow<Self::Break> { |
| 280 | + ControlFlow::Continue(()) |
| 281 | + } |
272 | 282 | } |
273 | 283 |
|
274 | 284 | /// A visitor that can be used to mutate an AST tree. |
@@ -397,6 +407,16 @@ pub trait VisitorMut { |
397 | 407 | fn post_visit_value(&mut self, _value: &mut ValueWithSpan) -> ControlFlow<Self::Break> { |
398 | 408 | ControlFlow::Continue(()) |
399 | 409 | } |
| 410 | + |
| 411 | + /// Invoked for any identifiers that appear in the AST before visiting children |
| 412 | + fn pre_visit_ident(&mut self, _ident: &mut Ident) -> ControlFlow<Self::Break> { |
| 413 | + ControlFlow::Continue(()) |
| 414 | + } |
| 415 | + |
| 416 | + /// Invoked for any identifiers that appear in the AST after visiting children |
| 417 | + fn post_visit_ident(&mut self, _ident: &mut Ident) -> ControlFlow<Self::Break> { |
| 418 | + ControlFlow::Continue(()) |
| 419 | + } |
400 | 420 | } |
401 | 421 |
|
402 | 422 | struct RelationVisitor<F>(F); |
@@ -1014,11 +1034,32 @@ mod tests { |
1014 | 1034 | let flow = s.visit(&mut visitor); |
1015 | 1035 | assert_eq!(flow, ControlFlow::Continue(())); |
1016 | 1036 | } |
| 1037 | + |
| 1038 | + #[derive(Default)] |
| 1039 | + struct IdentVisitor { |
| 1040 | + idents: Vec<String>, |
| 1041 | + } |
| 1042 | + |
| 1043 | + impl Visitor for IdentVisitor { |
| 1044 | + type Break = (); |
| 1045 | + |
| 1046 | + fn pre_visit_ident(&mut self, ident: &Ident) -> ControlFlow<Self::Break> { |
| 1047 | + self.idents.push(ident.value.clone()); |
| 1048 | + ControlFlow::Continue(()) |
| 1049 | + } |
| 1050 | + } |
| 1051 | + |
| 1052 | + #[test] |
| 1053 | + fn test_pre_visit_ident() { |
| 1054 | + let mut visitor = IdentVisitor::default(); |
| 1055 | + do_visit("SELECT a, b FROM t", &mut visitor); |
| 1056 | + assert_eq!(visitor.idents, vec!["a", "b", "t"]); |
| 1057 | + } |
1017 | 1058 | } |
1018 | 1059 |
|
1019 | 1060 | #[cfg(test)] |
1020 | 1061 | mod visit_mut_tests { |
1021 | | - use crate::ast::{Statement, Value, ValueWithSpan, VisitMut, VisitorMut}; |
| 1062 | + use crate::ast::{Ident, Statement, Value, ValueWithSpan, VisitMut, VisitorMut}; |
1022 | 1063 | use crate::dialect::GenericDialect; |
1023 | 1064 | use crate::parser::Parser; |
1024 | 1065 | use crate::tokenizer::Tokenizer; |
@@ -1079,4 +1120,23 @@ mod visit_mut_tests { |
1079 | 1120 | assert_eq!(mutated.to_string(), expected) |
1080 | 1121 | } |
1081 | 1122 | } |
| 1123 | + |
| 1124 | + #[derive(Default)] |
| 1125 | + struct IdentMutator; |
| 1126 | + |
| 1127 | + impl VisitorMut for IdentMutator { |
| 1128 | + type Break = (); |
| 1129 | + |
| 1130 | + fn pre_visit_ident(&mut self, ident: &mut Ident) -> ControlFlow<Self::Break> { |
| 1131 | + ident.value = ident.value.to_uppercase(); |
| 1132 | + ControlFlow::Continue(()) |
| 1133 | + } |
| 1134 | + } |
| 1135 | + |
| 1136 | + #[test] |
| 1137 | + fn test_pre_visit_ident_mut() { |
| 1138 | + let mut visitor = IdentMutator; |
| 1139 | + let mutated = do_visit_mut("SELECT a, b FROM t", &mut visitor); |
| 1140 | + assert_eq!(mutated.to_string(), "SELECT A, B FROM T"); |
| 1141 | + } |
1082 | 1142 | } |
0 commit comments