Skip to content

Commit 4c77156

Browse files
Add pre_visit_ident/post_visit_ident hooks to Visitor traits
1 parent 0bfafea commit 4c77156

2 files changed

Lines changed: 80 additions & 3 deletions

File tree

src/ast/mod.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ use core::{
3939
#[cfg(feature = "serde")]
4040
use serde::{Deserialize, Serialize};
4141

42+
#[cfg(feature = "visitor")]
43+
use core::ops::ControlFlow;
4244
#[cfg(feature = "visitor")]
4345
use sqlparser_derive::{Visit, VisitMut};
4446

@@ -242,7 +244,6 @@ impl<T> DerefMut for Parens<T> {
242244
/// An identifier, decomposed into its value or character data and the quote style.
243245
#[derive(Debug, Clone)]
244246
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
245-
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
246247
pub struct Ident {
247248
/// The value of the identifier without quotes.
248249
pub value: String,
@@ -388,6 +389,22 @@ impl fmt::Display for Ident {
388389
}
389390
}
390391

392+
#[cfg(feature = "visitor")]
393+
impl Visit for Ident {
394+
fn visit<V: Visitor>(&self, visitor: &mut V) -> ControlFlow<V::Break> {
395+
visitor.pre_visit_ident(self)?;
396+
visitor.post_visit_ident(self)
397+
}
398+
}
399+
400+
#[cfg(feature = "visitor")]
401+
impl VisitMut for Ident {
402+
fn visit<V: VisitorMut>(&mut self, visitor: &mut V) -> ControlFlow<V::Break> {
403+
visitor.pre_visit_ident(self)?;
404+
visitor.post_visit_ident(self)
405+
}
406+
}
407+
391408
/// A name of a table, view, custom type, etc., possibly multi-part, i.e. db.schema.obj
392409
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
393410
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]

src/ast/visitor.rs

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
use alloc::{boxed::Box, string::String, vec::Vec};
2222
use core::ops::ControlFlow;
2323

24-
use crate::ast::{Expr, ObjectName, Query, Select, Statement, TableFactor, ValueWithSpan};
24+
use crate::ast::{Expr, Ident, ObjectName, Query, Select, Statement, TableFactor, ValueWithSpan};
2525

2626
/// A type that can be visited by a [`Visitor`]. See [`Visitor`] for
2727
/// recursively visiting parsed SQL statements.
@@ -269,6 +269,16 @@ pub trait Visitor {
269269
fn post_visit_value(&mut self, _value: &ValueWithSpan) -> ControlFlow<Self::Break> {
270270
ControlFlow::Continue(())
271271
}
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+
}
272282
}
273283

274284
/// A visitor that can be used to mutate an AST tree.
@@ -397,6 +407,16 @@ pub trait VisitorMut {
397407
fn post_visit_value(&mut self, _value: &mut ValueWithSpan) -> ControlFlow<Self::Break> {
398408
ControlFlow::Continue(())
399409
}
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+
}
400420
}
401421

402422
struct RelationVisitor<F>(F);
@@ -1014,11 +1034,32 @@ mod tests {
10141034
let flow = s.visit(&mut visitor);
10151035
assert_eq!(flow, ControlFlow::Continue(()));
10161036
}
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+
}
10171058
}
10181059

10191060
#[cfg(test)]
10201061
mod visit_mut_tests {
1021-
use crate::ast::{Statement, Value, ValueWithSpan, VisitMut, VisitorMut};
1062+
use crate::ast::{Ident, Statement, Value, ValueWithSpan, VisitMut, VisitorMut};
10221063
use crate::dialect::GenericDialect;
10231064
use crate::parser::Parser;
10241065
use crate::tokenizer::Tokenizer;
@@ -1079,4 +1120,23 @@ mod visit_mut_tests {
10791120
assert_eq!(mutated.to_string(), expected)
10801121
}
10811122
}
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+
}
10821142
}

0 commit comments

Comments
 (0)