Skip to content

Commit 7a24889

Browse files
committed
Refactor SQL formatting logic to enhance handling of nested condition loops and improve spacing for various SQL constructs
1 parent a42e91b commit 7a24889

File tree

9 files changed

+112
-49
lines changed

9 files changed

+112
-49
lines changed

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlBlock.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ import com.intellij.formatting.Wrap
2525
import com.intellij.lang.ASTNode
2626
import com.intellij.psi.formatter.common.AbstractBlock
2727
import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock
28+
import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock
2829
import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock
2930
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
3031
import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock
32+
import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock
3133
import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder
3234
import org.domaframework.doma.intellij.formatter.util.IndentType
35+
import org.domaframework.doma.intellij.formatter.util.SqlKeywordUtil
3336
import org.domaframework.doma.intellij.psi.SqlTypes
3437

3538
open class SqlBlock(
@@ -129,6 +132,16 @@ open class SqlBlock(
129132
(prevBlock.conditionType.isElse() || prevBlock.conditionType.isEnd()) ||
130133
parent.childBlocks.dropLast(1).isEmpty()
131134
}
135+
if (parent is SqlNewGroupBlock) {
136+
val prevWord = prevBlocks.lastOrNull { it !is SqlCommentBlock }
137+
if (SqlKeywordUtil.isSetLineKeyword(getNodeText(), parent.getNodeText()) ||
138+
SqlKeywordUtil.isSetLineKeyword(getNodeText(), prevWord?.getNodeText() ?: "")
139+
) {
140+
return false
141+
}
142+
return childBlocks.lastOrNull() is SqlElConditionLoopCommentBlock ||
143+
prevBlocks.lastOrNull() is SqlElConditionLoopCommentBlock
144+
}
132145
}
133146
return false
134147
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlFileBlock.kt

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import com.intellij.lang.ASTNode
2727
import com.intellij.psi.PsiWhiteSpace
2828
import com.intellij.psi.formatter.common.AbstractBlock
2929
import org.domaframework.doma.intellij.common.util.TypeUtil
30-
import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock
3130
import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock
3231
import org.domaframework.doma.intellij.formatter.block.comment.SqlDefaultCommentBlock
3332
import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock
@@ -534,14 +533,6 @@ class SqlFileBlock(
534533
return SqlCustomSpacingBuilder().getSpacing(childBlock2)
535534
}
536535

