Skip to content

Add Support for "exists"and "not exists" in "where" Clauses #296

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Dec 2, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
820ac22
Make SqlCriterion abstract so we can add support for exists
jeffgbutler Nov 21, 2020
94b069d
Add ExistsCriterion and renderer
jeffgbutler Nov 22, 2020
161f069
First working exists test
jeffgbutler Nov 22, 2020
7a9ad99
Basic support for not exists
jeffgbutler Nov 22, 2020
ec98ec7
Basic support for not exists
jeffgbutler Nov 23, 2020
d21764c
Remove unnecessary if statement
jeffgbutler Nov 23, 2020
7756e00
Merge branch 'master' into exists-infrastructure
jeffgbutler Nov 30, 2020
dd43a85
Merge conflict resolution
jeffgbutler Nov 30, 2020
d66bced
Example Length Function
jeffgbutler Nov 29, 2020
cca11d2
Initial refactor of where support
jeffgbutler Nov 30, 2020
3906447
More merge cleanup
jeffgbutler Nov 30, 2020
84a6523
More merge cleanup
jeffgbutler Nov 30, 2020
7784536
Remove some useless code
jeffgbutler Nov 27, 2020
688cdc8
Kotlin Polishing
jeffgbutler Nov 29, 2020
84361fd
Better Kotlin Pattern
jeffgbutler Nov 29, 2020
d6604f0
Checkstyle and Sonar Updates
jeffgbutler Nov 30, 2020
dbea6c6
Better name for the base where support class
jeffgbutler Nov 30, 2020
dc782d5
Merge conflict resolution
jeffgbutler Nov 30, 2020
075ce9d
Merge remote-tracking branch 'origin/exists-infrastructure' into exis…
jeffgbutler Nov 30, 2020
83617c2
More merge cleanup
jeffgbutler Nov 30, 2020
1ad37ec
Better exists functions
jeffgbutler Nov 30, 2020
af20a93
Copyrights and polishing
jeffgbutler Nov 30, 2020
e2a80c2
Polishing
jeffgbutler Nov 30, 2020
fa716e9
Coverage
jeffgbutler Nov 30, 2020
9c3b876
Add exists to Kotlin DSL
jeffgbutler Nov 30, 2020
d39fb6f
Detekt Updates
jeffgbutler Nov 30, 2020
7149bee
Checkstyle updates
jeffgbutler Nov 30, 2020
07cfa81
Add Exists support in the CriteriaCollector
jeffgbutler Nov 30, 2020
0ff6592
Add Exists support in the standalone where clause and top level conne…
jeffgbutler Nov 30, 2020
827a6ed
Documentation
jeffgbutler Dec 1, 2020
034c72e
Finally a better name
jeffgbutler Dec 1, 2020
6f018e2
Add PR link to changelog
jeffgbutler Dec 1, 2020
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
Prev Previous commit
Next Next commit
Add Exists support in the CriteriaCollector
  • Loading branch information
jeffgbutler committed Nov 30, 2020
commit 07cfa81d89eb023b5c39afbadb5849ab95ca2b4c
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ package org.mybatis.dynamic.sql.util.kotlin

import org.mybatis.dynamic.sql.BindableColumn
import org.mybatis.dynamic.sql.ColumnAndConditionCriterion
import org.mybatis.dynamic.sql.ExistsCriterion
import org.mybatis.dynamic.sql.SqlCriterion
import org.mybatis.dynamic.sql.VisitableCondition
import org.mybatis.dynamic.sql.where.condition.Exists

typealias CriteriaReceiver = CriteriaCollector.() -> Unit

Expand Down Expand Up @@ -51,6 +53,27 @@ class CriteriaCollector {
)
}

fun and(exists: Exists) =
apply {
criteria.add(
ExistsCriterion.Builder()
.withConnector("and")
.withExists(exists)
.build()
)
}

fun and(exists: Exists, criteriaReceiver: CriteriaReceiver) =
apply {
criteria.add(
ExistsCriterion.Builder()
.withConnector("and")
.withExists(exists)
.withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria)
.build()
)
}

fun <T> or(column: BindableColumn<T>, condition: VisitableCondition<T>) =
apply {
criteria.add(
Expand All @@ -75,4 +98,25 @@ class CriteriaCollector {
.build()
)
}

fun or(exists: Exists) =
apply {
criteria.add(
ExistsCriterion.Builder()
.withConnector("or")
.withExists(exists)
.build()
)
}

fun or(exists: Exists, criteriaReceiver: CriteriaReceiver) =
apply {
criteria.add(
ExistsCriterion.Builder()
.withConnector("or")
.withExists(exists)
.withSubCriteria(CriteriaCollector().apply(criteriaReceiver).criteria)
.build()
)
}
}
173 changes: 167 additions & 6 deletions src/test/kotlin/examples/kotlin/mybatis3/joins/ExistsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,79 @@ class ExistsTest {
}
}

