Skip to content

Commit b8e2c24

Browse files
committed
Add SqlKeywordBlockFactory for creating SQL keyword blocks based on context
1 parent 9ba4ebe commit b8e2c24

File tree

2 files changed

+147
-75
lines changed

2 files changed

+147
-75
lines changed

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

Lines changed: 8 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBl
3030
import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock
3131
import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock
3232
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
33-
import org.domaframework.doma.intellij.formatter.block.conflict.OnConflictKeywordType
3433
import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock
3534
import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock
3635
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock
@@ -41,13 +40,8 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.S
4140
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock
4241
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock
4342
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionRawGroupBlock
44-
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock
45-
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineGroupBlock
4643
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineSecondGroupBlock
4744
import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock
48-
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlExistsGroupBlock
49-
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlInGroupBlock
50-
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlLateralGroupBlock
5145
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlSecondOptionKeywordGroupBlock
5246
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlFromGroupBlock
5347
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlSecondKeywordBlock
@@ -100,87 +94,26 @@ class SqlBlockGenerator(
10094
formatMode,
10195
)
10296

97+
private val keywordBlockFactory = SqlKeywordBlockFactory(sqlBlockFormattingCtx)
98+
10399
fun getKeywordBlock(
104100
child: ASTNode,
105101
lastGroupBlock: SqlBlock?,
106102
): SqlBlock {
107-
// Because we haven't yet set the parent-child relationship of the block,
108-
// the parent group references groupTopNodeIndexHistory.
109103
val keywordText = child.text.lowercase()
110104
val indentLevel = SqlKeywordUtil.getIndentType(keywordText)
111105

112106
if (indentLevel.isNewLineGroup()) {
113107
return getKeywordGroupBlock(indentLevel, keywordText, child, lastGroupBlock)
114108
}
115109

116-
when (indentLevel) {
117-
IndentType.INLINE -> {
118-
if (!SqlKeywordUtil.isSetLineKeyword(
119-
child.text,
120-
lastGroupBlock?.getNodeText() ?: "",
121-
)
122-
) {
123-
return SqlInlineGroupBlock(child, sqlBlockFormattingCtx)
124-
}
125-
}
126-
127-
IndentType.ATTACHED -> {
128-
if (lastGroupBlock is SqlCreateKeywordGroupBlock) {
129-
lastGroupBlock.setCreateQueryType(child.text)
130-
return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx)
131-
}
132-
}
133-
134-
IndentType.OPTIONS -> {
135-
if (keywordText == "as") {
136-
val parentCreateBlock =
137-
lastGroupBlock as? SqlCreateKeywordGroupBlock
138-
?: lastGroupBlock?.parentBlock as? SqlCreateKeywordGroupBlock
139-
if (parentCreateBlock != null && parentCreateBlock.createType == CreateQueryType.VIEW) {
140-
return SqlCreateViewGroupBlock(child, sqlBlockFormattingCtx)
141-
}
142-
}
143-
if (keywordText == "lateral") {
144-
return SqlLateralGroupBlock(child, sqlBlockFormattingCtx)
145-
}
146-
if (keywordText == "in") {
147-
return SqlInGroupBlock(
148-
child,
149-
sqlBlockFormattingCtx,
150-
)
151-
}
152-
153-
if (SqlKeywordUtil.isExistsKeyword(keywordText)) {
154-
if (lastGroupBlock is SqlExistsGroupBlock) {
155-
return SqlKeywordBlock(
156-
child,
157-
indentLevel,
158-
sqlBlockFormattingCtx,
159-
)
160-
}
161-
if (lastGroupBlock is SqlElConditionLoopCommentBlock && lastGroupBlock.conditionType.isElse() ||
162-
keywordText == "not" && (lastGroupBlock !is SqlConditionKeywordGroupBlock && lastGroupBlock !is SqlWhereGroupBlock)
163-
) {
164-
return SqlExistsGroupBlock(
165-
child,
166-
sqlBlockFormattingCtx,
167-
)
168-
}
169-
}
170-
}
171-
172-
IndentType.CONFLICT -> {
173-
if (lastGroupBlock is SqlConflictClauseBlock) {
174-
lastGroupBlock.conflictType = OnConflictKeywordType.of(keywordText)
175-
return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx)
176-
} else {
177-
return SqlConflictClauseBlock(child, sqlBlockFormattingCtx)
178-
}
179-
}
180-
181-
else -> return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx)
110+
return when (indentLevel) {
111+
IndentType.INLINE -> keywordBlockFactory.createInlineBlock(child, lastGroupBlock)
112+
IndentType.ATTACHED -> keywordBlockFactory.createAttachedBlock(child, lastGroupBlock)
113+
IndentType.OPTIONS -> keywordBlockFactory.createOptionsBlock(keywordText, child, lastGroupBlock)
114+
IndentType.CONFLICT -> keywordBlockFactory.createConflictBlock(keywordText, child, lastGroupBlock)
115+
else -> SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx)
182116
}
183-
return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx)
184117
}
185118

