2020import io .github .linyimin .plugin .component .SqlParamGenerateComponent ;
2121import io .github .linyimin .plugin .configuration .model .MybatisSqlConfiguration ;
2222import io .github .linyimin .plugin .constant .Constant ;
23+ import io .github .linyimin .plugin .pojo2json .DefaultPOJO2JSONParser ;
2324import io .github .linyimin .plugin .pojo2json .RandomPOJO2JSONParser ;
25+ import io .github .linyimin .plugin .sql .checker .Checker ;
26+ import io .github .linyimin .plugin .sql .checker .CheckerHolder ;
27+ import io .github .linyimin .plugin .sql .checker .Report ;
28+ import io .github .linyimin .plugin .sql .checker .enums .CheckScopeEnum ;
29+ import io .github .linyimin .plugin .sql .parser .SqlParser ;
2430import io .github .linyimin .plugin .ui .tree .MethodTreeNode ;
2531import io .github .linyimin .plugin .ui .tree .NamespaceTreeNode ;
2632import io .github .linyimin .plugin .ui .tree .RootTreeNode ;
2733import io .github .linyimin .plugin .ui .tree .TreeListener ;
34+ import io .github .linyimin .plugin .utils .IconUtils ;
35+ import org .apache .commons .collections .CollectionUtils ;
2836import org .fife .ui .rsyntaxtextarea .RSyntaxTextArea ;
2937import org .fife .ui .rtextarea .RTextScrollPane ;
3038import org .jetbrains .annotations .NotNull ;
3139
3240import javax .swing .*;
3341import javax .swing .border .EmptyBorder ;
3442import java .awt .*;
43+ import java .awt .event .ActionEvent ;
44+ import java .util .Arrays ;
3545import java .util .List ;
3646import java .util .Set ;
3747
@@ -67,7 +77,7 @@ public class MybatisSqlScannerPanel implements TabbedChangeListener {
6777 private final InfoPane infoPane ;
6878 private final TreeListener treeListener ;
6979
70- private final RootTreeNode root = new RootTreeNode ("Mybatis Sql" );
80+ private RootTreeNode allRoot = new RootTreeNode (Constant . ROOT_NAME );
7181
7282 private final BackgroundTaskQueue backgroundTaskQueue ;
7383
@@ -118,6 +128,66 @@ private void initRadioButtonGroup() {
118128 this .doesNotMeetSpecRadioButton .addMouseListener (new MouseCursorAdapter (this .doesNotMeetSpecRadioButton ));
119129 this .fullTableScanRadioButton .addMouseListener (new MouseCursorAdapter (this .fullTableScanRadioButton ));
120130
131+ this .allRadioButton .addActionListener (new AbstractAction () {
132+ @ Override
133+ public void actionPerformed (ActionEvent e ) {
134+ if (allRadioButton .isSelected ()) {
135+ backgroundTaskQueue .run (new Task .Backgroundable (project , Constant .APPLICATION_NAME ) {
136+ @ Override
137+ public void run (@ NotNull ProgressIndicator indicator ) {
138+ RootTreeNode root = getRootByType (FilterType .all );
139+ createTree (root );
140+ }
141+ });
142+ }
143+ }
144+ });
145+
146+ this .complianceWithSpecRadioButton .addActionListener (new AbstractAction () {
147+ @ Override
148+ public void actionPerformed (ActionEvent e ) {
149+ if (complianceWithSpecRadioButton .isSelected ()) {
150+ backgroundTaskQueue .run (new Task .Backgroundable (project , Constant .APPLICATION_NAME ) {
151+ @ Override
152+ public void run (@ NotNull ProgressIndicator indicator ) {
153+ RootTreeNode root = getRootByType (FilterType .compliance_spec );
154+ createTree (root );
155+ }
156+ });
157+ }
158+ }
159+ });
160+
161+ this .doesNotMeetSpecRadioButton .addActionListener (new AbstractAction () {
162+ @ Override
163+ public void actionPerformed (ActionEvent e ) {
164+ if (doesNotMeetSpecRadioButton .isSelected ()) {
165+ backgroundTaskQueue .run (new Task .Backgroundable (project , Constant .APPLICATION_NAME ) {
166+ @ Override
167+ public void run (@ NotNull ProgressIndicator indicator ) {
168+ RootTreeNode root = getRootByType (FilterType .not_meet_spec );
169+ createTree (root );
170+ }
171+ });
172+ }
173+ }
174+ });
175+
176+ this .fullTableScanRadioButton .addActionListener (new AbstractAction () {
177+ @ Override
178+ public void actionPerformed (ActionEvent e ) {
179+ if (fullTableScanRadioButton .isSelected ()) {
180+ backgroundTaskQueue .run (new Task .Backgroundable (project , Constant .APPLICATION_NAME ) {
181+ @ Override
182+ public void run (@ NotNull ProgressIndicator indicator ) {
183+ RootTreeNode root = getRootByType (FilterType .full_table_scan );
184+ createTree (root );
185+ }
186+ });
187+ }
188+ }
189+ });
190+
121191 }
122192
123193 private void initText () {
@@ -153,7 +223,8 @@ public void run(@NotNull ProgressIndicator indicator) {
153223 scannerResultPanel .add (infoPane .getInfoPane ());
154224 infoPane .setText ("Scan mybatis sql..." );
155225 });
156- createTree ();
226+ allRoot = scanMybatisSql ();
227+ createTree (allRoot );
157228 ApplicationManager .getApplication ().invokeLater (() -> {
158229 scannerResultPanel .remove (infoPane .getInfoPane ());
159230 scannerResultPanel .add (scannerResultContentPanel );
@@ -162,9 +233,41 @@ public void run(@NotNull ProgressIndicator indicator) {
162233 });
163234 }
164235
165- private void createTree () {
236+ private RootTreeNode getRootByType (FilterType filterType ) {
237+ RootTreeNode root = new RootTreeNode (Constant .ROOT_NAME );
238+
239+ SimpleNode [] simpleNodes = allRoot .getChildren ();
240+ if (simpleNodes .length == 0 ) {
241+ return root ;
242+ }
243+ for (SimpleNode node : simpleNodes ) {
244+
245+ SimpleNode [] methodNodes = node .getChildren ();
246+ if (methodNodes .length == 0 ) {
247+ continue ;
248+ }
249+
250+ NamespaceTreeNode namespaceTreeNode = new NamespaceTreeNode (root , node .getName ());
251+ root .add (namespaceTreeNode );
252+
253+ for (SimpleNode methodNode : methodNodes ) {
254+
255+ Icon icon = methodNode .getPresentation ().getIcon (true );
256+
257+ FilterType type = FilterType .resolveByIcon (icon );
166258
167- scanMybatisSql ();
259+ if (filterType == FilterType .all || icon == IconUtils .ERROR_ICON || filterType == type ) {
260+ MethodTreeNode methodTreeNode = new MethodTreeNode (namespaceTreeNode , methodNode .getName (), icon );
261+ methodTreeNode .setMybatisSqlScannerPanel (this ).setConfiguration (((MethodTreeNode )methodNode ).getConfiguration ());
262+ namespaceTreeNode .add (methodTreeNode );
263+ }
264+ }
265+ }
266+
267+ return root ;
268+ }
269+
270+ private void createTree (RootTreeNode root ) {
168271
169272 // 设置 tree structure
170273 SimpleTreeStructure treeStructure = new SimpleTreeStructure .Impl (root );
@@ -198,51 +301,110 @@ private void createTree() {
198301
199302 }
200303
201- private void scanMybatisSql (String namespace ) {
304+ private void scanMybatisSql (RootTreeNode root , String namespace ) {
305+
202306 NamespaceTreeNode namespaceTreeNode = new NamespaceTreeNode (root , namespace );
203307 root .add (namespaceTreeNode );
204308
205309 Set <XmlTag > methods = ApplicationManager .getApplication ().runReadAction ((Computable <Set <XmlTag >>) () -> MybatisXmlContentCache .acquireMethodsByNamespace (project , namespace ));
206310
207311 for (XmlTag method : methods ) {
208312 ProcessResult <MybatisSqlConfiguration > result = ApplicationManager .getApplication ().runReadAction (
209- (Computable <ProcessResult <MybatisSqlConfiguration >>) () -> SqlParamGenerateComponent .generate (method .getFirstChild (), new RandomPOJO2JSONParser (), false )
313+ (Computable <ProcessResult <MybatisSqlConfiguration >>) () -> SqlParamGenerateComponent .generate (method .getFirstChild (), new DefaultPOJO2JSONParser (), false )
210314 );
315+
316+ MybatisSqlConfiguration configuration = result .getData ();
317+
318+ MethodTreeNode methodTreeNode ;
319+
211320 if (result .isSuccess ()) {
212- MybatisSqlConfiguration configuration = result .getData ();
213- MethodTreeNode methodTreeNode = new MethodTreeNode (namespaceTreeNode , configuration .getMethod ());
214- methodTreeNode .setMybatisSqlScannerPanel (this ).setConfiguration (configuration );
215- namespaceTreeNode .add (methodTreeNode );
216321
217322 ProcessResult <String > sqlResult = ApplicationManager .getApplication ().runReadAction ((Computable <ProcessResult <String >>) () -> SqlParamGenerateComponent .generateSql (project , configuration .getMethod (), configuration .getParams (), false ));
218323
219324 if (sqlResult .isSuccess ()) {
220325 configuration .setRawSql (sqlResult .getData ());
326+ Icon icon = sqlCheck (sqlResult .getData ());
327+ methodTreeNode = new MethodTreeNode (namespaceTreeNode , configuration .getMethod (), icon );
328+
221329 } else {
222- // TODO: 无法生成错误提示
330+ methodTreeNode = new MethodTreeNode ( namespaceTreeNode , configuration . getMethod (), IconUtils . ERROR_ICON );
223331 }
224332
225333 } else {
226- // TODO: 无法生成错误提示
334+ methodTreeNode = new MethodTreeNode (namespaceTreeNode , configuration .getMethod (), IconUtils .ERROR_ICON );
335+ }
336+ methodTreeNode .setMybatisSqlScannerPanel (this ).setConfiguration (configuration );
337+ namespaceTreeNode .add (methodTreeNode );
338+ }
339+ }
340+
341+ private Icon sqlCheck (String sql ) {
342+ try {
343+ // 语法校验
344+ ProcessResult <String > validateResult = SqlParser .validate (sql );
345+
346+ if (!validateResult .isSuccess ()) {
347+ return IconUtils .ERROR_ICON ;
227348 }
228349
350+ // 索引检查
351+ ProcessResult <Boolean > indexCheckResult = checkIndex (sql );
352+ if (!indexCheckResult .isSuccess ()) {
353+ return IconUtils .ERROR_ICON ;
354+ }
355+
356+ if (!indexCheckResult .getData ()) {
357+ return IconUtils .CRITICAL_ICON ;
358+ }
359+
360+ ProcessResult <Boolean > ruleCheckResult = checkRule (sql );
361+ if (!ruleCheckResult .isSuccess ()) {
362+ return IconUtils .ERROR_ICON ;
363+ }
364+
365+ if (!ruleCheckResult .getData ()) {
366+ return IconUtils .BLOCKED_ICON ;
367+ }
368+
369+ return IconUtils .MAJOR_ICON ;
370+ } catch (Exception e ) {
371+ return IconUtils .ERROR_ICON ;
229372 }
230373 }
231374
232- private void scanMybatisSql () {
375+ private ProcessResult <Boolean > checkIndex (String sql ) {
376+ // TODO:
377+ return ProcessResult .success (true );
378+ }
379+
380+ private ProcessResult <Boolean > checkRule (String sql ) {
381+
382+ CheckScopeEnum scope = SqlParser .getCheckScope (sql );
383+ Checker checker = CheckerHolder .getChecker (scope );
384+
385+ if (checker == null ) {
386+ return ProcessResult .success (true );
387+ }
388+
389+ List <Report > reports = checker .check (sql );
390+ if (CollectionUtils .isEmpty (reports )) {
391+ return ProcessResult .success (true );
392+ }
393+
394+ boolean meetRule = reports .stream ().allMatch (Report ::isPass );
395+
396+ return ProcessResult .success (meetRule );
397+ }
398+
399+ private RootTreeNode scanMybatisSql () {
400+ RootTreeNode root = new RootTreeNode (Constant .ROOT_NAME );
233401 // mapper 列表节点
234402 List <String > namespaces = ApplicationManager .getApplication ().runReadAction ((Computable <List <String >>) () -> MybatisXmlContentCache .acquireByNamespace (project , true ));
235403 for (String namespace : namespaces ) {
236- scanMybatisSql (namespace );
404+ scanMybatisSql (root , namespace );
237405 }
238- }
239-
240- public JPanel getSqlContentPanel () {
241- return sqlContentPanel ;
242- }
243406
244- public JPanel getSqlPanel () {
245- return sqlPanel ;
407+ return root ;
246408 }
247409
248410 public InfoPane getInfoPane () {
@@ -256,4 +418,22 @@ public JPanel getIndexPanel() {
256418 public JScrollPane getIndexScrollPane () {
257419 return indexScrollPane ;
258420 }
421+
422+ public enum FilterType {
423+
424+ all (null ),
425+ compliance_spec (IconUtils .MAJOR_ICON ),
426+ not_meet_spec (IconUtils .BLOCKED_ICON ),
427+ full_table_scan (IconUtils .CRITICAL_ICON );
428+
429+ private final Icon icon ;
430+
431+ FilterType (Icon icon ) {
432+ this .icon = icon ;
433+ }
434+
435+ public static FilterType resolveByIcon (Icon icon ) {
436+ return Arrays .stream (FilterType .values ()).filter (type -> type .icon == icon ).findFirst ().orElse (FilterType .all );
437+ }
438+ }
259439}
0 commit comments