Skip to content

Commit b25b329

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

File tree

2 files changed

+146
-75
lines changed

2 files changed

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

0 commit comments

Comments
 (0)