Skip to content

Commit 267cc7a

Browse files
authored
Merge pull request #426 from domaframework/fix/sql-format-column-name-as-word
Handle Blocks with the Same Name as Functions or Keywords as Word Blocks
2 parents 99ca38b + ca616fa commit 267cc7a

25 files changed

+533
-242
lines changed

src/main/kotlin/org/domaframework/doma/intellij/common/util/TypeUtil.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,21 @@ import org.domaframework.doma.intellij.extension.psi.isDataType
2727
import org.domaframework.doma.intellij.extension.psi.isDomain
2828
import org.domaframework.doma.intellij.extension.psi.isEntity
2929
import org.domaframework.doma.intellij.formatter.block.SqlBlock
30+
import org.domaframework.doma.intellij.formatter.block.comma.SqlCommaBlock
31+
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock
32+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQuerySubGroupBlock
33+
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
3034
import kotlin.reflect.KClass
3135

3236
object TypeUtil {
37+
private val TOP_LEVEL_EXPECTED_TYPES =
38+
listOf(
39+
SqlSubGroupBlock::class,
40+
SqlCommaBlock::class,
41+
SqlWithQuerySubGroupBlock::class,
42+
SqlCreateViewGroupBlock::class,
43+
)
44+
3345
/**
3446
* Unwraps the type parameter from Optional if present, otherwise returns the original type.
3547
*/
@@ -118,6 +130,8 @@ object TypeUtil {
118130
return PsiTypeChecker.isBaseClassType(type) || DomaClassName.isOptionalWrapperType(type.canonicalText)
119131
}
120132

133+
fun isTopLevelExpectedType(childBlock: SqlBlock?): Boolean = isExpectedClassType(TOP_LEVEL_EXPECTED_TYPES, childBlock)
134+
121135
/**
122136
* Determines whether the specified class instance matches.
123137
*/

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ open class SqlBlock(
102102
protected fun isConditionLoopDirectiveRegisteredBeforeParent(): Boolean {
103103
val firstPrevBlock = (prevBlocks.lastOrNull() as? SqlElConditionLoopCommentBlock)
104104
parentBlock?.let { parent ->
105-
return firstPrevBlock != null &&
105+
106+
return (childBlocks.firstOrNull() as? SqlElConditionLoopCommentBlock)?.isBeforeParentBlock() == true ||
107+
firstPrevBlock != null &&
106108
firstPrevBlock.conditionEnd != null &&
107109
firstPrevBlock.node.startOffset > parent.node.startOffset
108110
}

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

Lines changed: 132 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ import com.intellij.formatting.Wrap
2626
import com.intellij.lang.ASTNode
2727
import com.intellij.psi.PsiWhiteSpace
2828
import com.intellij.psi.formatter.common.AbstractBlock
29-
import com.intellij.psi.util.PsiTreeUtil
30-
import com.intellij.psi.util.elementType
31-
import com.intellij.psi.util.nextLeaf
32-
import com.intellij.psi.util.nextLeafs
3329
import org.domaframework.doma.intellij.common.util.TypeUtil
3430
import org.domaframework.doma.intellij.formatter.block.comma.SqlCommaBlock
3531
import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock
@@ -62,7 +58,6 @@ import org.domaframework.doma.intellij.formatter.block.other.SqlEscapeBlock
6258
import org.domaframework.doma.intellij.formatter.block.other.SqlOtherBlock
6359
import org.domaframework.doma.intellij.formatter.block.word.SqlAliasBlock
6460
import org.domaframework.doma.intellij.formatter.block.word.SqlArrayWordBlock
65-
import org.domaframework.doma.intellij.formatter.block.word.SqlFunctionGroupBlock
6661
import org.domaframework.doma.intellij.formatter.block.word.SqlTableBlock
6762
import org.domaframework.doma.intellij.formatter.block.word.SqlWordBlock
6863
import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder
@@ -152,152 +147,130 @@ open class SqlFileBlock(
152147
child: ASTNode,
153148
prevBlock: SqlBlock?,
154149
): SqlBlock {
155-
val defaultFormatCtx =
156-
SqlBlockFormattingContext(
157-
wrap,
158-
alignment,
159-
spacingBuilder,
160-
isEnableFormat(),
161-
formatMode,
162-
)
150+
val defaultFormatCtx = createDefaultFormattingContext()
163151
val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()
164152
val lastGroupFilteredDirective = blockBuilder.getLastGroupFilterDirective()
165-
return when (child.elementType) {
166-
SqlTypes.KEYWORD -> {
167-
return blockUtil.getKeywordBlock(
168-
child,
169-
blockBuilder.getLastGroupTopNodeIndexHistory(),
170-
)
171-
}
172-
173-
SqlTypes.DATATYPE -> {
174-
SqlDataTypeBlock(
175-
child,
176-
defaultFormatCtx,
177-
)
178-
}
179-
180-
SqlTypes.LEFT_PAREN -> {
181-
return blockUtil.getSubGroupBlock(lastGroup, child, blockBuilder.getGroupTopNodeIndexHistory())
182-
}
183-
184-
SqlTypes.OTHER -> {
185-
return if (lastGroup is SqlUpdateSetGroupBlock &&
186-
lastGroup.columnDefinitionGroupBlock != null
187-
) {
188-
SqlUpdateColumnAssignmentSymbolBlock(
189-
child,
190-
defaultFormatCtx,
191-
)
192-
} else {
193-
val escapeStrings = listOf("\"", "`", "[", "]")
194-
if (escapeStrings.contains(child.text)) {
195-
if (child.text == "[" && prevBlock is SqlArrayWordBlock) {
196-
SqlArrayListGroupBlock(
197-
child,
198-
defaultFormatCtx,
199-
)
200-
} else {
201-
SqlEscapeBlock(
202-
child,
203-
defaultFormatCtx,
204-
)
205-
}
206-
} else {
207-
SqlOtherBlock(
208-
child,
209-
defaultFormatCtx,
210-
)
211-
}
212-
}
213-
}
214153

215-
SqlTypes.RIGHT_PAREN -> return SqlRightPatternBlock(
216-
child,
217-
defaultFormatCtx,
218-
)
154+
return when (child.elementType) {
155+
SqlTypes.KEYWORD -> createKeywordBlock(child, lastGroup)
156+
SqlTypes.DATATYPE -> SqlDataTypeBlock(child, defaultFormatCtx)
157+
SqlTypes.LEFT_PAREN -> blockUtil.getSubGroupBlock(lastGroup, child, blockBuilder.getGroupTopNodeIndexHistory())
158+
SqlTypes.OTHER -> createOtherBlock(child, prevBlock, lastGroup, defaultFormatCtx)
159+
SqlTypes.RIGHT_PAREN -> SqlRightPatternBlock(child, defaultFormatCtx)
160+
SqlTypes.COMMA -> createCommaBlock(child, lastGroup, defaultFormatCtx)
161+
SqlTypes.FUNCTION_NAME -> createFunctionNameBlock(child, lastGroup, defaultFormatCtx)
162+
SqlTypes.WORD -> createWordBlock(child, lastGroup, defaultFormatCtx)
163+
SqlTypes.BLOCK_COMMENT -> createBlockCommentBlock(child, lastGroup, lastGroupFilteredDirective, defaultFormatCtx)
164+
SqlTypes.LINE_COMMENT -> SqlLineCommentBlock(child, defaultFormatCtx)
165+
SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH -> SqlElSymbolBlock(child, defaultFormatCtx)
166+
SqlTypes.LE, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, SqlTypes.GE, SqlTypes.GT -> SqlElSymbolBlock(child, defaultFormatCtx)
167+
SqlTypes.STRING, SqlTypes.NUMBER, SqlTypes.BOOLEAN -> SqlLiteralBlock(child, defaultFormatCtx)
168+
else -> SqlUnknownBlock(child, defaultFormatCtx)
169+
}
170+
}
219171

220-
SqlTypes.COMMA -> {
221-
return if (lastGroup is SqlWithQueryGroupBlock) {
222-
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
223-
} else {
224-
blockUtil.getCommaGroupBlock(lastGroup, child)
225-
}
226-
}
172+
private fun createDefaultFormattingContext(): SqlBlockFormattingContext =
173+
SqlBlockFormattingContext(
174+
wrap,
175+
alignment,
176+
spacingBuilder,
177+
isEnableFormat(),
178+
formatMode,
179+
)
227180

228-
SqlTypes.FUNCTION_NAME -> {
229-
val notWhiteSpaceElement =
230-
child.psi.nextLeafs
231-
.takeWhile { it is PsiWhiteSpace }
232-
.lastOrNull()
233-
?.nextLeaf(true)
234-
if (notWhiteSpaceElement?.elementType == SqlTypes.LEFT_PAREN ||
235-
PsiTreeUtil.nextLeaf(child.psi)?.elementType == SqlTypes.LEFT_PAREN
236-
) {
237-
return SqlFunctionGroupBlock(child, defaultFormatCtx)
238-
}
239-
return SqlKeywordBlock(
240-
child,
241-
IndentType.ATTACHED,
242-
defaultFormatCtx,
243-
)
244-
}
181+
private fun createKeywordBlock(
182+
child: ASTNode,
183+
lastGroup: SqlBlock?,
184+
): SqlBlock {
185+
if (blockUtil.hasEscapeBeforeWhiteSpace(blocks.lastOrNull() as? SqlBlock?, child)) {
186+
return blockUtil.getWordBlock(lastGroup, child)
187+
}
188+
return blockUtil.getKeywordBlock(
189+
child,
190+
blockBuilder.getLastGroupTopNodeIndexHistory(),
191+
)
192+
}
245193

246-
SqlTypes.WORD -> {
247-
return if (lastGroup is SqlWithQueryGroupBlock) {
248-
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
249-
} else {
250-
blockUtil.getWordBlock(lastGroup, child)
251-
}
252-
}
194+
private fun createOtherBlock(
195+
child: ASTNode,
196+
prevBlock: SqlBlock?,
197+
lastGroup: SqlBlock?,
198+
defaultFormatCtx: SqlBlockFormattingContext,
199+
): SqlBlock {
200+
if (lastGroup is SqlUpdateSetGroupBlock && lastGroup.columnDefinitionGroupBlock != null) {
201+
return SqlUpdateColumnAssignmentSymbolBlock(child, defaultFormatCtx)
202+
}
253203

254-
SqlTypes.BLOCK_COMMENT -> {
255-
val tempBlock =
256-
blockUtil.getBlockCommentBlock(
257-
child,
258-
createBlockDirectiveCommentSpacingBuilder(),
259-
)
260-
if (tempBlock !is SqlElConditionLoopCommentBlock) {
261-
if (lastGroup is SqlWithQueryGroupBlock || lastGroupFilteredDirective is SqlWithQueryGroupBlock) {
262-
return SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
263-
}
264-
}
265-
return if (lastGroup is SqlWithCommonTableGroupBlock) {
266-
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
267-
} else {
268-
tempBlock
269-
}
204+
val escapeStrings = listOf("\"", "`", "[", "]")
205+
if (escapeStrings.contains(child.text)) {
206+
return if (child.text == "[" && prevBlock is SqlArrayWordBlock) {
207+
SqlArrayListGroupBlock(child, defaultFormatCtx)
208+
} else {
209+
SqlEscapeBlock(child, defaultFormatCtx)
270210
}
211+
}
212+
return SqlOtherBlock(child, defaultFormatCtx)
213+
}
271214

272-
SqlTypes.LINE_COMMENT ->
273-
return SqlLineCommentBlock(
274-
child,
275-
defaultFormatCtx,
276-
)
277-
278-
SqlTypes.PLUS, SqlTypes.MINUS, SqlTypes.ASTERISK, SqlTypes.SLASH ->
279-
return SqlElSymbolBlock(
280-
child,
281-
defaultFormatCtx,
282-
)
215+
private fun createCommaBlock(
216+
child: ASTNode,
217+
lastGroup: SqlBlock?,
218+
defaultFormatCtx: SqlBlockFormattingContext,
219+
): SqlBlock =
220+
if (lastGroup is SqlWithQueryGroupBlock) {
221+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
222+
} else {
223+
blockUtil.getCommaGroupBlock(lastGroup, child)
224+
}
283225

284-
SqlTypes.LE, SqlTypes.LT, SqlTypes.EL_EQ, SqlTypes.EL_NE, SqlTypes.GE, SqlTypes.GT ->
285-
return SqlElSymbolBlock(
286-
child,
287-
defaultFormatCtx,
288-
)
226+
private fun createFunctionNameBlock(
227+
child: ASTNode,
228+
lastGroup: SqlBlock?,
229+
defaultFormatCtx: SqlBlockFormattingContext,
230+
): SqlBlock {
231+
val block = blockUtil.getFunctionName(child, defaultFormatCtx)
232+
if (block != null) {
233+
return block
234+
}
235+
// If it is not followed by a left parenthesis, treat it as a word block
236+
return if (lastGroup is SqlWithQueryGroupBlock) {
237+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
238+
} else {
239+
blockUtil.getWordBlock(lastGroup, child)
240+
}
241+
}
289242

290-
SqlTypes.STRING, SqlTypes.NUMBER, SqlTypes.BOOLEAN ->
291-
return SqlLiteralBlock(
292-
child,
293-
defaultFormatCtx,
294-
)
243+
private fun createWordBlock(
244+
child: ASTNode,
245+
lastGroup: SqlBlock?,
246+
defaultFormatCtx: SqlBlockFormattingContext,
247+
): SqlBlock =
248+
if (lastGroup is SqlWithQueryGroupBlock) {
249+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
250+
} else {
251+
blockUtil.getWordBlock(lastGroup, child)
252+
}
295253

296-
else ->
297-
SqlUnknownBlock(
298-
child,
299-
defaultFormatCtx,
300-
)
254+
private fun createBlockCommentBlock(
255+
child: ASTNode,
256+
lastGroup: SqlBlock?,
257+
lastGroupFilteredDirective: SqlBlock?,
258+
defaultFormatCtx: SqlBlockFormattingContext,
259+
): SqlBlock {
260+
val tempBlock =
261+
blockUtil.getBlockCommentBlock(
262+
child,
263+
createBlockDirectiveCommentSpacingBuilder(),
264+
)
265+
if (tempBlock !is SqlElConditionLoopCommentBlock) {
266+
if (lastGroup is SqlWithQueryGroupBlock || lastGroupFilteredDirective is SqlWithQueryGroupBlock) {
267+
return SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
268+
}
269+
}
270+
return if (lastGroup is SqlWithCommonTableGroupBlock) {
271+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
272+
} else {
273+
tempBlock
301274
}
302275
}
303276

@@ -554,7 +527,19 @@ open class SqlFileBlock(
554527
SqlCustomSpacingBuilder.nonSpacing
555528
}
556529

557-
else -> SqlCustomSpacingBuilder.normalSpacing
530+
is SqlSubGroupBlock -> {
531+
val includeSpaceRight = childBlock1.endPatternBlock?.isPreSpaceRight()
532+
533+
if (includeSpaceRight == false) {
534+
SqlCustomSpacingBuilder.nonSpacing
535+
} else {
536+
SqlCustomSpacingBuilder.normalSpacing
537+
}
538+
}
539+
540+
else -> {
541+
SqlCustomSpacingBuilder.normalSpacing
542+
}
558543
}
559544
}
560545

@@ -576,6 +561,13 @@ open class SqlFileBlock(
576561
if (childBlock2.isEndEscape) {
577562
return SqlCustomSpacingBuilder.nonSpacing
578563
}
564+
565+
// When a column definition is enclosed in escape characters,
566+
// calculate the indentation to match the formatting rules of a CREATE query.
567+
CreateClauseHandler
568+
.getColumnDefinitionRawGroupSpacing(childBlock1, childBlock2)
569+
?.let { return it }
570+
579571
return SqlCustomSpacingBuilder().getSpacing(childBlock2)
580572
}
581573

0 commit comments

Comments
 (0)