Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package org.domaframework.doma.intellij.formatter.block

import com.intellij.lang.ASTNode
import com.intellij.psi.formatter.common.AbstractBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.SqlNewGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
Expand Down Expand Up @@ -95,7 +96,11 @@ open class SqlKeywordBlock(
}

else -> {
parentBlock?.indent?.groupIndentLen ?: 1
if (parentBlock is SqlElConditionLoopCommentBlock) {
parentBlock?.indent?.groupIndentLen ?: 1
} else {
parentBlock?.indent?.groupIndentLen?.plus(1) ?: 1
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright Doma Tools Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.domaframework.doma.intellij.formatter.block.group.keyword.option

import com.intellij.lang.ASTNode
import org.domaframework.doma.intellij.formatter.block.SqlBlock
import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionRawGroupBlock
import org.domaframework.doma.intellij.formatter.util.IndentType
import org.domaframework.doma.intellij.formatter.util.SqlBlockFormattingContext

class SqlExistsGroupBlock(
node: ASTNode,
context: SqlBlockFormattingContext,
) : SqlKeywordGroupBlock(node, IndentType.OPTIONS, context) {
override fun setParentGroupBlock(lastGroup: SqlBlock?) {
super.setParentGroupBlock(lastGroup)
indent.indentLen = createBlockIndentLen()
indent.groupIndentLen = createGroupIndentLen()
}

override fun createBlockIndentLen(): Int {
parentBlock?.let { parent ->
if (parent.parentBlock is SqlElConditionLoopCommentBlock) {
return parent.indent.groupIndentLen
}
}
return parentBlock?.indent?.groupIndentLen?.plus(1) ?: 1
}

override fun createGroupIndentLen(): Int {
val parentGroupIndent = parentBlock?.indent?.groupIndentLen ?: 0
return topKeywordBlocks.sumOf { it.getNodeText().length.plus(1) }.plus(parentGroupIndent).minus(1)
}

override fun isSaveSpace(lastGroup: SqlBlock?): Boolean {
if (lastGroup is SqlCreateTableColumnDefinitionRawGroupBlock) {
return false
}
return super.isSaveSpace(lastGroup)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ open class SqlSubQueryGroupBlock(
is SqlJoinQueriesGroupBlock -> return parent.indent.indentLen
is SqlJoinGroupBlock -> return parent.indent.groupIndentLen.plus(1)
else -> {
val children =
prevChildren?.filter {
it !is SqlDefaultCommentBlock &&
(parent as? SqlKeywordGroupBlock)?.topKeywordBlocks?.contains(it) == false
}
val children = prevChildren?.filter { shouldIncludeChildBlock(it, parent) }
// Retrieve the list of child blocks excluding the conditional directive that appears immediately before this block,
// as it is already included as a child block.
val sumChildren =
Expand All @@ -90,6 +86,13 @@ open class SqlSubQueryGroupBlock(
}
} ?: offset

private fun shouldIncludeChildBlock(
block: SqlBlock,
parent: SqlBlock,
): Boolean =
block !is SqlDefaultCommentBlock &&
(parent as? SqlKeywordGroupBlock)?.topKeywordBlocks?.contains(block) == false

override fun createGroupIndentLen(): Int {
parentBlock?.let { parent ->
if (parent is SqlJoinQueriesGroupBlock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.SqlKeywordG
import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateViewGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineSecondGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlExistsGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlInGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlLateralGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlReturningGroupBlock
Expand Down Expand Up @@ -64,6 +65,7 @@ class SqlBlockRelationBuilder(
SqlColumnDefinitionRawGroupBlock::class,
SqlLateralGroupBlock::class,
SqlInGroupBlock::class,
SqlExistsGroupBlock::class,
)

private val TOP_LEVEL_EXPECTED_TYPES =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ object JoinClauseHandler {
child: ASTNode,
sqlBlockFormattingCtx: SqlBlockFormattingContext,
): SqlBlock =
if (SqlKeywordUtil.Companion.isJoinKeyword(keywordText)) {
if (SqlKeywordUtil.isJoinKeyword(keywordText)) {
SqlJoinGroupBlock(
child,
sqlBlockFormattingCtx,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlC
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.inline.SqlInlineSecondGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.insert.SqlInsertQueryGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlExistsGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlInGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlLateralGroupBlock
import org.domaframework.doma.intellij.formatter.block.group.keyword.option.SqlSecondOptionKeywordGroupBlock
Expand Down Expand Up @@ -148,6 +149,24 @@ class SqlBlockGenerator(
sqlBlockFormattingCtx,
)
}

if (SqlKeywordUtil.isExistsKeyword(keywordText)) {
if (lastGroupBlock is SqlExistsGroupBlock) {
return SqlKeywordBlock(
child,
indentLevel,
sqlBlockFormattingCtx,
)
}
if (lastGroupBlock is SqlElConditionLoopCommentBlock && lastGroupBlock.conditionType.isElse() ||
keywordText == "not" && (lastGroupBlock !is SqlConditionKeywordGroupBlock && lastGroupBlock !is SqlWhereGroupBlock)
) {
return SqlExistsGroupBlock(
child,
sqlBlockFormattingCtx,
)
}
}
}

IndentType.CONFLICT -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,15 @@ class SqlKeywordUtil {

fun isWithOptionKeyword(keyword: String): Boolean = WITH_OPTION_KEYWORDS.contains(keyword.lowercase())

private val EXISTS_KEYWORDS =
setOf(
"if",
"exists",
"not",
)

fun isExistsKeyword(keyword: String): Boolean = EXISTS_KEYWORDS.contains(keyword.lowercase())

private val SET_LINE_KEYWORDS =
mapOf(
"into" to setOf("insert"),
Expand All @@ -307,6 +316,7 @@ class SqlKeywordUtil {
"by" to setOf("group", "order", "first"),
"and" to setOf("between"),
"if" to setOf("table", "create"),
"exists" to setOf("if", "where"),
"conflict" to setOf("on"),
"nothing" to setOf("do"),
"constraint" to setOf("on"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,10 @@ class SqlFormatterTest : BasePlatformTestCase() {
formatSqlFile("ConditionalSubquery.sql", "ConditionalSubquery$formatDataPrefix.sql")
}

fun testConditionalExistsFormatter() {
formatSqlFile("ConditionalExists.sql", "ConditionalExists$formatDataPrefix.sql")
}

private fun formatSqlFile(
beforeFile: String,
afterFile: String,
Expand Down
49 changes: 49 additions & 0 deletions src/test/testData/sql/formatter/ConditionalExists.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
SELECT e.id
, e.name
, d.department_name
FROM employees e /*%if join */
INNER JOIN separators spr
ON EXISTS ( SELECT id FROM spr )
/*%end */
WHERE
/*%if isNot*/
NOT
/*%end*/
/*%if filterByHighPerformers */
EXISTS ( SELECT 1
FROM performance_reviews pr
WHERE pr.employee_id = e.id
/*%if reviewPeriod != null */
AND pr.review_date BETWEEN /* reviewPeriod.startDate */'2023-01-01' AND /* reviewPeriod.endDate */'2023-12-31'
/*%end*/
/*%if minScore != null */
AND pr.performance_score >= /* minScore */4.0
/*%end*/ )
/*%elseif filterByLowPerformers */
/*%if isNot*/
NOT
/*%end*/
EXISTS ( SELECT 1
FROM performance_reviews pr
WHERE pr.employee_id = e.id
/*%if reviewPeriod != null */
AND pr.review_date BETWEEN /* reviewPeriod.startDate */'2023-01-01' AND /* reviewPeriod.endDate */'2023-12-31'
/*%end*/
/*%if minScore != null */
AND pr.performance_score >= /* minScore */4.0
/*%end*/ )
/*%elseif filterByMediumPerformers */
NOT
EXISTS
( SELECT 1
FROM performance_reviews pr
WHERE pr.employee_id = e.id
/*%if reviewPeriod != null */
AND pr.review_date BETWEEN /* reviewPeriod.startDate */'2023-01-01' AND /* reviewPeriod.endDate */'2023-12-31'
/*%end*/
/*%if minScore != null */
AND pr.performance_score >= /* minScore */4.0
/*%end*/ )
/*%else*/
e.is_active = true
/*%end*/
49 changes: 49 additions & 0 deletions src/test/testData/sql/formatter/ConditionalExists_format.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
SELECT e.id
, e.name
, d.department_name
FROM employees e
/*%if join */
INNER JOIN separators spr
ON EXISTS ( SELECT id
FROM spr )
/*%end */
WHERE
/*%if isNot*/
NOT
/*%end*/
/*%if filterByHighPerformers */
EXISTS ( SELECT 1
FROM performance_reviews pr
WHERE pr.employee_id = e.id
/*%if reviewPeriod != null */
AND pr.review_date BETWEEN /* reviewPeriod.startDate */'2023-01-01' AND /* reviewPeriod.endDate */'2023-12-31'
/*%end*/
/*%if minScore != null */
AND pr.performance_score >= /* minScore */4.0
/*%end*/ )
/*%elseif filterByLowPerformers */
/*%if isNot*/
NOT
/*%end*/
EXISTS ( SELECT 1
FROM performance_reviews pr
WHERE pr.employee_id = e.id
/*%if reviewPeriod != null */
AND pr.review_date BETWEEN /* reviewPeriod.startDate */'2023-01-01' AND /* reviewPeriod.endDate */'2023-12-31'
/*%end*/
/*%if minScore != null */
AND pr.performance_score >= /* minScore */4.0
/*%end*/ )
/*%elseif filterByMediumPerformers */
NOT EXISTS ( SELECT 1
FROM performance_reviews pr
WHERE pr.employee_id = e.id
/*%if reviewPeriod != null */
AND pr.review_date BETWEEN /* reviewPeriod.startDate */'2023-01-01' AND /* reviewPeriod.endDate */'2023-12-31'
/*%end*/
/*%if minScore != null */
AND pr.performance_score >= /* minScore */4.0
/*%end*/ )
/*%else*/
e.is_active = true
/*%end*/
Loading