Skip to content

Commit cd960ff

Browse files
committed
feat: 2.04 MyBatis *.xml SQL inspection | MyBatis *.xml SQL 实时检查
1 parent fa8e09f commit cd960ff

File tree

13 files changed

+162
-20
lines changed

13 files changed

+162
-20
lines changed

.idea/vcs.xml

Lines changed: 0 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44

55
## [1.0.0]
66

7-
- 2.03 add sql-list.err.md file
7+
- 2.04 MyBatis *.xml SQL inspection
88
- 2.02 ★ Column Relationships PlantUML
99
- 2.01 Copy MyBatis *.xml SQL
1010
- 2.00 ★ Check MyBatis *.xml SQL
1111
- 1.00 Export MyBatis *.xml SQL
1212

1313
# 中文更新日志
1414

15+
- 2.04 MyBatis *.xml SQL 实时检查
1516
- 2.03 增加 sql-list.err.md 文件
1617
- 2.02 ★ 列关系 PlantUML 图
1718
- 2.01 复制 MyBatis *.xml SQL

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pluginGroup = com.github.linwancen.plugin.sql
44
pluginName = sql-list
55
pluginRepositoryUrl = https://github.com/LinWanCen/sql-list
66
# SemVer format -> https://semver.org
7-
pluginVersion = 2.03
7+
pluginVersion = 2.04
88

99
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
1010
pluginSinceBuild = 201

src/main/java/io/github/linwancen/sql/excel/SqlInfoWriter.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io.github.linwancen.sql.bean.SqlInfo;
77
import io.github.linwancen.sql.bean.TableColumn;
88
import io.github.linwancen.util.excel.ExcelUtils;
9+
import io.github.linwancen.util.format.LineFormat;
910
import io.github.linwancen.util.plantuml.PlantUML;
1011
import org.slf4j.Logger;
1112
import org.slf4j.LoggerFactory;
@@ -42,9 +43,13 @@ public SqlInfoWriter(ExcelWriter excelWriter) {
4243
}
4344

