diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt index 2b0cd5bf..fd2ef97c 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/SqlKeywordBlock.kt @@ -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 @@ -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 + } } } } diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/option/SqlExistsGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/option/SqlExistsGroupBlock.kt new file mode 100644 index 00000000..03f7013a --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/keyword/option/SqlExistsGroupBlock.kt @@ -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) + } +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt index faea6ab8..19ec3387 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/block/group/subgroup/SqlSubQueryGroupBlock.kt @@ -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 = @@ -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) { diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockRelationBuilder.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockRelationBuilder.kt index e4106390..6ff1f11d 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockRelationBuilder.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/builder/SqlBlockRelationBuilder.kt @@ -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 @@ -64,6 +65,7 @@ class SqlBlockRelationBuilder( SqlColumnDefinitionRawGroupBlock::class, SqlLateralGroupBlock::class, SqlInGroupBlock::class, + SqlExistsGroupBlock::class, ) private val TOP_LEVEL_EXPECTED_TYPES = diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/JoinClauseHandler.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/JoinClauseHandler.kt index 28aa2dc5..99a987a4 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/JoinClauseHandler.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/handler/JoinClauseHandler.kt @@ -30,7 +30,7 @@ object JoinClauseHandler { child: ASTNode, sqlBlockFormattingCtx: SqlBlockFormattingContext, ): SqlBlock = - if (SqlKeywordUtil.Companion.isJoinKeyword(keywordText)) { + if (SqlKeywordUtil.isJoinKeyword(keywordText)) { SqlJoinGroupBlock( child, sqlBlockFormattingCtx, diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockGenerator.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockGenerator.kt index 3ea84ce3..419793df 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockGenerator.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlBlockGenerator.kt @@ -30,7 +30,6 @@ import org.domaframework.doma.intellij.formatter.block.comment.SqlBlockCommentBl import org.domaframework.doma.intellij.formatter.block.comment.SqlCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElBlockCommentBlock import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock -import org.domaframework.doma.intellij.formatter.block.conflict.OnConflictKeywordType import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock import org.domaframework.doma.intellij.formatter.block.conflict.SqlDoGroupBlock import org.domaframework.doma.intellij.formatter.block.group.column.SqlColumnBlock @@ -41,12 +40,8 @@ import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.S import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateTableColumnDefinitionRawGroupBlock -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.insert.SqlInsertQueryGroupBlock -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 import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlFromGroupBlock import org.domaframework.doma.intellij.formatter.block.group.keyword.second.SqlSecondKeywordBlock @@ -99,12 +94,12 @@ class SqlBlockGenerator( formatMode, ) + private val keywordBlockFactory = SqlKeywordBlockFactory(sqlBlockFormattingCtx) + fun getKeywordBlock( child: ASTNode, lastGroupBlock: SqlBlock?, ): SqlBlock { - // Because we haven't yet set the parent-child relationship of the block, - // the parent group references groupTopNodeIndexHistory. val keywordText = child.text.lowercase() val indentLevel = SqlKeywordUtil.getIndentType(keywordText) @@ -112,56 +107,13 @@ class SqlBlockGenerator( return getKeywordGroupBlock(indentLevel, keywordText, child, lastGroupBlock) } - when (indentLevel) { - IndentType.INLINE -> { - if (!SqlKeywordUtil.isSetLineKeyword( - child.text, - lastGroupBlock?.getNodeText() ?: "", - ) - ) { - return SqlInlineGroupBlock(child, sqlBlockFormattingCtx) - } - } - - IndentType.ATTACHED -> { - if (lastGroupBlock is SqlCreateKeywordGroupBlock) { - lastGroupBlock.setCreateQueryType(child.text) - return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) - } - } - - IndentType.OPTIONS -> { - if (keywordText == "as") { - val parentCreateBlock = - lastGroupBlock as? SqlCreateKeywordGroupBlock - ?: lastGroupBlock?.parentBlock as? SqlCreateKeywordGroupBlock - if (parentCreateBlock != null && parentCreateBlock.createType == CreateQueryType.VIEW) { - return SqlCreateViewGroupBlock(child, sqlBlockFormattingCtx) - } - } - if (keywordText == "lateral") { - return SqlLateralGroupBlock(child, sqlBlockFormattingCtx) - } - if (keywordText == "in") { - return SqlInGroupBlock( - child, - sqlBlockFormattingCtx, - ) - } - } - - IndentType.CONFLICT -> { - if (lastGroupBlock is SqlConflictClauseBlock) { - lastGroupBlock.conflictType = OnConflictKeywordType.of(keywordText) - return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) - } else { - return SqlConflictClauseBlock(child, sqlBlockFormattingCtx) - } - } - - else -> return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) + return when (indentLevel) { + IndentType.INLINE -> keywordBlockFactory.createInlineBlock(child, lastGroupBlock) + IndentType.ATTACHED -> keywordBlockFactory.createAttachedBlock(child, lastGroupBlock) + IndentType.OPTIONS -> keywordBlockFactory.createOptionsBlock(keywordText, child, lastGroupBlock) + IndentType.CONFLICT -> keywordBlockFactory.createConflictBlock(keywordText, child, lastGroupBlock) + else -> SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) } - return SqlKeywordBlock(child, indentLevel, sqlBlockFormattingCtx) } private fun getKeywordGroupBlock( diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordBlockFactory.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordBlockFactory.kt new file mode 100644 index 00000000..926db5d4 --- /dev/null +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordBlockFactory.kt @@ -0,0 +1,138 @@ +/* + * 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.util + +import com.intellij.lang.ASTNode +import org.domaframework.doma.intellij.formatter.block.SqlBlock +import org.domaframework.doma.intellij.formatter.block.SqlKeywordBlock +import org.domaframework.doma.intellij.formatter.block.comment.SqlElConditionLoopCommentBlock +import org.domaframework.doma.intellij.formatter.block.conflict.OnConflictKeywordType +import org.domaframework.doma.intellij.formatter.block.conflict.SqlConflictClauseBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.condition.SqlConditionKeywordGroupBlock +import org.domaframework.doma.intellij.formatter.block.group.keyword.create.SqlCreateKeywordGroupBlock +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.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.SqlWhereGroupBlock + +/** + * Factory class for creating SQL keyword blocks based on indent type and context + */ +class SqlKeywordBlockFactory( + private val sqlBlockFormattingCtx: SqlBlockFormattingContext, +) { + fun createInlineBlock( + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock = + if (!SqlKeywordUtil.isSetLineKeyword( + child.text, + lastGroupBlock?.getNodeText() ?: "", + ) + ) { + SqlInlineGroupBlock(child, sqlBlockFormattingCtx) + } else { + SqlKeywordBlock(child, IndentType.INLINE, sqlBlockFormattingCtx) + } + + fun createAttachedBlock( + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock { + if (lastGroupBlock is SqlCreateKeywordGroupBlock) { + lastGroupBlock.setCreateQueryType(child.text) + } + return SqlKeywordBlock(child, IndentType.ATTACHED, sqlBlockFormattingCtx) + } + + fun createOptionsBlock( + keywordText: String, + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock { + // Handle AS keyword for CREATE VIEW + if (keywordText == "as") { + val parentCreateBlock = findParentCreateBlock(lastGroupBlock) + if (parentCreateBlock?.createType == CreateQueryType.VIEW) { + return SqlCreateViewGroupBlock(child, sqlBlockFormattingCtx) + } + } + + // Handle LATERAL keyword + if (keywordText == "lateral") { + return SqlLateralGroupBlock(child, sqlBlockFormattingCtx) + } + + // Handle IN keyword + if (keywordText == "in") { + return SqlInGroupBlock(child, sqlBlockFormattingCtx) + } + + // Handle EXISTS/NOT EXISTS keywords + if (SqlKeywordUtil.isExistsKeyword(keywordText)) { + return createExistsBlock(keywordText, child, lastGroupBlock) + } + + return SqlKeywordBlock(child, IndentType.OPTIONS, sqlBlockFormattingCtx) + } + + fun createConflictBlock( + keywordText: String, + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock = + if (lastGroupBlock is SqlConflictClauseBlock) { + lastGroupBlock.conflictType = OnConflictKeywordType.of(keywordText) + SqlKeywordBlock(child, IndentType.CONFLICT, sqlBlockFormattingCtx) + } else { + SqlConflictClauseBlock(child, sqlBlockFormattingCtx) + } + + private fun findParentCreateBlock(block: SqlBlock?): SqlCreateKeywordGroupBlock? = + when (block) { + is SqlCreateKeywordGroupBlock -> block + else -> block?.parentBlock as? SqlCreateKeywordGroupBlock + } + + private fun createExistsBlock( + keywordText: String, + child: ASTNode, + lastGroupBlock: SqlBlock?, + ): SqlBlock { + // If already in EXISTS group, just return a keyword block + if (lastGroupBlock is SqlExistsGroupBlock) { + return SqlKeywordBlock(child, IndentType.OPTIONS, sqlBlockFormattingCtx) + } + + // Check for ELSE condition or NOT keyword outside WHERE/condition context + val shouldCreateExistsGroup = + when { + lastGroupBlock is SqlElConditionLoopCommentBlock && lastGroupBlock.conditionType.isElse() -> true + keywordText == "not" && !isInConditionContext(lastGroupBlock) -> true + else -> false + } + + return if (shouldCreateExistsGroup) { + SqlExistsGroupBlock(child, sqlBlockFormattingCtx) + } else { + SqlKeywordBlock(child, IndentType.OPTIONS, sqlBlockFormattingCtx) + } + } + + private fun isInConditionContext(block: SqlBlock?): Boolean = block is SqlConditionKeywordGroupBlock || block is SqlWhereGroupBlock +} diff --git a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt index 7aef2483..5fdc0a3e 100644 --- a/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt +++ b/src/main/kotlin/org/domaframework/doma/intellij/formatter/util/SqlKeywordUtil.kt @@ -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"), @@ -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"), diff --git a/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt b/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt index cc07e945..ca0f6030 100644 --- a/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt +++ b/src/test/kotlin/org/domaframework/doma/intellij/formatter/SqlFormatterTest.kt @@ -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, diff --git a/src/test/testData/sql/formatter/ConditionalExists.sql b/src/test/testData/sql/formatter/ConditionalExists.sql new file mode 100644 index 00000000..b864503b --- /dev/null +++ b/src/test/testData/sql/formatter/ConditionalExists.sql @@ -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*/ diff --git a/src/test/testData/sql/formatter/ConditionalExists_format.sql b/src/test/testData/sql/formatter/ConditionalExists_format.sql new file mode 100644 index 00000000..b850a000 --- /dev/null +++ b/src/test/testData/sql/formatter/ConditionalExists_format.sql @@ -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*/