@Test
fun testAndExistsAnd2() {
newSession().use { session ->
val mapper = session.getMapper(CommonSelectMapper::class.java)

val selectStatement = select(ItemMaster.allColumns()) {
from(ItemMaster, "im")
where(ItemMaster.itemId, isEqualTo(22)) {
and(exists {
select(OrderLine.allColumns()) {
from(OrderLine, "ol")
where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im")))
}
})
and(ItemMaster.itemId, isGreaterThan(2))
}
orderBy(ItemMaster.itemId)
}

val expectedStatement = "select im.* from ItemMaster im" +
" where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" +
" and exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" +
" and im.item_id > #{parameters.p2,jdbcType=INTEGER})" +
" order by item_id"
assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement)

val rows = mapper.selectManyMappedRows(selectStatement)
assertThat(rows).hasSize(1)

with(rows[0]) {
assertThat(this).containsEntry("ITEM_ID", 22)
assertThat(this).containsEntry("DESCRIPTION", "Helmet")
}
}
}

@Test
fun testAndExistsAnd3() {
newSession().use { session ->
val mapper = session.getMapper(CommonSelectMapper::class.java)

val selectStatement = select(ItemMaster.allColumns()) {
from(ItemMaster, "im")
where(ItemMaster.itemId, isEqualTo(22)) {
and(exists {
select(OrderLine.allColumns()) {
from(OrderLine, "ol")
where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im")))
}
}) {
and(ItemMaster.itemId, isGreaterThan(2))
}
}
orderBy(ItemMaster.itemId)
}

val expectedStatement = "select im.* from ItemMaster im" +
" where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" +
" and (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" +
" and im.item_id > #{parameters.p2,jdbcType=INTEGER}))" +
" order by item_id"
assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement)

val rows = mapper.selectManyMappedRows(selectStatement)
assertThat(rows).hasSize(1)

with(rows[0]) {
assertThat(this).containsEntry("ITEM_ID", 22)
assertThat(this).containsEntry("DESCRIPTION", "Helmet")
}
}
}

@Test
fun testOrExists() {
newSession().use { session ->
Expand Down Expand Up @@ -290,6 +363,99 @@ class ExistsTest {
}
}

@Test
fun testOrExistsAnd2() {
newSession().use { session ->
val mapper = session.getMapper(CommonSelectMapper::class.java)

val selectStatement = select(ItemMaster.allColumns()) {
from(ItemMaster, "im")
where(ItemMaster.itemId, isEqualTo(22)) {
or(exists {
select(OrderLine.allColumns()) {
from(OrderLine, "ol")
where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im")))
}
})
and(ItemMaster.itemId, isGreaterThan(2))
}
orderBy(ItemMaster.itemId)
}

val expectedStatement = "select im.* from ItemMaster im" +
" where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" +
" or exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" +
" and im.item_id > #{parameters.p2,jdbcType=INTEGER})" +
" order by item_id"
assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement)

val rows = mapper.selectManyMappedRows(selectStatement)
assertThat(rows).hasSize(3)

with(rows[0]) {
assertThat(this).containsEntry("ITEM_ID", 22)
assertThat(this).containsEntry("DESCRIPTION", "Helmet")
}

with(rows[1]) {
assertThat(this).containsEntry("ITEM_ID", 33)
assertThat(this).containsEntry("DESCRIPTION", "First Base Glove")
}

with(rows[2]) {
assertThat(this).containsEntry("ITEM_ID", 44)
assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove")
}
}
}

@Test
fun testOrExistsAnd3() {
newSession().use { session ->
val mapper = session.getMapper(CommonSelectMapper::class.java)

val selectStatement = select(ItemMaster.allColumns()) {
from(ItemMaster, "im")
where(ItemMaster.itemId, isEqualTo(22)) {
or(exists {
select(OrderLine.allColumns()) {
from(OrderLine, "ol")
where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im")))
}
}) {
and(ItemMaster.itemId, isGreaterThan(2))
}
}
orderBy(ItemMaster.itemId)
}

val expectedStatement = "select im.* from ItemMaster im" +
" where (im.item_id = #{parameters.p1,jdbcType=INTEGER}" +
" or (exists (select ol.* from OrderLine ol where ol.item_id = im.item_id)" +
" and im.item_id > #{parameters.p2,jdbcType=INTEGER}))" +
" order by item_id"
assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement)

val rows = mapper.selectManyMappedRows(selectStatement)
assertThat(rows).hasSize(3)

with(rows[0]) {
assertThat(this).containsEntry("ITEM_ID", 22)
assertThat(this).containsEntry("DESCRIPTION", "Helmet")
}

with(rows[1]) {
assertThat(this).containsEntry("ITEM_ID", 33)
assertThat(this).containsEntry("DESCRIPTION", "First Base Glove")
}

with(rows[2]) {
assertThat(this).containsEntry("ITEM_ID", 44)
assertThat(this).containsEntry("DESCRIPTION", "Outfield Glove")
}
}
}

@Test
fun testWhereExistsOr() {
newSession().use { session ->
Expand All @@ -300,12 +466,7 @@ class ExistsTest {
where(exists {
select(OrderLine.allColumns()) {
from(OrderLine, "ol")
where(
OrderLine.itemId,
isEqualTo(
ItemMaster.itemId.qualifiedWith("im")
)
)
where(OrderLine.itemId, isEqualTo(ItemMaster.itemId.qualifiedWith("im")))
}
}) {
or(ItemMaster.itemId, isEqualTo(22))
Expand Down