-
Notifications
You must be signed in to change notification settings - Fork 27
Open
Description
- druid中关于遍历AST的逻辑,访问器只需要编写访问哪块数据结构的代码即可,不直接负责接下来是否继续递归的逻辑(是由 SQLObject 子类负责,主要指 accept方法 的调用,这块逻辑算是重复逻辑,总不能每编写一种访问器就要再次重复编写这个递归逻辑吧,顶多访问器的visit方法返回布尔值来决定是否继续),降低了心智负担
public abstract class SQLObjectImpl implements SQLObject {
public final void accept(SQLASTVisitor visitor) {
if (visitor == null) {
throw new IllegalArgumentException();
}
visitor.preVisit(this);
// 由子类负责
accept0(visitor);
visitor.postVisit(this);
}
}
// 其中一个子类
public class SQLSelect extends SQLObjectImpl {
protected void accept0(SQLASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, this.withSubQuery);
acceptChild(visitor, this.query);
acceptChild(visitor, this.restriction);
acceptChild(visitor, this.orderBy);
acceptChild(visitor, this.hints);
acceptChild(visitor, this.offset);
acceptChild(visitor, this.rowCount);
}
visitor.endVisit(this);
}
}
// 我实现的访问器的时候,只需要 关注数据类型,不需要关注方法名(统一用visit)
// 方法名+数据类型 已经语义明确的告知要访问那块数据类型,不需要在方法名中再重复说明了
public interface SQLASTVisitor {
boolean visit(SQLAllColumnExpr x);
boolean visit(SQLBetweenExpr x);
boolean visit(SQLBinaryOpExpr x);
boolean visit(SQLCaseExpr x);
boolean visit(SQLCaseExpr.Item x);
boolean visit(SQLCaseStatement x);
}-
目前该解析器需要开发者自己在编写的访问器中处理递归逻辑转发,那就需要对数据结构很清晰,但对于刚接触该项目的人来说,很难了解这么清楚,就怕作者在时间长了之后也不一定记得住这么多数据结构类型
-
希望作者能将是否继续遍历语法树的逻辑迁移到 SqlExpression
-
额外说明下,我首次编写SqlParser.Net语法树访问器的尴尬点(下面自定义访问器的中VisitSqlSelectQueryExpression方法的代码注释)
[Test]
public void TestVisitor()
{
string sql = "select * from test where id = 1";
SqlExpression sqlExpression = DbUtils.Parse(sql, DbType.Oracle);
sqlExpression.Accept(new CustomVisitor());
}
// 自定义访问器
public class CustomVisitor : BaseAstVisitor
{
// 我以为只要重写这个方法,就能访问到这里,结果并不是,然后我去看了 UnitTestAstVisitor的源码,才发现需要自己去编写 accept 的访问逻辑
public override void VisitSqlSelectQueryExpression(SqlSelectQueryExpression sqlSelectQueryExpression)
{
Console.WriteLine();
}
}Metadata
Metadata
Assignees
Labels
No labels