4445
public void write(List<SqlInfo> sqlInfo) {
45-
excelWriter.write(sqlInfo, sql);
4646
StringBuilder err = new StringBuilder();
4747
for (SqlInfo info : sqlInfo) {
48+
String sqlStr = info.getSql();
49+
sqlStr = LineFormat.itemsOneLine(sqlStr);
50+
sqlStr = LineFormat.deleteSpaceLine(sqlStr);
51+
info.setSql(sqlStr);
52+
4853
for (TreeMap<String, TableColumn> map : info.getColumnList()) {
4954
for (TableColumn v : map.values()) {
5055
// column table null and one table use it
@@ -71,6 +76,7 @@ public void write(List<SqlInfo> sqlInfo) {
7176

7277
appendErr(info, err);
7378
}
79+
excelWriter.write(sqlInfo, sql);
7480

7581
File file = excelWriter.writeContext().writeWorkbookHolder().getFile();
7682
String path = file.getAbsolutePath();

src/main/java/io/github/linwancen/sql/parser/jsqlparser/JSqlParser.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import io.github.linwancen.sql.bean.SqlInfo;
44
import io.github.linwancen.sql.parser.jsqlparser.statement.StatementVisitor;
55
import io.github.linwancen.sql.parser.log.SqlInfoLog;
6-
import io.github.linwancen.util.PathUtils;
76
import net.sf.jsqlparser.parser.CCJSqlParser;
87
import net.sf.jsqlparser.statement.Statement;
98
import org.slf4j.Logger;
@@ -14,7 +13,10 @@
1413

1514
public class JSqlParser {
1615
private static final Logger LOG = LoggerFactory.getLogger(JSqlParser.class);
17-
public static final Pattern DELETE_PATTERN = Pattern.compile("(?i)(BINARY|(?:ur|sw)$|storageDb[\\s\\S]*)");
16+
public static final Pattern DELETE_PATTERN = Pattern.compile("(?i)((?:ur|sw)$" +
17+
"|BINARY" +
18+
"|storageDb[\\s\\S]*" +
19+
"|\n\n|\r\r|\r\n\r\n)");
1820

1921
public static void parseSQL(SqlInfo sqlInfo) {
2022
parseSQL(sqlInfo, s -> DELETE_PATTERN.matcher(s).replaceAll(""));

src/main/java/io/github/linwancen/sql/parser/mybatis/file/XmlFileParser.java

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
import io.github.linwancen.sql.parser.mybatis.file.sql.SqlParamBuilder;
77
import io.github.linwancen.sql.parser.mybatis.file.sql.XmlChange;
88
import io.github.linwancen.util.PathUtils;
9-
import io.github.linwancen.util.format.LineFormat;
109
import io.github.linwancen.util.git.GitUtils;
1110
import io.github.linwancen.util.xml.JdomUtils;
1211
import org.apache.ibatis.builder.MapperBuilderAssistant;
@@ -27,6 +26,7 @@
2726

2827
import java.io.File;
2928
import java.io.FileInputStream;
29+
import java.io.InputStream;
3030
import java.util.HashMap;
3131
import java.util.List;
3232
import java.util.Map;
@@ -61,7 +61,7 @@ public static XmlFileParser build(Configuration configuration, File file, GitRoo
6161
}
6262
}
6363

64-
private XmlFileParser(FileInputStream fis, Configuration configuration, File file, GitRootInfo gitRootInfo) {
64+
public XmlFileParser(InputStream fis, Configuration configuration, File file, GitRootInfo gitRootInfo) {
6565
this.configuration = configuration;
6666
this.file = file;
6767
if (gitRootInfo != null) {
@@ -185,8 +185,6 @@ public void parserSql(Function<SqlInfo, Boolean> fun) {
185185
sql = sql.trim();
186186
if (!sql.isEmpty()) {
187187
sql = sql.replace("?", "''");
188-
sql = LineFormat.itemsOneLine(sql);
189-
sql = LineFormat.deleteSpaceLine(sql);
190188
sqlInfo.setSql(sql);
191189
}
192190
} catch (Exception e) {

src/main/kotlin/com/github/linwancen/plugin/sql/action/SqlCopy.kt

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@ import com.intellij.openapi.wm.WindowManager
1111
import com.intellij.util.ui.TextTransferable
1212
import io.github.linwancen.sql.parser.mybatis.file.XmlFileParser
1313
import org.apache.ibatis.session.Configuration
14+
import org.slf4j.LoggerFactory
1415
import java.io.File
16+
import java.nio.charset.Charset
1517

1618

1719
open class SqlCopy : CopyAction() {
20+
private val log = LoggerFactory.getLogger(this::class.java)
1821

1922
override fun update(e: AnActionEvent) {
2023
e.presentation.text = I18n.message("sql.copy")
@@ -25,18 +28,30 @@ open class SqlCopy : CopyAction() {
2528
val editor = CommonDataKeys.EDITOR.getData(dataContext) ?: return
2629
val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return
2730
val virtualFile = CommonDataKeys.VIRTUAL_FILE.getData(dataContext) ?: return
31+
val psiFile = CommonDataKeys.PSI_FILE.getData(dataContext) ?: return
2832
object : Task.Backgroundable(project, "Export SQL ") {
2933
override fun run(indicator: ProgressIndicator) {
34+
try {
35+
runTask()
36+
} catch (e: Throwable) {
37+
log.info("SqlCopy catch Throwable but log to record.", e)
38+
}
39+
}
40+
41+
private fun runTask() {
3042
val file = File(virtualFile.canonicalPath ?: return)
31-
val parser = XmlFileParser.build(Configuration(), file, null) ?: return
43+
val inputStream = psiFile.text.byteInputStream(Charset.forName("UTF-8"))
44+
val parser = XmlFileParser(inputStream, Configuration(), file, null)
45+
if (parser.mapper == null) {
46+
return
47+
}
3248
val line = editor.caretModel.logicalPosition.line + 1
3349
parser.parserSqlFragments()
3450
parser.parserSql {
3551
if (it.startLine <= line && line <= it.endLine) {
36-
it.sql?.let { sql ->
37-
CopyPasteManager.getInstance()?.setContents(TextTransferable(sql as CharSequence))
38-
WindowManager.getInstance()?.getStatusBar(project)?.info = "Copy SQL for ${it.fullId}"
39-
}
52+
val text = it.sql ?: it.xmlErr ?: it.sqlErr ?: return@parserSql false
53+
CopyPasteManager.getInstance()?.setContents(TextTransferable(text as CharSequence))
54+
WindowManager.getInstance()?.getStatusBar(project)?.info = "Copy SQL for ${it.fullId}"
4055
false
4156
} else true
4257
}

src/main/kotlin/com/github/linwancen/plugin/sql/action/SqlList.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@ import io.github.linwancen.sql.excel.SqlInfoWriter
1515
import io.github.linwancen.sql.parser.AllParser
1616
import io.github.linwancen.util.excel.ExcelUtils
1717
import io.github.linwancen.util.git.GitUtils
18+
import org.slf4j.LoggerFactory
1819
import java.io.File
1920

2021

2122
open class SqlList : CopyAction() {
23+
private val log = LoggerFactory.getLogger(this::class.java)
2224

2325
override fun update(e: AnActionEvent) {
2426
val files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return
@@ -38,6 +40,14 @@ open class SqlList : CopyAction() {
3840
val files = e.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY) ?: return
3941
object : Task.Backgroundable(project, "Export SQL ") {
4042
override fun run(indicator: ProgressIndicator) {
43+
try {
44+
runTask()
45+
} catch (e: Throwable) {
46+
log.info("SqlCopy catch Throwable but log to record.", e)
47+
}
48+
}
49+
50+
private fun runTask() {
4151
GitUtils.utf8()
4252
if (files.isEmpty()) {
4353
return
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package com.github.linwancen.plugin.sql.inspection
2+
3+
import com.intellij.codeInspection.LocalInspectionTool
4+
import com.intellij.codeInspection.ProblemsHolder
5+
import com.intellij.psi.FileViewProvider
6+
import com.intellij.psi.PsiElementVisitor
7+
import com.intellij.psi.XmlElementVisitor
8+
import com.intellij.psi.xml.XmlFile
9+
import com.intellij.psi.xml.XmlTag
10+
import io.github.linwancen.sql.bean.SqlInfo
11+
import io.github.linwancen.sql.parser.jsqlparser.JSqlParser
12+
import io.github.linwancen.sql.parser.mybatis.file.XmlFileParser
13+
import io.github.linwancen.util.format.LineColumnTip
14+
import org.apache.ibatis.session.Configuration
15+
import org.slf4j.LoggerFactory
16+
import java.io.File
17+
import java.nio.charset.Charset
18+
import java.util.regex.Matcher
19+
20+
class XmlSqlInspection : LocalInspectionTool() {
21+
private val log = LoggerFactory.getLogger(this::class.java)
22+
23+
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
24+
return object : XmlElementVisitor() {
25+
26+
override fun visitXmlFile(xmlFile: XmlFile?) {
27+
try {
28+
visit(xmlFile)
29+
} catch (e: Throwable) {
30+
log.info("XmlSqlInspection.visitXmlFile() catch Throwable but log to record.", e)
31+
}
32+
}
33+
34+
private fun visit(xmlFile: XmlFile?) {
35+
val file = File(xmlFile?.virtualFile?.canonicalPath ?: return)
36+
val inputStream = xmlFile.text.byteInputStream(Charset.forName("UTF-8"))
37+
val parser = XmlFileParser(inputStream, Configuration(), file, null)
38+
if (parser.mapper == null) {
39+
return
40+
}
41+
42+
// build idMap
43+
val idMap = mutableMapOf<String, XmlTag>()
44+
val rootTags = xmlFile.rootTag?.children ?: return
45+
rootTags.forEach {
46+
if (it is XmlTag) {
47+
val id = it.getAttributeValue("id") ?: return@forEach
48+
idMap[id] = it
49+
}
50+
}
51+
52+
// parser and registerProblem
53+
parser.parserSqlFragments()
54+
parser.parserSql {
55+
JSqlParser.parseSQL(it)
56+
val err = it.sqlErr ?: it.xmlErr ?: return@parserSql true
57+
val xmlTag = idMap[it.id]
58+
if (xmlTag != null) {
59+
if (!registeredInChild(err, xmlFile, xmlTag, it)) {
60+
holder.registerProblem(xmlTag, "$err\n\n${it.sql ?: ""}")
61+
}
62+
}
63+
true
64+
}
65+
}
66+
67+
private fun registeredInChild(err: String, xmlFile: XmlFile, xmlTag: XmlTag, it: SqlInfo): Boolean {
68+
val m: Matcher = LineColumnTip.LINE_COLUMN_PATTERN.matcher(err)
69+
if (!m.find()) {
70+
return false
71+
}
72+
val line = m.group(1).toInt()
73+
val column = m.group(2).toInt()
74+
val tagStart = xmlTag.textRange?.startOffset ?: return false
75+
val viewProvider: FileViewProvider = xmlFile.viewProvider
76+
val document = viewProvider.document ?: return false
77+
val tagLine = document.getLineNumber(tagStart)
78+
val startOffset = document.getLineStartOffset(tagLine + line)
79+
val psiElement = viewProvider.findElementAt(startOffset + column - 1) ?: return false
80+
holder.registerProblem(psiElement, "$err\n\n${it.sql ?: ""}")
81+
return true
82+
}
83+
84+
}
85+
}
86+
87+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,17 @@
3131
<add-to-group group-id="ProjectViewPopupMenu" anchor="before" relative-to-action="CompareTwoFiles"/>
3232
</action>
3333
</actions>
34+
35+
<extensions defaultExtensionNs="com.intellij">
36+
<localInspection language="XML"
37+
shortName="XmlSql"
38+
bundle="messages.I18n"
39+
key="inspection.xml.sql.display.name"
40+
groupPath="SqlList"
41+
groupBundle="messages.I18n"
42+
groupKey="inspection.sql.list.group.key"
43+
enabledByDefault="true"
44+
level="WARNING"
45+
implementationClass="com.github.linwancen.plugin.sql.inspection.XmlSqlInspection"/>
46+
</extensions>
3447
</idea-plugin>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<html lang="en">
2+
<body>
3+
MyBatis.xml SQL have error or JSqlParser not Support this.<br>
4+
<!-- tooltip end -->
5+
<br>
6+
<br>
7+
</body>
8+
</html>

src/main/resources/messages/I18n.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ sql.diff=Export MyBaits *.xml Diff SQL
33
sql.copy=Copy MyBaits *.xml SQL
44
sql.list.git=Export MyBaits *.xml SQL With Git Author. Slow!
55
sql.diff.git=Export MyBaits *.xml Diff SQL With Git Author. Slow!
6+
7+
inspection.sql.list.group.key=XmlSql
8+
9+
inspection.xml.sql.display.name=Xml SQL Err

src/main/resources/messages/I18n_zh.properties

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,7 @@ sql.diff=\u5BFC\u51FA MyBaits *.xml \u5DEE\u5F02\u7684 SQL
33
sql.copy=\u590D\u5236 MyBaits *.xml \u7684 SQL
44
sql.list.git=\u5BFC\u51FA MyBaits *.xml \u7684 SQL \u5E26 Git \u4F5C\u8005\uFF0C\u6162\uFF01
55
sql.diff.git=\u5BFC\u51FA MyBaits *.xml \u5DEE\u5F02\u7684 SQL \u5E26 Git \u4F5C\u8005\uFF0C\u6162\uFF01
6+
7+
inspection.sql.list.group.key=XmlSql
8+
9+
inspection.xml.sql.display.name=Xml SQL \u95EE\u9898

0 commit comments

Comments
 (0)