被sql格式化耽误的一天

2,318 阅读2分钟

写在前面

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来格式化是这样的:

image.png

格式化成这样有四个小问题:

  • #号没有换行,影响阅读;
  • #和if中间有空格,影响动态sql执行;
  • $和{}中间有空格,影响动态sql执行;
  • #和end被拆开,影响动态sql执行; 试过其他几种sql模式,都有各种问题,没办法只能来改源码了。

改sql-formatter源码

在编辑器中打开sql-formatter代码,先看目录结构,了解功能分包情况,还比较清晰:

image.png

  • 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',
];

image.png 另外针对$和{}之间的空格,可以在标准sql配置文件的最后的参数设置部分添加'美元符{'和'}'就好了。

image.png

这里主要改的是美元符$和{之间的空格,另外是添加了几个逻辑判断符号,至此格式化动态sql基本逻辑已经实现,唯一美中不足的是#if...#end里的and没有缩进。

image.png

结束语

至此四个问题基本解决,遗留一个#if和#end之间的and语句在缩进一格的问题,有知道的朋友请在评论区告知一下,谢谢