|
17 | 17 |
|
18 | 18 | //! Recursive visitors for ast Nodes. See [`Visitor`] for more details.
|
19 | 19 |
|
20 |
| -use crate::ast::{Expr, ObjectName, Query, Statement, TableFactor}; |
| 20 | +use crate::ast::{Expr, ObjectName, Query, Statement, TableFactor, Value}; |
21 | 21 | use core::ops::ControlFlow;
|
22 | 22 |
|
23 | 23 | /// A type that can be visited by a [`Visitor`]. See [`Visitor`] for
|
@@ -233,6 +233,16 @@ pub trait Visitor {
|
233 | 233 | fn post_visit_statement(&mut self, _statement: &Statement) -> ControlFlow<Self::Break> {
|
234 | 234 | ControlFlow::Continue(())
|
235 | 235 | }
|
| 236 | + |
| 237 | + /// Invoked for any Value that appear in the AST before visiting children |
| 238 | + fn pre_visit_value(&mut self, _value: &Value) -> ControlFlow<Self::Break> { |
| 239 | + ControlFlow::Continue(()) |
| 240 | + } |
| 241 | + |
| 242 | + /// Invoked for any Value that appear in the AST after visiting children |
| 243 | + fn post_visit_value(&mut self, _value: &Value) -> ControlFlow<Self::Break> { |
| 244 | + ControlFlow::Continue(()) |
| 245 | + } |
236 | 246 | }
|
237 | 247 |
|
238 | 248 | /// A visitor that can be used to mutate an AST tree.
|
@@ -337,6 +347,16 @@ pub trait VisitorMut {
|
337 | 347 | fn post_visit_statement(&mut self, _statement: &mut Statement) -> ControlFlow<Self::Break> {
|
338 | 348 | ControlFlow::Continue(())
|
339 | 349 | }
|
| 350 | + |
| 351 | + /// Invoked for any value that appear in the AST before visiting children |
| 352 | + fn pre_visit_value(&mut self, _value: &mut Value) -> ControlFlow<Self::Break> { |
| 353 | + ControlFlow::Continue(()) |
| 354 | + } |
| 355 | + |
| 356 | + /// Invoked for any statements that appear in the AST after visiting children |
| 357 | + fn post_visit_value(&mut self, _value: &mut Value) -> ControlFlow<Self::Break> { |
| 358 | + ControlFlow::Continue(()) |
| 359 | + } |
340 | 360 | }
|
341 | 361 |
|
342 | 362 | struct RelationVisitor<F>(F);
|
@@ -647,6 +667,7 @@ where
|
647 | 667 | #[cfg(test)]
|
648 | 668 | mod tests {
|
649 | 669 | use super::*;
|
| 670 | + use crate::ast::Statement; |
650 | 671 | use crate::dialect::GenericDialect;
|
651 | 672 | use crate::parser::Parser;
|
652 | 673 | use crate::tokenizer::Tokenizer;
|
@@ -720,17 +741,16 @@ mod tests {
|
720 | 741 | }
|
721 | 742 | }
|
722 | 743 |
|
723 |
| - fn do_visit(sql: &str) -> Vec<String> { |
| 744 | + fn do_visit<V: Visitor>(sql: &str, visitor: &mut V) -> Statement { |
724 | 745 | let dialect = GenericDialect {};
|
725 | 746 | let tokens = Tokenizer::new(&dialect, sql).tokenize().unwrap();
|
726 | 747 | let s = Parser::new(&dialect)
|
727 | 748 | .with_tokens(tokens)
|
728 | 749 | .parse_statement()
|
729 | 750 | .unwrap();
|
730 | 751 |
|
731 |
| - let mut visitor = TestVisitor::default(); |
732 |
| - s.visit(&mut visitor); |
733 |
| - visitor.visited |
| 752 | + s.visit(visitor); |
| 753 | + s |
734 | 754 | }
|
735 | 755 |
|
736 | 756 | #[test]
|
@@ -889,8 +909,9 @@ mod tests {
|
889 | 909 | ),
|
890 | 910 | ];
|
891 | 911 | for (sql, expected) in tests {
|
892 |
| - let actual = do_visit(sql); |
893 |
| - let actual: Vec<_> = actual.iter().map(|x| x.as_str()).collect(); |
| 912 | + let mut visitor = TestVisitor::default(); |
| 913 | + let _ = do_visit(sql, &mut visitor); |
| 914 | + let actual: Vec<_> = visitor.visited.iter().map(|x| x.as_str()).collect(); |
894 | 915 | assert_eq!(actual, expected)
|
895 | 916 | }
|
896 | 917 | }
|
@@ -920,3 +941,67 @@ mod tests {
|
920 | 941 | s.visit(&mut visitor);
|
921 | 942 | }
|
922 | 943 | }
|
| 944 | + |
| 945 | +#[cfg(test)] |
| 946 | +mod visit_mut_tests { |
| 947 | + use crate::ast::{Statement, Value, VisitMut, VisitorMut}; |
| 948 | + use crate::dialect::GenericDialect; |
| 949 | + use crate::parser::Parser; |
| 950 | + use crate::tokenizer::Tokenizer; |
| 951 | + use core::ops::ControlFlow; |
| 952 | + |
| 953 | + #[derive(Default)] |
| 954 | + struct MutatorVisitor { |
| 955 | + index: u64, |
| 956 | + } |
| 957 | + |
| 958 | + impl VisitorMut for MutatorVisitor { |
| 959 | + type Break = (); |
| 960 | + |
| 961 | + fn pre_visit_value(&mut self, value: &mut Value) -> ControlFlow<Self::Break> { |
| 962 | + self.index += 1; |
| 963 | + *value = Value::SingleQuotedString(format!("REDACTED_{}", self.index)); |
| 964 | + ControlFlow::Continue(()) |
| 965 | + } |
| 966 | + |
| 967 | + fn post_visit_value(&mut self, _value: &mut Value) -> ControlFlow<Self::Break> { |
| 968 | + ControlFlow::Continue(()) |
| 969 | + } |
| 970 | + } |
| 971 | + |
| 972 | + fn do_visit_mut<V: VisitorMut>(sql: &str, visitor: &mut V) -> Statement { |
| 973 | + let dialect = GenericDialect {}; |
| 974 | + let tokens = Tokenizer::new(&dialect, sql).tokenize().unwrap(); |
| 975 | + let mut s = Parser::new(&dialect) |
| 976 | + .with_tokens(tokens) |
| 977 | + .parse_statement() |
| 978 | + .unwrap(); |
| 979 | + |
| 980 | + s.visit(visitor); |
| 981 | + s |
| 982 | + } |
| 983 | + |
| 984 | + #[test] |
| 985 | + fn test_value_redact() { |
| 986 | + let tests = vec![ |
| 987 | + ( |
| 988 | + concat!( |
| 989 | + "SELECT * FROM monthly_sales ", |
| 990 | + "PIVOT(SUM(a.amount) FOR a.MONTH IN ('JAN', 'FEB', 'MAR', 'APR')) AS p (c, d) ", |
| 991 | + "ORDER BY EMPID" |
| 992 | + ), |
| 993 | + concat!( |
| 994 | + "SELECT * FROM monthly_sales ", |
| 995 | + "PIVOT(SUM(a.amount) FOR a.MONTH IN ('REDACTED_1', 'REDACTED_2', 'REDACTED_3', 'REDACTED_4')) AS p (c, d) ", |
| 996 | + "ORDER BY EMPID" |
| 997 | + ), |
| 998 | + ), |
| 999 | + ]; |
| 1000 | + |
| 1001 | + for (sql, expected) in tests { |
| 1002 | + let mut visitor = MutatorVisitor::default(); |
| 1003 | + let mutated = do_visit_mut(sql, &mut visitor); |
| 1004 | + assert_eq!(mutated.to_string(), expected) |
| 1005 | + } |
| 1006 | + } |
| 1007 | +} |
0 commit comments