From 21e354d865d600cd0dee0ecac4e6649a72076382 Mon Sep 17 00:00:00 2001 From: dolgopolovwork <37849469+dolgopolovwork@users.noreply.github.com> Date: Thu, 13 Feb 2020 22:27:17 +0700 Subject: [PATCH] notInSubQuery functionality (#791) --- .../kotlin/org/jetbrains/exposed/sql/Op.kt | 8 +++++++ .../exposed/sql/SQLExpressionBuilder.kt | 2 ++ .../sql/tests/shared/dml/SelectTests.kt | 24 ++++++++++++++++++- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt index ca1f4d22..88bb8feb 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/Op.kt @@ -122,6 +122,14 @@ class InSubQueryOp(val expr: Expression, val query: Query): Op() } } +class NotInSubQueryOp(val expr: Expression, val query: Query) : Op() { + override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { + append(expr, " NOT IN (") + query.prepareSQL(this) + +")" + } +} + class QueryParameter(val value: T, val sqlType: IColumnType) : Expression() { override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { registerArgument(sqlType, value) } } diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt index 1f3871a7..73fb628e 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/SQLExpressionBuilder.kt @@ -190,6 +190,8 @@ object SqlExpressionBuilder { infix fun ExpressionWithColumnType.inSubQuery(query: Query): Op = InSubQueryOp(this, query) + infix fun ExpressionWithColumnType.notInSubQuery(query: Query): Op = NotInSubQueryOp(this, query) + @Suppress("UNCHECKED_CAST") fun ExpressionWithColumnType.asLiteral(value: T) = when (value) { is Boolean -> booleanLiteral(value) diff --git a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/SelectTests.kt b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/SelectTests.kt index 652420d6..a6799931 100644 --- a/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/SelectTests.kt +++ b/exposed-tests/src/test/kotlin/org/jetbrains/exposed/sql/tests/shared/dml/SelectTests.kt @@ -5,6 +5,7 @@ import org.jetbrains.exposed.sql.* import org.jetbrains.exposed.sql.tests.DatabaseTestsBase import org.jetbrains.exposed.sql.tests.shared.assertEquals import org.junit.Test +import kotlin.test.assertNull class SelectTests : DatabaseTestsBase() { // select expressions @@ -74,7 +75,6 @@ class SelectTests : DatabaseTestsBase() { } - @Test fun testInList01() { withCitiesAndUsers { cities, users, userData -> @@ -104,6 +104,28 @@ class SelectTests : DatabaseTestsBase() { } } + @Test + fun testNotInSubQueryNoData() { + withCitiesAndUsers { cities, _, _ -> + val r = cities.select { cities.id notInSubQuery cities.slice(cities.id).selectAll() } + // no data since all ids are selected + assertEquals(0, r.count()) + } + } + + @Test + fun testNotInSubQuery() { + withCitiesAndUsers { cities, _, _ -> + val cityId = 2 + val r = cities.select { cities.id notInSubQuery cities.slice(cities.id).select { cities.id eq cityId } }.map { it[cities.id] }.sorted() + assertEquals(2, r.size) + // only 2 cities with id 1 and 2 respectively + assertEquals(1, r[0]) + assertEquals(3, r[1]) + //there is no city with id=2 + assertNull(r.find { it == cityId }) + } + } @Test fun testSelectDistinct() {