537-
if (childBlock1 is SqlWhitespaceBlock) {
538-
when (childBlock2) {
539-
is SqlBlockCommentBlock, is SqlLineCommentBlock, is SqlNewGroupBlock -> {
540-
return SqlCustomSpacingBuilder().getSpacing(childBlock2)
541-
}
542-
}
543-
}
544-
545536
if (childBlock2 is SqlNewGroupBlock) {
546537
if (childBlock1 is SqlSubGroupBlock && childBlock2.indent.indentLevel == IndentType.ATTACHED) {
547538
return SqlCustomSpacingBuilder.nonSpacing
@@ -583,6 +574,18 @@ class SqlFileBlock(
583574
?.let { return it }
584575
}
585576

577+
// First apply spacing logic for blocks under specific conditions,
578+
// then execute the general spacing logic for post-line-break blocks at the end.
579+
if (childBlock1 is SqlWhitespaceBlock) {
580+
return when (childBlock2) {
581+
is SqlDefaultCommentBlock, is SqlNewGroupBlock -> {
582+
SqlCustomSpacingBuilder().getSpacing(childBlock2)
583+
}
584+
585+
else -> SqlCustomSpacingBuilder().getSpacing(childBlock2)
586+
}
587+
}
588+
586589
val spacing: Spacing? = customSpacingBuilder?.getCustomSpacing(childBlock1, childBlock2)
587590
return spacing ?: spacingBuilder.getSpacing(this, childBlock1, childBlock2)
588591
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/comment/SqlElConditionLoopCommentBlock.kt

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import com.intellij.psi.util.elementType
2525
import org.domaframework.doma.intellij.common.util.TypeUtil
2626
import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective
2727
import org.domaframework.doma.intellij.formatter.block.SqlBlock
28-
import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock
28+
import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock
2929
import org.domaframework.doma.intellij.formatter.block.SqlOperationBlock
3030
import org.domaframework.doma.intellij.formatter.block.SqlRightPatternBlock
3131
import org.domaframework.doma.intellij.formatter.block.SqlUnknownBlock
@@ -35,8 +35,6 @@ import org.domaframework.doma.intellij.formatter.block.expr.SqlElStaticFieldAcce
3535
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock
3636
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
3737
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock
38-
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineGroupBlock
39-
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineSecondGroupBlock
4038
import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock
4139
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
4240
import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder
@@ -200,10 +198,13 @@ class SqlElConditionLoopCommentBlock(
200198
override fun isLeaf(): Boolean = false
201199

202200
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean {
201+
if (conditionType.isEnd() || conditionType.isElse()) {
202+
return true
203+
}
203204
if (lastGroup is SqlSubGroupBlock) {
204205
return lastGroup.childBlocks.dropLast(1).isNotEmpty()
205206
}
206-
return true
207+
return lastGroup?.childBlocks?.any { it !is SqlKeywordBlock && it !is SqlKeywordGroupBlock } == true
207208
}
208209

209210
/**
@@ -220,10 +221,6 @@ class SqlElConditionLoopCommentBlock(
220221
}
221222
val openConditionLoopDirectiveCount = getOpenDirectiveCount(parent)
222223
when (parent) {
223-
is SqlKeywordGroupBlock, is SqlCommaBlock, is SqlInlineGroupBlock, is SqlInlineSecondGroupBlock -> {
224-
return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2)
225-
}
226-
227224
is SqlSubGroupBlock -> {
228225
val parentGroupIndentLen = parent.indent.groupIndentLen
229226
val grand = parent.parentBlock
@@ -266,6 +263,7 @@ class SqlElConditionLoopCommentBlock(
266263
return parent.indent.indentLen.plus(2)
267264
}
268265
}
266+
else -> return parent.indent.indentLen.plus(openConditionLoopDirectiveCount * 2)
269267
}
270268
}
271269
return 0

src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/SqlKeywordGroupBlock.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ open class SqlKeywordGroupBlock(
4444
listOf(
4545
SqlKeywordBlock::class,
4646
SqlKeywordGroupBlock::class,
47+
SqlElConditionLoopCommentBlock::class,
4748
)
4849

4950
if (lastChild == null ||
@@ -55,7 +56,9 @@ open class SqlKeywordGroupBlock(
5556
) {
5657
topKeywordBlocks.add(block)
5758
} else {
58-
canAddTopKeyword = false
59+
if (block !is SqlElConditionLoopCommentBlock) {
60+
canAddTopKeyword = false
61+
}
5962
}
6063

6164
indent.groupIndentLen = createGroupIndentLen()

src/main/kotlin/org/domaframework/doma/intellij/formatter/processor/SqlSetParentGroupProcessor.kt

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,19 @@ class SqlSetParentGroupProcessor(
6464
* Sets the parent of the latest group block and registers itself as a child element.
6565
*/
6666
fun updateGroupBlockParentAndAddGroup(childBlock: SqlBlock) {
67-
setParentGroups(
67+
val context =
6868
SetParentContext(
6969
childBlock,
7070
blockBuilder,
71-
),
72-
) { history ->
71+
)
72+
val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()
73+
if (lastGroup is SqlElConditionLoopCommentBlock) {
74+
updateParentGroupLastConditionLoop(lastGroup, context) { block ->
75+
block.indent.indentLevel < childBlock.indent.indentLevel
76+
}
77+
return
78+
}
79+
setParentGroups(context) { history ->
7380
return@setParentGroups history.lastOrNull()
7481
}
7582
}
@@ -91,7 +98,7 @@ class SqlSetParentGroupProcessor(
9198
/**
9299
* Registers itself as a child element in the same block as the parent of the last group at the time of processing.
93100
*/
94-
fun updateGroupBlockLastGroupParentAddGroup(
101+
private fun updateGroupBlockLastGroupParentAddGroup(
95102
lastGroupBlock: SqlBlock,
96103
childBlock: SqlBlock,
97104
) {
@@ -117,7 +124,7 @@ class SqlSetParentGroupProcessor(
117124
)
118125

119126
if (lastGroupBlock is SqlElConditionLoopCommentBlock) {
120-
updateParentGroupLastConditionLoop(lastGroupBlock, context, childBlock) {
127+
updateParentGroupLastConditionLoop(lastGroupBlock, context) {
121128
it.indent.indentLevel < childBlock.indent.indentLevel
122129
}
123130
return
@@ -257,15 +264,23 @@ class SqlSetParentGroupProcessor(
257264
listOf(
258265
SqlColumnRawGroupBlock::class,
259266
)
260-
if (isExpectedClassType(expectedTypes, lastGroupBlock)) {
261-
blockBuilder.removeLastGroupTopNodeIndexHistory()
262-
}
263-
setParentGroups(
267+
val context =
264268
SetParentContext(
265269
childBlock,
266270
blockBuilder,
267-
),
268-
) { history ->
271+
)
272+
273+
if (lastGroupBlock is SqlElConditionLoopCommentBlock) {
274+
updateParentGroupLastConditionLoop(lastGroupBlock, context) {
275+
it.indent.indentLevel < childBlock.indent.indentLevel
276+
}
277+
return
278+
}
279+
280+
if (isExpectedClassType(expectedTypes, lastGroupBlock)) {
281+
blockBuilder.removeLastGroupTopNodeIndexHistory()
282+
}
283+
setParentGroups(context) { history ->
269284
return@setParentGroups history
270285
.lastOrNull { it.indent.indentLevel < childBlock.indent.indentLevel }
271286
}
@@ -295,7 +310,7 @@ class SqlSetParentGroupProcessor(
295310

296311
val lastGroupBlock = blockBuilder.getLastGroupTopNodeIndexHistory()
297312
if (lastGroupBlock is SqlElConditionLoopCommentBlock) {
298-
updateParentGroupLastConditionLoop(lastGroupBlock, context, childBlock) {
313+
updateParentGroupLastConditionLoop(lastGroupBlock, context) {
299314
it.indent.indentLevel == IndentType.INLINE_SECOND
300315
}
301316
return
@@ -319,9 +334,9 @@ class SqlSetParentGroupProcessor(
319334
private fun updateParentGroupLastConditionLoop(
320335
lastGroupBlock: SqlElConditionLoopCommentBlock,
321336
context: SetParentContext,
322-
childBlock: SqlBlock,
323337
findDefaultParent: (SqlBlock) -> Boolean,
324338
) {
339+
val childBlock = context.childBlock
325340
if (lastGroupBlock.parentBlock != null) {
326341
setParentGroups(context) { history ->
327342
return@setParentGroups lastGroupBlock
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package org.domaframework.doma.intellij.formatter.util
2+
3+
import com.intellij.lang.ASTNode
4+
import org.domaframework.doma.intellij.formatter.block.SqlBlock
5+
import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock
6+
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
7+
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock
8+
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
9+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock
10+
11+
object CommaRawUtil {
12+
fun getCommaBlock(
13+
lastGroup: SqlBlock?,
14+
child: ASTNode,
15+
sqlBlockFormattingCtx: SqlBlockFormattingContext,
16+
): SqlBlock =
17+
if (lastGroup is SqlElConditionLoopCommentBlock) {
18+
if (lastGroup.parentBlock == null) {
19+
getSqlCommaBlock(lastGroup.tempParentBlock, child, sqlBlockFormattingCtx)
20+
} else {
21+
getSqlCommaBlock(lastGroup.parentBlock, child, sqlBlockFormattingCtx)
22+
}
23+
} else {
24+
getSqlCommaBlock(lastGroup, child, sqlBlockFormattingCtx)
25+
}
26+
27+
private fun getSqlCommaBlock(
28+
lastGroup: SqlBlock?,
29+
child: ASTNode,
30+
sqlBlockFormattingCtx: SqlBlockFormattingContext,
31+
): SqlBlock =
32+
when (lastGroup) {
33+
is SqlColumnRawGroupBlock, is SqlKeywordGroupBlock -> {
34+
if (lastGroup.indent.indentLevel == IndentType.SECOND) {
35+
SqlCommaBlock(child, sqlBlockFormattingCtx)
36+
} else {
37+
SqlColumnRawGroupBlock(child, sqlBlockFormattingCtx)
38+
}
39+
}
40+
41+
is SqlWithCommonTableGroupBlock -> SqlWithCommonTableGroupBlock(child, sqlBlockFormattingCtx)
42+
43+
else -> SqlCommaBlock(child, sqlBlockFormattingCtx)
44+
}
45+
}

src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockUtil.kt

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import com.intellij.psi.PsiComment
2424
import com.intellij.psi.util.PsiTreeUtil
2525
import org.domaframework.doma.intellij.extension.expr.isConditionOrLoopDirective
2626
import org.domaframework.doma.intellij.formatter.block.SqlBlock
27-
import org.domaframework.doma.intellij.formatter.block.SqlCommaBlock
2827
import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock
2928
import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock
3029
import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock
@@ -35,7 +34,6 @@ import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClaus
3534
import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock
3635
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock
3736
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock
38-
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock
3937
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlJoinGroupBlock
4038
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
4139
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlLateralGroupBlock
@@ -393,19 +391,7 @@ class SqlBlockUtil(
393391
.getColumnRawGroup(lastGroup, child, sqlBlockFormattingCtx)
394392
?.let { return it }
395393

396-
return when (lastGroup) {
397-
is SqlColumnRawGroupBlock, is SqlKeywordGroupBlock -> {
398-
if (lastGroup.indent.indentLevel == IndentType.SECOND) {
399-
SqlCommaBlock(child, sqlBlockFormattingCtx)
400-
} else {
401-
SqlColumnRawGroupBlock(child, sqlBlockFormattingCtx)
402-
}
403-
}
404-
405-
is SqlWithCommonTableGroupBlock -> SqlWithCommonTableGroupBlock(child, sqlBlockFormattingCtx)
406-
407-
else -> SqlCommaBlock(child, sqlBlockFormattingCtx)
408-
}
394+
return CommaRawUtil.getCommaBlock(lastGroup, child, sqlBlockFormattingCtx)
409395
}
410396

411397
fun getWordBlock(

src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class SqlKeywordUtil {
313313
"update" to setOf("do"),
314314
"set" to setOf("by", "cycle"),
315315
"order" to setOf("partition", "by"),
316+
"select" to setOf("if", "exists"),
316317
)
317318

318319
fun isSetLineKeyword(

src/test/testData/sql/formatter/NestedDirectives_format.sql

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,14 @@ SELECT e.id
44
FROM employee e
55
/*%if includesDepartment */
66
LEFT JOIN department d
7-
ON e.department_id = d.id
7+
ON e.department_id = d.id
88
/*%if includeDepartmentDetails */
99
LEFT JOIN department_detail dd
1010
ON d.id = dd.department_id
1111
/*%end */
1212
/*%end */
1313
WHERE 1 = 1
14-
ORDER BY
15-
/*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1
14+
ORDER BY /*%if sortConditions != null && !sortConditions.isEmpty() */ -- IF1
1615
/*%for sort : sortConditions */ -- IF2
1716
/*%if sort.field == "name" */ -- IF3
1817
e.name

0 commit comments

Comments
 (0)