Skip to content

Commit 06e32c9

Browse files
authored
Merge pull request #301 from domaframework/feature/sql-format-support-cte
Support SQL Format for CTE
2 parents 503b77d + 8ca4954 commit 06e32c9

File tree

83 files changed

+1725
-699
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1725
-699
lines changed

src/main/java/org/domaframework/doma/intellij/Sql.flex

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.domaframework.doma.intellij.psi.SqlTypes;
2929
"as",
3030
"asc",
3131
"between",
32+
"breadth",
3233
"by",
3334
"case",
3435
"change",
@@ -39,6 +40,7 @@ import org.domaframework.doma.intellij.psi.SqlTypes;
3940
"comment",
4041
"create",
4142
"cross",
43+
"cycle",
4244
"database",
4345
"default",
4446
"delete",
@@ -72,6 +74,7 @@ import org.domaframework.doma.intellij.psi.SqlTypes;
7274
"not",
7375
"nothing",
7476
"null",
77+
"materialized",
7578
"modify",
7679
"offset",
7780
"on",
@@ -81,7 +84,10 @@ import org.domaframework.doma.intellij.psi.SqlTypes;
8184
"primary",
8285
"references",
8386
"rename",
87+
"returning",
88+
"recursive",
8489
"right",
90+
"search",
8591
"select",
8692
"set",
8793
"table",
@@ -92,10 +98,12 @@ import org.domaframework.doma.intellij.psi.SqlTypes;
9298
"union",
9399
"unique",
94100
"update",
101+
"using",
95102
"values",
96103
"view",
97104
"when",
98-
"where"
105+
"where",
106+
"with"
99107
);
100108

101109
// COLUMN DataTypes
@@ -128,6 +136,7 @@ import org.domaframework.doma.intellij.psi.SqlTypes;
128136
);
129137