186119
private fun getKeywordGroupBlock(
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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.formatter.util
17+
18+
import com.intellij.lang.ASTNode
19+
import org.domaframework.doma.intellij.formatter.block.SqlBlock
20+
import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock
21+
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
22+
import org.domaframework.doma.intellij.formatter.block.conflict.OnConflictKeywordType
23+
import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock
24+
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
25+
import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionKeywordGroupBlock
26+
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock
27+
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock
28+
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineGroupBlock
29+
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlExistsGroupBlock
30+
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlInGroupBlock
31+
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlLateralGroupBlock
32+
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlWhereGroupBlock
33+
34+
/**
35+
* Factory class for creating SQL keyword blocks based on indent type and context
36+
*/
37+
class SqlKeywordBlockFactory(
38+
private val sqlBlockFormattingCtx: SqlBlockFormattingContext,
39+
) {
40+
fun createInlineBlock(
41+
child: ASTNode,
42+
lastGroupBlock: SqlBlock?,
43+
): SqlBlock =
44+
if (!SqlKeywordUtil.isSetLineKeyword(
45+
child.text,
46+
lastGroupBlock?.getNodeText() ?: "",
47+
)
48+
) {
49+
SqlInlineGroupBlock(child, sqlBlockFormattingCtx)
50+
} else {
51+
SqlKeywordBlock(child, IndentType.INLINE, sqlBlockFormattingCtx)
52+
}
53+
54+
fun createAttachedBlock(
55+
child: ASTNode,
56+
lastGroupBlock: SqlBlock?,
57+
): SqlBlock {
58+
if (lastGroupBlock is SqlCreateKeywordGroupBlock) {
59+
lastGroupBlock.setCreateQueryType(child.text)
60+
}
61+
return SqlKeywordBlock(child, IndentType.ATTACHED, sqlBlockFormattingCtx)
62+
}
63+
64+
fun createOptionsBlock(
65+
keywordText: String,
66+
child: ASTNode,
67+
lastGroupBlock: SqlBlock?,
68+
): SqlBlock {
69+
// Handle AS keyword for CREATE VIEW
70+
if (keywordText == "as") {
71+
val parentCreateBlock = findParentCreateBlock(lastGroupBlock)
72+
if (parentCreateBlock?.createType == CreateQueryType.VIEW) {
73+
return SqlCreateViewGroupBlock(child, sqlBlockFormattingCtx)
74+
}
75+
}
76+
77+
// Handle LATERAL keyword
78+
if (keywordText == "lateral") {
79+
return SqlLateralGroupBlock(child, sqlBlockFormattingCtx)
80+
}
81+
82+
// Handle IN keyword
83+
if (keywordText == "in") {
84+
return SqlInGroupBlock(child, sqlBlockFormattingCtx)
85+
}
86+
87+
// Handle EXISTS/NOT EXISTS keywords
88+
if (SqlKeywordUtil.isExistsKeyword(keywordText)) {
89+
return createExistsBlock(keywordText, child, lastGroupBlock)
90+
}
91+
92+
return SqlKeywordBlock(child, IndentType.OPTIONS, sqlBlockFormattingCtx)
93+
}
94+
95+
fun createConflictBlock(
96+
keywordText: String,
97+
child: ASTNode,
98+
lastGroupBlock: SqlBlock?,
99+
): SqlBlock =
100+
if (lastGroupBlock is SqlConflictClauseBlock) {
101+
lastGroupBlock.conflictType = OnConflictKeywordType.of(keywordText)
102+
SqlKeywordBlock(child, IndentType.CONFLICT, sqlBlockFormattingCtx)
103+
} else {
104+
SqlConflictClauseBlock(child, sqlBlockFormattingCtx)
105+
}
106+
107+
private fun findParentCreateBlock(block: SqlBlock?): SqlCreateKeywordGroupBlock? =
108+
when (block) {
109+
is SqlCreateKeywordGroupBlock -> block
110+
else -> block?.parentBlock as? SqlCreateKeywordGroupBlock
111+
}
112+
113+
private fun createExistsBlock(
114+
keywordText: String,
115+
child: ASTNode,
116+
lastGroupBlock: SqlBlock?,
117+
): SqlBlock {
118+
// If already in EXISTS group, just return a keyword block
119+
if (lastGroupBlock is SqlExistsGroupBlock) {
120+
return SqlKeywordBlock(child, IndentType.OPTIONS, sqlBlockFormattingCtx)
121+
}
122+
123+
// Check for ELSE condition or NOT keyword outside WHERE/condition context
124+
val shouldCreateExistsGroup =
125+
when {
126+
lastGroupBlock is SqlElConditionLoopCommentBlock && lastGroupBlock.conditionType.isElse() -> true
127+
keywordText == "not" && !isInConditionContext(lastGroupBlock) -> true
128+
else -> false
129+
}
130+
131+
return if (shouldCreateExistsGroup) {
132+
SqlExistsGroupBlock(child, sqlBlockFormattingCtx)
133+
} else {
134+
SqlKeywordBlock(child, IndentType.OPTIONS, sqlBlockFormattingCtx)
135+
}
136+
}
137+
138+
private fun isInConditionContext(block: SqlBlock?): Boolean = block is SqlConditionKeywordGroupBlock || block is SqlWhereGroupBlock
139+
}

0 commit comments

Comments
 (0)