EasyQuery开发笔记 - 抽象语法树

easy query 项目地址: github

按照最开始的目的,easy query期望使用统一的条件查询表达式,来描述查询的条件。以简化企业级项目开发中的查询参数传递问题
比如

// 简单的条件
name = "quitee"
// 复杂的条件
(name = "quitee" and age <= 18) or age > 28

由于这种表达式并不是一个类似json一样的结构化信息,所以不得不需要通过另外一种途径去处理了,也就是通过抽象语法树来实现了

为什么使用抽象语法树

在谈实现之前,还是有必要说明一下

设计上,这个看似是SQL的条件表达式在定义上是个sql没有太大关系,只是在描述一个查询条件
所以在我眼中他不是SQL

预期上,通过对这个表达式的处理。它可以变成mysql的查询,SQL server的查询,甚至是es的查询条件
在这里插入图片描述
所以这不是replace或者正则表达式就能够完成的

且不说这个场景是否需要,对自己也当个是学习了

实现流程

了解了抽象语法树的必要性后,就开始着手对我们的表达式语句进行定义与解析
大体流程如下图
在这里插入图片描述

1. 定义表达式长什么样

先别急着开始码代码

在开始实现语法树以及构造语法树之前,需要定义好我们的表达式是啥,长什么样子

  • 词法:定义的是我们的表达式中,有哪些关键词,关键词都代表了什么
  • 语法:定义了我们表达式是否通顺,表达含义正确

在easy query的词法设计如下

比较操作:
=,!=,>,<,>=,<=,in,not in,contains,startWith,endWith,between,match

逻辑组合操作:
and,or

其他:
由 双引号 "..." 包住的内容为 文本 string类型
非双引号的为特殊类型
number,date,bool,text,NULL 等

语法设计如下,相对不复杂

// 比较语法
<比较字段> <比较操作> <比较操作值>

// 组合语法
<比较语法|组合语法> <and|or> <比较语法|组合语法>

2. 分词

有了上述的定义以后,那么第一步就是对表达式进行一个字符一个字符的扫描

这里借鉴了fastjson的思路

定义对象 QueryLexer ,由它来主要负责分词,并且进行词法分析

QueryLexer::nextToken() // 返回下一个分词结果

在这里插入图片描述

3. 构造语法树

拿到分词结果以后就开始处理语法以及生成语法树了

语法树采用了二叉树的形式表现
在这里插入图片描述
在这里插入图片描述
实现上,设计到了三个关键对象

  • token栈:将未被接收的token压入栈中,以备后续使用
  • 节点栈:将生成的新的节点压入,以备后续使用。最终该栈只有一个节点,即根节点
  • 期望处理器:处理token并且生成节点。目前有处理比较条件和处理and/or条件的两个
3.1 token栈

token栈的引入,能够解决当前token无人认领的时候的尴尬局面

比如 name = "quitee"
首先获取到的token是text类型的name,对于期望处理器来说,还不足以确定是自己的处理范畴,因此会选择忽略,于是这个token就会被入栈/等到 =这个token来了以后,比较处理器 AstNodeBuilderFieldCondition发现这是自己的活,就能从栈中获取到name,并且把它当成比较的字段来处理了

3.2 节点栈

节点栈同token栈一样,当以处理节点为主的期望处理器需要获取到之前处理过的节点时,则从中获取上一个节点

3.3 期望处理器

期望处理器是一个一个处理token,生成节点的处理器
同时还要告诉构造器,下一个token期望由哪些处理器来处理

比如 处理name = "quitee"比较处理器 AstNodeBuilderFieldCondition的下一个期望就不会再是比较处理器 AstNodeBuilderFieldCondition

name = "quitee" age < 10  // 不是我们定下的语法

// 我们期望的语法如下
name = "quitee" and age <10
(name = "quitee")
name = "quitee"
(... and name = "quitee")

最终,就能将表达式,转化成结构化的树结构。为我们后续转成sql,dsl query等等都打下了基础
在这里插入图片描述

拓展

由于词法是我们自己解析的,因此在代码编写合适的情况下,我们可以拓展出很多新的花样

1. 自定义token关键词

我们可以将token类型添加别名,比如下面的配置
在这里插入图片描述
结果同样可以解析成功
在这里插入图片描述

2. 遍历

由于生成了树结构,那么我们就可以通过常用的遍历手段来进行遍历

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值