Skip to content

Commit a0d8140

Browse files
authored
Merge pull request #460 from domaframework/feature/sql-annotation-file-bulk-convert
Batch Conversion Action Between Sql Annotations and SQL Files
2 parents 5003141 + 705efd0 commit a0d8140

File tree

48 files changed

+1213
-260
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1213
-260
lines changed
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* Copyright Doma Tools Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.domaframework.doma.intellij.action.dao
17+
18+
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
19+
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
20+
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
21+
import com.intellij.openapi.command.WriteCommandAction
22+
import com.intellij.openapi.editor.Editor
23+
import com.intellij.openapi.project.Project
24+
import com.intellij.psi.PsiClass
25+
import com.intellij.psi.PsiElement
26+
import com.intellij.psi.PsiFile
27+
import com.intellij.psi.PsiMethod
28+
import org.domaframework.doma.intellij.bundle.MessageBundle
29+
import org.domaframework.doma.intellij.common.dao.getDaoClass
30+
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
31+
import org.domaframework.doma.intellij.common.util.PluginLoggerUtil
32+
33+
/**
34+
* Intention action to convert @Sql annotation to SQL file
35+
*/
36+
class BulkConvertSqlAnnotationToFileAction : PsiElementBaseIntentionAction() {
37+
override fun getFamilyName(): String = MessageBundle.message("bulk.convert.sql.annotation.to.file.family")
38+
39+
override fun getText(): String = MessageBundle.message("bulk.convert.sql.annotation.to.file.text")
40+
41+
override fun isAvailable(
42+
project: Project,
43+
editor: Editor?,
44+
element: PsiElement,
45+
): Boolean {
46+
val daoClass = findDaoClassElement(element) ?: return false
47+
if (getDaoClass(daoClass.containingFile) == null) return false
48+
49+
val methods = getTargetMethods(daoClass, project)
50+
51+
return methods.isNotEmpty()
52+
}
53+
54+
override fun generatePreview(
55+
project: Project,
56+
editor: Editor,
57+
file: PsiFile,
58+
): IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
59+
60+
override fun invoke(
61+
project: Project,
62+
editor: Editor?,
63+
element: PsiElement,
64+
) {
65+
// Do nothing when previewing
66+
if (IntentionPreviewUtils.isIntentionPreviewActive()) return
67+
val startTime = System.nanoTime()
68+
val daoClass = findDaoClassElement(element) ?: return
69+
// Already checked in isAvailable, should not be null here
70+
check(getDaoClass(daoClass.containingFile) != null) { "DAO class should be available" }
71+
72+
val methods = getTargetMethods(daoClass, project)
73+
74+
if (methods.isEmpty()) return
75+
76+
WriteCommandAction.runWriteCommandAction(project) {
77+
methods.reversed().forEach { method ->
78+
val converter = SqlAnnotationConverter(project, method)
79+
converter.convertToSqlFile()
80+
}
81+
}
82+
83+
PluginLoggerUtil.countLogging(
84+
className = this::class.java.simpleName,
85+
actionName = "convertSqlAnnotationToFileBatch",
86+
inputName = "IntentionAction",
87+
start = startTime,
88+
)
89+
}
90+
91+
private fun getTargetMethods(
92+
daoClass: PsiClass,
93+
project: Project,
94+
): List<PsiMethod> =
95+
daoClass.methods.filter { method ->
96+
val isSupportedDaoMethod = SqlAnnotationConverter.supportedTypes.any { it.getPsiAnnotation(method) != null }
97+
val psiDaoMethod = PsiDaoMethod(project, method)
98+
val isSqlAnnotationUsed = psiDaoMethod.useSqlAnnotation()
99+
val hasSqlFileWithParent = psiDaoMethod.sqlFile?.parent != null
100+
101+
isSqlAnnotationUsed && !hasSqlFileWithParent && isSupportedDaoMethod
102+
}
103+
104+
private fun findDaoClassElement(element: PsiElement): PsiClass? = element as? PsiClass ?: element.parent as? PsiClass
105+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Copyright Doma Tools Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.domaframework.doma.intellij.action.dao
17+
18+
import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction
19+
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
20+
import com.intellij.codeInsight.intention.preview.IntentionPreviewUtils
21+
import com.intellij.openapi.command.WriteCommandAction
22+
import com.intellij.openapi.editor.Editor
23+
import com.intellij.openapi.project.Project
24+
import com.intellij.psi.PsiClass
25+
import com.intellij.psi.PsiElement
26+
import com.intellij.psi.PsiFile
27+
import com.intellij.psi.PsiMethod
28+
import org.domaframework.doma.intellij.bundle.MessageBundle
29+
import org.domaframework.doma.intellij.common.dao.getDaoClass
30+
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
31+
import org.domaframework.doma.intellij.common.util.PluginLoggerUtil
32+
33+
/**
34+
* Intention action to convert SQL file to @Sql annotation
35+
*/
36+
class BulkConvertSqlFileToAnnotationAction : PsiElementBaseIntentionAction() {
37+
override fun getFamilyName(): String = MessageBundle.message("bulk.convert.sql.file.to.annotation.family")
38+
39+
override fun getText(): String = MessageBundle.message("bulk.convert.sql.file.to.annotation.text")
40+
41+
override fun isAvailable(
42+
project: Project,
43+
editor: Editor?,
44+
element: PsiElement,
45+
): Boolean {
46+
val daoClass = findDaoClassElement(element) ?: return false
47+
if (getDaoClass(daoClass.containingFile) == null) return false
48+
49+
val methods = getTargetMethods(daoClass, project)
50+
51+
return methods.isNotEmpty()
52+
}
53+
54+
override fun generatePreview(
55+
project: Project,
56+
editor: Editor,
57+
file: PsiFile,
58+
): IntentionPreviewInfo = IntentionPreviewInfo.EMPTY
59+
60+
override fun invoke(
61+
project: Project,
62+
editor: Editor?,
63+
element: PsiElement,
64+
) {
65+
// Do nothing when previewing
66+
if (IntentionPreviewUtils.isIntentionPreviewActive()) return
67+
val startTime = System.nanoTime()
68+
val daoClass = findDaoClassElement(element) ?: return
69+
// Already checked in isAvailable, should not be null here
70+
check(getDaoClass(daoClass.containingFile) != null) { "DAO class should be available" }
71+
72+
val methods = getTargetMethods(daoClass, project)
73+
if (methods.isEmpty()) return
74+
75+
WriteCommandAction.runWriteCommandAction(project) {
76+
methods.reversed().forEach { method ->
77+
val converter = SqlAnnotationConverter(project, method)
78+
converter.convertToSqlAnnotation()
79+
}
80+
}
81+
82+
PluginLoggerUtil.countLogging(
83+
className = this::class.java.simpleName,
84+
actionName = "convertSqlFileToAnnotationBatch",
85+
inputName = "IntentionAction",
86+
start = startTime,
87+
)
88+
}
89+
90+
private fun getTargetMethods(
91+
daoClass: PsiClass,
92+
project: Project,
93+
): List<PsiMethod> =
94+
daoClass.methods.filter { method ->
95+
val isSupportedDaoMethod = SqlAnnotationConverter.supportedTypes.any { it.getPsiAnnotation(method) != null }
96+
val psiDaoMethod = PsiDaoMethod(project, method)
97+
val isSqlAnnotationUsed = psiDaoMethod.useSqlAnnotation()
98+
val hasSqlFileWithParent = psiDaoMethod.sqlFile?.parent != null
99+
100+
// For SQL file to annotation conversion, we need:
101+
// - SQL file exists
102+
// - @Sql annotation is NOT used
103+
!isSqlAnnotationUsed && hasSqlFileWithParent && isSupportedDaoMethod
104+
}
105+
106+
private fun findDaoClassElement(element: PsiElement): PsiClass? = element as? PsiClass ?: element.parent as? PsiClass
107+
}

src/main/kotlin/org/domaframework/doma/intellij/action/dao/ConvertSqlAnnotationToFileAction.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ class ConvertSqlAnnotationToFileAction : PsiElementBaseIntentionAction() {
4949
// Check if method has @Sql annotation
5050
// When a Sql annotation is present, a virtual SQL file is associated;
5151
// therefore, check the parent and exclude the injected (inline) SQL.
52-
if (getDaoClass(method.containingFile) == null || !psiDaoMethod.useSqlAnnotation() ||
53-
psiDaoMethod.sqlFile != null && psiDaoMethod.sqlFile?.parent != null
54-
) {
52+
val isDaoClassMissing = getDaoClass(method.containingFile) == null
53+
val isSqlAnnotationNotUsed = !psiDaoMethod.useSqlAnnotation()
54+
val hasSqlFileWithParent = psiDaoMethod.sqlFile != null && psiDaoMethod.sqlFile?.parent != null
55+
if (isDaoClassMissing || isSqlAnnotationNotUsed || hasSqlFileWithParent) {
5556
return false
5657
}
5758

0 commit comments

Comments
 (0)