前端用sql-formatter解析含嵌套concat的MyBatis SQL失败求助
解决sql-formatter解析嵌套concat/含trim的concat SQL失败问题
问题根源
sql-formatter默认的语法解析器对嵌套函数(比如concat套concat、concat里嵌trim)的递归处理逻辑有缺陷,再加上MyBatis的#{var}语法需要额外兼容,直接导致解析时抛出Parse error。之前用简单自定义正则只能覆盖单层函数,搞不定嵌套场景。
可行解决办法
1. 扩展sql-formatter的自定义语法规则
通过更精准的规则配置,让解析器支持嵌套函数识别:
import sqlFormatter from 'sql-formatter'; const customConfig = { // 兼容MyBatis的参数语法 paramTypes: [{ regex: /#\{[^}]+\}/g, type: 'parameter' }], // 标记concat、trim为可嵌套的函数 functions: [ { name: 'concat', openParens: '(', closeParens: ')', nested: true }, { name: 'trim', openParens: '(', closeParens: ')', nested: true } ], // 强化括号匹配逻辑,处理嵌套括号 brackets: [ { open: '(', close: ')', escape: false }, { open: "'", close: "'", escape: true } ] }; // 调用格式化 const formattedSql = sqlFormatter.format(yourCompressedSql, { ...customConfig, language: 'mysql' // 替换成你用的数据库方言 });
这个方案直接从解析规则层面解决问题,能覆盖大部分嵌套场景。
2. 预处理SQL再格式化
如果扩展规则还是搞不定,可以用“占位符替换”的迂回手段:
// 预处理:把嵌套的concat/trim换成唯一占位符 function preprocessSql(sql) { // 递归匹配嵌套的concat和trim const nestedFuncRegex = /(concat|trim)\(([^()]+|(?R))*\)/g; const placeholders = []; let processed = sql.replace(nestedFuncRegex, (match) => { const key = `__FUNC_${placeholders.length}__`; placeholders.push({ key, value: match }); return key; }); return { processed, placeholders }; } // 格式化后还原占位符 const { processed, placeholders } = preprocessSql(yourCompressedSql); let formatted = sqlFormatter.format(processed, { paramTypes: [{ regex: /#\{[^}]+\}/g, type: 'parameter' }], language: 'mysql' }); placeholders.forEach(item => { formatted = formatted.replace(new RegExp(item.key, 'g'), item.value); });
这个方法通过把复杂嵌套函数临时“藏起来”,避免解析器出错,格式化完成后再还原,兼容性拉满。
3. 换用更兼容的格式化库
如果sql-formatter的扩展能力实在不够,试试pg-formatter或sqlfmt,这些库对嵌套函数的支持更好,同时配置MyBatis参数兼容:
import pgFormatter from 'pg-formatter'; const formattedSql = pgFormatter.format(yourCompressedSql, { indent: 2, // 让识别器兼容MyBatis的参数语法 extraKeywords: ['#{', '}'] });
验证示例
针对报错的测试SQL:
SELECT * FROM user WHERE name = concat('a', concat('b', trim(' c '))) AND id = #{userId}
用上述方案处理后,能正常输出格式化结果:
SELECT * FROM user WHERE name = concat('a', concat('b', trim(' c '))) AND id = #{userId}
内容的提问来源于stack exchange,提问作者We He
相关产品推荐
相关产品推荐