130138
private static boolean isKeyword(CharSequence word) {
139+
// TODO Reads plugin settings and allows users to register arbitrary keywords
131140
return KEYWORDS.contains(word.toString().toLowerCase());
132141
}
133142

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ object TypeUtil {
102102
*/
103103
fun isExpectedClassType(
104104
expectedClasses: List<KClass<*>>,
105-
childBlock: SqlBlock,
105+
childBlock: SqlBlock?,
106106
): Boolean =
107107
expectedClasses.any { clazz ->
108108
clazz.isInstance(childBlock)

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

Lines changed: 41 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -26,32 +26,27 @@ 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 org.domaframework.doma.intellij.common.util.TypeUtil.isExpectedClassType
3129
import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBlock
3230
import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock
3331
import org.domaframework.doma.intellij.formatter.block.comment.SqlLineCommentBlock
34-
import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock
35-
import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock
3632
import org.domaframework.doma.intellij.formatter.block.expr.SqlElBlockCommentBlock
3733
import org.domaframework.doma.intellij.formatter.block.expr.SqlElConditionLoopCommentBlock
3834
import org.domaframework.doma.intellij.formatter.block.expr.SqlElSymbolBlock
3935
import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock
4036
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock
4137
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnDefinitionRawGroupBlock
4238
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock
43-
import org.domaframework.doma.intellij.formatter.block.group.column.SqlDataTypeBlock
4439
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineGroupBlock
4540
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlInlineSecondGroupBlock
4641
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
47-
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock
48-
import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertColumnGroupBlock
4942
import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateColumnAssignmentSymbolBlock
5043
import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateSetGroupBlock
44+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithColumnGroupBlock
45+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithCommonTableGroupBlock
46+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithQueryGroupBlock
5147
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlDataTypeParamBlock
5248
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock
53-
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock
54-
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlRightPatternBlock
49+
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
5550
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubQueryGroupBlock
5651
import org.domaframework.doma.intellij.formatter.builder.SqlBlockBuilder
5752
import org.domaframework.doma.intellij.formatter.builder.SqlCustomSpacingBuilder
@@ -93,6 +88,7 @@ open class SqlBlock(
9388
val blocks = mutableListOf<AbstractBlock>()
9489
open var parentBlock: SqlBlock? = null
9590
open val childBlocks = mutableListOf<SqlBlock>()
91+
9692
open val indent: ElementIndent =
9793
ElementIndent(
9894
IndentType.FILE,
@@ -118,8 +114,6 @@ open class SqlBlock(
118114
// This method can be overridden to set additional properties on the parent block if needed.
119115
}
120116

121-
open val isNeedWhiteSpace: Boolean = true
122-
123117
open fun addChildBlock(childBlock: SqlBlock) {
124118
childBlocks.add(childBlock)
125119
}
@@ -137,10 +131,10 @@ open class SqlBlock(
137131
val lastGroup = blockBuilder.getLastGroupTopNodeIndexHistory()
138132
if (child !is PsiWhiteSpace) {
139133
val childBlock = getBlock(child)
140-
updateWhiteSpaceInclude(lastBlock, childBlock, lastGroup)
141134
prevNonWhiteSpaceNode = child
142135
updateCommentParentAndIdent(childBlock)
143136
updateBlockParentAndLAddGroup(childBlock)
137+
updateWhiteSpaceInclude(lastBlock, childBlock, lastGroup)
144138
blocks.add(childBlock)
145139
} else {
146140
if (lastBlock !is SqlLineCommentBlock) {
@@ -195,88 +189,15 @@ open class SqlBlock(
195189
}
196190
}
197191

192+
open fun isSaveSpace(lastGroup: SqlBlock?): Boolean = false
193+
198194
/**
199195
* Determines whether to retain the space (newline) based on the last registered group or the class of the currently checked element.
200196
*/
201197
private fun isSaveWhiteSpace(
202198
childBlock: SqlBlock,
203199
lastGroup: SqlBlock?,
204-
): Boolean {
205-
val child = childBlock.node
206-
207-
if (!childBlock.isNeedWhiteSpace) return false
208-
209-
val expectedClassTypes =
210-
listOf(
211-
SqlElConditionLoopCommentBlock::class,
212-
SqlInsertColumnGroupBlock::class,
213-
SqlColumnDefinitionRawGroupBlock::class,
214-
SqlCreateTableColumnDefinitionGroupBlock::class,
215-
SqlUpdateColumnAssignmentSymbolBlock::class,
216-
SqlDoGroupBlock::class,
217-
)
218-
219-
if (isExpectedClassType(expectedClassTypes, childBlock)) return true
220-
221-
if (isNewLineSqlComment(child, childBlock)) return true
222-
223-
if (lastGroup is SqlConflictClauseBlock) return false
224-
if (childBlock is SqlColumnRawGroupBlock) {
225-
return !childBlock.isFirstColumnGroup
226-
}
227-
228-
return (
229-
isNewLineGroupBlockAfterRegistrationChild(childBlock, lastGroup) ||
230-
(childBlock is SqlRightPatternBlock && childBlock.isNewLine(lastGroup))
231-
)
232-
}
233-
234-
/**
235-
* Retains the block only for comments that are broken down.
236-
*/
237-
private fun isNewLineSqlComment(
238-
child: ASTNode,
239-
childBlock: SqlBlock,
240-
): Boolean {
241-
val commentBlockType =
242-
listOf(
243-
SqlLineCommentBlock::class,
244-
SqlBlockCommentBlock::class,
245-
)
246-
val prevSpace = PsiTreeUtil.prevLeaf(child.psi)
247-
return isExpectedClassType(
248-
commentBlockType,
249-
childBlock,
250-
) &&
251-
prevSpace?.text?.contains("\n") == true
252-
}
253-
254-
/**
255-
* Determines whether a newline is required after registering itself as a child of the parent block.
256-
*/
257-
private fun isNewLineGroupBlockAfterRegistrationChild(
258-
childBlock: SqlBlock,
259-
lastGroup: SqlBlock?,
260-
): Boolean {
261-
fun isParallelListRawChild(): Boolean =
262-
childBlock is SqlCommaBlock &&
263-
(
264-
lastGroup is SqlParallelListBlock ||
265-
lastGroup?.parentBlock is SqlParallelListBlock
266-
)
267-
268-
if (isParallelListRawChild()) return false
269-
270-
if (parentSetProcessor.isNewGroupAndNotSetLineKeywords(childBlock, lastGroup)) {
271-
return if (lastGroup is SqlSubQueryGroupBlock) {
272-
val lastGroupChildren = lastGroup.childBlocks
273-
(lastGroupChildren.isNotEmpty() && lastGroupChildren.drop(1).isNotEmpty())
274-
} else {
275-
true
276-
}
277-
}
278-
return false
279-
}
200+
): Boolean = childBlock.isSaveSpace(lastGroup)
280201

281202
/**
282203
* Updates the parent block or registers itself as a new group block based on the class of the target block.
@@ -349,8 +270,8 @@ open class SqlBlock(
349270
)
350271
}
351272

352-
is SqlSubQueryGroupBlock -> {
353-
parentSetProcessor.updateGroupBlockParentAndAddGroup(
273+
is SqlSubGroupBlock -> {
274+
parentSetProcessor.updateSubGroupBlockParent(
354275
childBlock,
355276
)
356277
}
@@ -395,6 +316,8 @@ open class SqlBlock(
395316
*/
396317
open fun createBlockIndentLen(): Int = 0
397318

319+
open fun createGroupIndentLen(): Int = 0
320+
398321
/**
399322
* Creates a block for the given child AST node.
400323
*/
@@ -449,13 +372,27 @@ open class SqlBlock(
449372
)
450373

451374
SqlTypes.COMMA -> {
452-
return blockUtil.getCommaGroupBlock(lastGroup, child)
375+
return if (lastGroup is SqlWithQueryGroupBlock) {
376+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
377+
} else {
378+
blockUtil.getCommaGroupBlock(lastGroup, child)
379+
}
453380
}
454381

455-
SqlTypes.WORD -> return blockUtil.getWordBlock(lastGroup, child)
382+
SqlTypes.WORD -> {
383+
return if (lastGroup is SqlWithQueryGroupBlock) {
384+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
385+
} else {
386+
blockUtil.getWordBlock(lastGroup, child)
387+
}
388+
}
456389

457390
SqlTypes.BLOCK_COMMENT -> {
458-
return blockUtil.getBlockCommentBlock(child, createBlockCommentSpacingBuilder())
391+
return if (lastGroup is SqlWithCommonTableGroupBlock) {
392+
SqlWithCommonTableGroupBlock(child, defaultFormatCtx)
393+
} else {
394+
blockUtil.getBlockCommentBlock(child, createBlockCommentSpacingBuilder())
395+
}
459396
}
460397

461398
SqlTypes.LINE_COMMENT ->
@@ -555,6 +492,14 @@ open class SqlBlock(
555492
return SqlCustomSpacingBuilder().getSpacing(child2)
556493
}
557494

495+
if (child2 is SqlWithColumnGroupBlock) {
496+
return SqlCustomSpacingBuilder.normalSpacing
497+
}
498+
499+
if (child1 is SqlSubGroupBlock && child2 is SqlSubGroupBlock) {
500+
return SqlCustomSpacingBuilder.nonSpacing
501+
}
502+
558503
// Do not leave a space after the comment block of the bind variable
559504
if (child1 is SqlElBlockCommentBlock && child1 !is SqlElConditionLoopCommentBlock && child2 !is SqlCommentBlock) {
560505
return SqlCustomSpacingBuilder.nonSpacing
@@ -587,6 +532,9 @@ open class SqlBlock(
587532
}
588533

589534
if (child2 is SqlNewGroupBlock) {
535+
if (child1 is SqlSubGroupBlock && child2.indent.indentLevel == IndentType.ATTACHED) {
536+
return SqlCustomSpacingBuilder.nonSpacing
537+
}
590538
when (child2) {
591539
is SqlSubQueryGroupBlock -> {
592540
if (child1 is SqlNewGroupBlock) {

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

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,15 @@ import com.intellij.lang.ASTNode
1919
import com.intellij.psi.formatter.common.AbstractBlock
2020
import org.domaframework.doma.intellij.common.util.TypeUtil
2121
import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnRawGroupBlock
22+
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
2223
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock
2324
import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertColumnGroupBlock
25+
import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertValueGroupBlock
2426
import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateColumnGroupBlock
27+
import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateSetGroupBlock
2528
import org.domaframework.doma.intellij.formatter.block.group.keyword.update.SqlUpdateValueGroupBlock
29+
import org.domaframework.doma.intellij.formatter.block.group.keyword.with.SqlWithColumnGroupBlock
30+
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlFunctionParamBlock
2631
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlParallelListBlock
2732
import org.domaframework.doma.intellij.formatter.block.group.subgroup.SqlSubGroupBlock
2833
import org.domaframework.doma.intellij.formatter.util.IndentType
@@ -67,27 +72,38 @@ open class SqlCommaBlock(
6772
val parentIndentSyncBlockTypes =
6873
listOf(
6974
SqlUpdateColumnGroupBlock::class,
70-
SqlUpdateValueGroupBlock::class,
7175
SqlInsertColumnGroupBlock::class,
76+
SqlWithColumnGroupBlock::class,
7277
)
7378
val parentIndentLen = parent.indent.groupIndentLen
7479
if (TypeUtil.isExpectedClassType(parentIndentSyncBlockTypes, parent)) {
7580
return parentIndentLen
7681
}
7782

83+
// TODO Indent each comma in a value group so that it aligns with the position of the first value row.
84+
val parentIndentSingleSpaceTypes =
85+
listOf(
86+
SqlInsertValueGroupBlock::class,
87+
SqlUpdateValueGroupBlock::class,
88+
)
89+
if (TypeUtil.isExpectedClassType(parentIndentSingleSpaceTypes, parent)) {
90+
return parentIndentLen.plus(1)
91+
}
92+
7893
val grand = parent.parentBlock
7994
grand?.let { grand ->
8095
if (grand is SqlCreateKeywordGroupBlock) {
8196
val grandIndentLen = grand.indent.groupIndentLen
8297
return grandIndentLen.plus(parentIndentLen).minus(1)
8398
}
8499

100+
val grandIndent = grand.indent.indentLen
101+
val groupIndent = parentBlock?.indent?.groupIndentLen ?: 0
102+
85103
if (grand is SqlColumnRawGroupBlock) {
86-
val grandIndentLen = grand.indent.groupIndentLen
87-
var prevTextLen = 1
88-
parent.prevChildren?.dropLast(1)?.forEach { prev -> prevTextLen = prevTextLen.plus(prev.getNodeText().length) }
89-
return grandIndentLen.plus(prevTextLen).plus(1)
104+
return groupIndent.plus(grandIndent)
90105
}
106+
return groupIndent.plus(grandIndent).minus(1)
91107
}
92108
return parentIndentLen.plus(1)
93109
} else {
@@ -104,10 +120,24 @@ open class SqlCommaBlock(
104120
)
105121
}
106122
return parent.indent.groupIndentLen
107-
.plus(prevLen)
108123
.plus(1)
109124
}
110125
}
111126
return 1
112127
}
128+
129+
override fun isSaveSpace(lastGroup: SqlBlock?): Boolean {
130+
val exceptionTypes =
131+
listOf(
132+
SqlInsertColumnGroupBlock::class,
133+
SqlInsertValueGroupBlock::class,
134+
SqlUpdateSetGroupBlock::class,
135+
SqlUpdateColumnGroupBlock::class,
136+
SqlUpdateValueGroupBlock::class,
137+
SqlFunctionParamBlock::class,
138+
SqlWithColumnGroupBlock::class,
139+
SqlKeywordGroupBlock::class,
140+
)
141+
return TypeUtil.isExpectedClassType(exceptionTypes, parentBlock)
142+
}
113143
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@
1313
* See the License for the specific language governing permissions and
1414
* limitations under the License.
1515
*/
16-
package org.domaframework.doma.intellij.formatter.block.group.column
16+
package org.domaframework.doma.intellij.formatter.block
1717

1818
import com.intellij.lang.ASTNode
1919
import com.intellij.psi.formatter.common.AbstractBlock
20-
import org.domaframework.doma.intellij.formatter.block.SqlBlock
2120
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionRawGroupBlock
2221
import org.domaframework.doma.intellij.formatter.util.IndentType
2322
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext

0 commit comments

Comments
 (0)