Skip to content

Commit 32b2eea

Browse files
committed
Support for Dao methods of Batch annotations
1 parent 6cb622a commit 32b2eea

File tree

4 files changed

+89
-38
lines changed

4 files changed

+89
-38
lines changed

src/main/kotlin/org/domaframework/doma/intellij/contributor/sql/provider/SqlParameterCompletionProvider.kt

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.completion.CompletionProvider
2020
import com.intellij.codeInsight.completion.CompletionResultSet
2121
import com.intellij.codeInsight.lookup.LookupElementBuilder
2222
import com.intellij.codeInsight.lookup.VariableLookupItem
23+
import com.intellij.openapi.project.Project
2324
import com.intellij.psi.PsiClass
2425
import com.intellij.psi.PsiDirectory
2526
import com.intellij.psi.PsiElement
@@ -33,6 +34,7 @@ import com.intellij.psi.util.elementType
3334
import com.intellij.psi.util.prevLeafs
3435
import com.intellij.util.ProcessingContext
3536
import org.domaframework.doma.intellij.common.dao.findDaoMethod
37+
import org.domaframework.doma.intellij.common.psi.PsiDaoMethod
3638
import org.domaframework.doma.intellij.common.psi.PsiParentClass
3739
import org.domaframework.doma.intellij.common.psi.PsiPatternUtil
3840
import org.domaframework.doma.intellij.common.sql.PsiClassTypeUtil
@@ -271,66 +273,49 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
271273
originalFile: PsiFile,
272274
result: CompletionResultSet,
273275
) {
276+
val daoMethod = findDaoMethod(originalFile)
274277
val searchText = cleanString(getSearchElementText(position))
275278
var topElementType: PsiType? = null
276-
if (elements.isEmpty()) {
277-
getElementTypeByFieldAccess(originalFile, elements, result)
279+
if (elements.isEmpty() && daoMethod != null) {
280+
getElementTypeByFieldAccess(originalFile, elements, daoMethod, result)
278281
return
279282
}
280283
val top = elements.first()
281-
282284
val topText = cleanString(getSearchElementText(top))
283285
val prevWord = PsiPatternUtil.getBindSearchWord(originalFile, elements.last(), " ")
284286
if (prevWord.startsWith("@") && prevWord.endsWith("@")) {
285-
setStaticFieldAccess(top, prevWord, topText, result)
287+
setCompletionStaticFieldAccess(top, prevWord, topText, result)
286288
return
287289
}
290+
291+
var isBatchAnnotation = false
288292
if (top.parent !is PsiFile && top.parent?.parent !is PsiDirectory) {
289293
val staticDirective = top.findNodeParent(SqlTypes.EL_STATIC_FIELD_ACCESS_EXPR)
290294
staticDirective?.let {
291295
topElementType = getElementTypeByStaticFieldAccess(top, it, topText) ?: return
292296
}
293297
}
294298

299+
if (daoMethod == null) return
300+
val project = originalFile.project
301+
val psiDaoMethod = PsiDaoMethod(project, daoMethod)
295302
if (topElementType == null) {
296-
if (isFieldAccessByForItem(top, elements, searchText, result)) return
303+
isBatchAnnotation = psiDaoMethod.daoType.isBatchAnnotation()
304+
if (isFieldAccessByForItem(top, elements, searchText, isBatchAnnotation, result)) return
297305
topElementType =
298-
getElementTypeByFieldAccess(originalFile, elements, result) ?: return
306+
getElementTypeByFieldAccess(originalFile, elements, daoMethod, result) ?: return
299307
}
300308

301-
var psiParentClass = PsiParentClass(topElementType)
302-
// FieldAccess Completion
303-
ForDirectiveUtil.getFieldAccessLastPropertyClassType(
309+
setCompletionFieldAccess(
310+
topElementType,
311+
originalFile.project,
312+
isBatchAnnotation,
304313
elements,
305-
top.project,
306-
psiParentClass,
307-
shortName = "",
308-
dropLastIndex = 1,
309-
complete = { lastType ->
310-
val searchWord = cleanString(getSearchElementText(position))
311-
setFieldsAndMethodsCompletionResultSet(
312-
lastType.searchField(searchWord)?.toTypedArray() ?: emptyArray(),
313-
lastType.searchMethod(searchWord)?.toTypedArray() ?: emptyArray(),
314-
result,
315-
)
316-
},
314+
searchText,
315+
result,
317316
)
318317
}
319318

320-
private fun setStaticFieldAccess(
321-
top: PsiElement,
322-
prevWord: String,
323-
topText: String,
324-
result: CompletionResultSet,
325-
) {
326-
val clazz = getRefClazz(top) { prevWord.replace("@", "") } ?: return
327-
val matchFields = clazz.searchStaticField(topText)
328-
val matchMethod = clazz.searchStaticMethod(topText)
329-
330-
// When you enter here, it is the top element, so return static fields and methods.
331-
setFieldsAndMethodsCompletionResultSet(matchFields, matchMethod, result)
332-
}
333-
334319
private fun getSearchElementText(elm: PsiElement?): String =
335320
if (elm is SqlElIdExpr || elm.elementType == SqlTypes.EL_IDENTIFIER) {
336321
elm?.text ?: ""
@@ -369,9 +354,9 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
369354
private fun getElementTypeByFieldAccess(
370355
originalFile: PsiFile,
371356
elements: List<PsiElement>,
357+
daoMethod: PsiMethod,
372358
result: CompletionResultSet,
373359
): PsiType? {
374-
val daoMethod = findDaoMethod(originalFile) ?: return null
375360
val topText = cleanString(getSearchElementText(elements.firstOrNull()))
376361
val matchParams = daoMethod.searchParameter(topText)
377362
val findParam = matchParams.find { it.name == topText }
@@ -417,10 +402,10 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
417402
private fun isFieldAccessByForItem(
418403
top: PsiElement,
419404
elements: List<PsiElement>,
420-
positionText: String,
405+
searchWord: String,
406+
isBatchAnnotation: Boolean = false,
421407
result: CompletionResultSet,
422408
): Boolean {
423-
val searchWord = cleanString(positionText)
424409
val project = top.project
425410
val forDirectiveBlocks = ForDirectiveUtil.getForDirectiveBlocks(top)
426411
ForDirectiveUtil.findForItem(top, forDirectives = forDirectiveBlocks) ?: return false
@@ -439,6 +424,7 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
439424
elements,
440425
project,
441426
topClassType,
427+
isBatchAnnotation = isBatchAnnotation,
442428
shortName = "",
443429
dropLastIndex = 1,
444430
complete = { lastType ->
@@ -451,4 +437,46 @@ class SqlParameterCompletionProvider : CompletionProvider<CompletionParameters>(
451437
)
452438
return result is ValidationCompleteResult
453439
}
440+
441+
private fun setCompletionFieldAccess(
442+
topElementType: PsiType,
443+
project: Project,
444+
isBatchAnnotation: Boolean,
445+
elements: List<PsiElement>,
446+
searchWord: String,
447+
result: CompletionResultSet,
448+
) {
449+
var psiParentClass = PsiParentClass(topElementType)
450+
451+
// FieldAccess Completion
452+
ForDirectiveUtil.getFieldAccessLastPropertyClassType(
453+
elements,
454+
project,
455+
psiParentClass,
456+
isBatchAnnotation = isBatchAnnotation,
457+
shortName = "",
458+
dropLastIndex = 1,
459+
complete = { lastType ->
460+
setFieldsAndMethodsCompletionResultSet(
461+
lastType.searchField(searchWord)?.toTypedArray() ?: emptyArray(),
462+
lastType.searchMethod(searchWord)?.toTypedArray() ?: emptyArray(),
463+
result,
464+
)
465+
},
466+
)
467+
}
468+
469+
private fun setCompletionStaticFieldAccess(
470+
top: PsiElement,
471+
prevWord: String,
472+
topText: String,
473+
result: CompletionResultSet,
474+
) {
475+
val clazz = getRefClazz(top) { prevWord.replace("@", "") } ?: return
476+
val matchFields = clazz.searchStaticField(topText)
477+
val matchMethod = clazz.searchStaticMethod(topText)
478+
479+
// When you enter here, it is the top element, so return static fields and methods.
480+
setFieldsAndMethodsCompletionResultSet(matchFields, matchMethod, result)
481+
}
454482
}

src/test/kotlin/org/domaframework/doma/intellij/complate/sql/SqlCompleteTest.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class SqlCompleteTest : DomaSqlTest() {
5656
"$testDapName/completeOptionalDaoParam.sql",
5757
"$testDapName/completeOptionalStaticProperty.sql",
5858
"$testDapName/completeOptionalByForItem.sql",
59+
"$testDapName/completeOptionalBatchAnnotation.sql",
5960
)
6061
myFixture.enableInspections(SqlBindVariableValidInspector())
6162
}
@@ -356,6 +357,14 @@ class SqlCompleteTest : DomaSqlTest() {
356357
)
357358
}
358359

360+
fun testCompleteOptionalBatchAnnotation() {
361+
innerDirectiveCompleteTest(
362+
"$testDapName/completeOptionalBatchAnnotation.sql",
363+
listOf("optionalIds"),
364+
listOf("get()", "orElseGet()", "isPresent()", "projectId"),
365+
)
366+
}
367+
359368
private fun innerDirectiveCompleteTest(
360369
sqlFileName: String,
361370
expectedSuggestions: List<String>,

src/test/testData/src/main/java/doma/example/dao/SqlCompleteTestDao.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,7 @@ interface SqlCompleteTestDao {
9191
@Select
9292
Project completeOptionalByForItem(List<Project> projects);
9393

94+
@BatchDelete(sqlFile = true)
95+
int completeOptionalBatchAnnotation(Optional<List<Optional<Project>>> projects);
96+
9497
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
DELETE FROM project
2+
WHERE rank > 10
3+
-- projects : Optional<List<Optional<Project>>> -> Project
4+
AND id = /* projects.projectId */
5+
-- projects.optionalIds : Optional<List<Optional<Integer>>> -> List<Integer>
6+
/*%for id : projects.<caret>option */
7+
opt_id = /* id */0
8+
/*%if id_has_next */
9+
/*# "OR" */
10+
/*%end */
11+
/*%end */

0 commit comments

Comments
 (0)