写在前面
sql格式化,有很多库,比较常用的像sql-formatter ,能满足大部分的需求,却不能满足我的需求。原因是我的sql是动态的,有参数和逻辑判断,试了各种模式,找了很多插件,都不能有效格式化动态sql部分。 下面举一个动态sql的小例子:
select id, name, des
from table_user
where class='601'
#if(${name})
and name = '${name}'
#end
limit 1
这是velocity语法。从上面小例子大家可以看到and name = ${name} 是根据name这个入参是否存在来判断的,入参的写法类似js模版字符串的写法,if判断语句是通过前面加#号来编写的。
这种动态sql使用sql-formatter的标准sql来格式化是这样的:
格式化成这样有四个小问题:
- #号没有换行,影响阅读;
- #和if中间有空格,影响动态sql执行;
- $和{}中间有空格,影响动态sql执行;
- #和end被拆开,影响动态sql执行; 试过其他几种sql模式,都有各种问题,没办法只能来改源码了。
改sql-formatter源码
在编辑器中打开sql-formatter代码,先看目录结构,了解功能分包情况,还比较清晰:
- core文件夹是核心代码
- language文件夹是各种sql语句的不同配置文件
- sqlFormatter.js是库入口文件 这次改动针对标准sql版本进行,也就是languages/StandardSqlFormatter.js文件,可以看到标准sql配置文件里对关键词进行了分类,有一般关键词,有独占一行顶头缩进的关键词,有独占一行顶头不缩进的关键词,还有需要新起一行的关键词,这些都还好理解:
针对前面格式1、2、4问题,则是需要新起一行,而不能独占一行,所以在新起一行关键词中添加动态sql关键词:#if、#elseif、#else、#end即可实现#号换行和#和后面关键词不分离:
// 单起一行
const reservedNewlineWords = [
'AND',
'ELSE',
'OR',
'WHEN',
// joins
'JOIN',
'INNER JOIN',
'LEFT JOIN',
'LEFT OUTER JOIN',
'RIGHT JOIN',
'RIGHT OUTER JOIN',
'FULL JOIN',
'FULL OUTER JOIN',
'CROSS JOIN',
'NATURAL JOIN',
// 新加#ifelse
'#IF',
'#ELSEIF',
'#ELSE',
'#END',
];
另外针对$和{}之间的空格,可以在标准sql配置文件的最后的参数设置部分添加'美元符{'和'}'就好了。
这里主要改的是美元符$和{之间的空格,另外是添加了几个逻辑判断符号,至此格式化动态sql基本逻辑已经实现,唯一美中不足的是#if...#end里的and没有缩进。
结束语
至此四个问题基本解决,遗留一个#if和#end之间的and语句在缩进一格的问题,有知道的朋友请在评论区告知一下,谢谢