From 48de92415552959de997b2eb82613cfb71d4d01b Mon Sep 17 00:00:00 2001 From: Jocelyne Date: Mon, 27 Jan 2025 11:58:50 +0100 Subject: [PATCH 1/2] feat: EXPOSED-697 Add `lessSubQuery`, `lessEqSubQuery`, `greaterSubQuery`, and `greaterEqSubQuery` operators --- exposed-core/api/exposed-core.api | 28 +++++++++++++ .../kotlin/org/jetbrains/exposed/sql/Op.kt | 20 ++++++++++ .../exposed/sql/SQLExpressionBuilder.kt | 12 ++++++ .../sql/tests/shared/dml/SelectTests.kt | 40 +++++++++++++++++++ 4 files changed, 100 insertions(+) diff --git a/exposed-core/api/exposed-core.api b/exposed-core/api/exposed-core.api index 798e1216dc..398a3224b9 100644 --- a/exposed-core/api/exposed-core.api +++ b/exposed-core/api/exposed-core.api @@ -1045,10 +1045,18 @@ public final class org/jetbrains/exposed/sql/GreaterEqOp : org/jetbrains/exposed public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)V } +public final class org/jetbrains/exposed/sql/GreaterEqSubQueryOp : org/jetbrains/exposed/sql/SubQueryOp { + public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)V +} + public final class org/jetbrains/exposed/sql/GreaterOp : org/jetbrains/exposed/sql/ComparisonOp { public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)V } +public final class org/jetbrains/exposed/sql/GreaterSubQueryOp : org/jetbrains/exposed/sql/SubQueryOp { + public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)V +} + public final class org/jetbrains/exposed/sql/GroupConcat : org/jetbrains/exposed/sql/Function { public fun (Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;Z[Lkotlin/Pair;)V public final fun getDistinct ()Z @@ -1140,6 +1148,8 @@ public abstract interface class org/jetbrains/exposed/sql/ISqlExpressionBuilder public abstract fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp; public abstract fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/GreaterEqOp; public abstract fun greaterEqEntityID (Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp; + public abstract fun greaterEqSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/GreaterEqSubQueryOp; + public abstract fun greaterSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/GreaterSubQueryOp; public abstract fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/EqOp; public abstract fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/EqOp; public abstract fun inList (Ljava/util/List;Ljava/lang/Iterable;)Lorg/jetbrains/exposed/sql/ops/InListOrNotInListBaseOp; @@ -1178,6 +1188,8 @@ public abstract interface class org/jetbrains/exposed/sql/ISqlExpressionBuilder public abstract fun lessEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessEqOp; public abstract fun lessEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/LessEqOp; public abstract fun lessEqEntityID (Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessEqOp; + public abstract fun lessEqSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/LessEqSubQueryOp; + public abstract fun lessSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/LessSubQueryOp; public abstract fun like (Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; public abstract fun like (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; public abstract fun like (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/LikePattern;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; @@ -1274,6 +1286,8 @@ public final class org/jetbrains/exposed/sql/ISqlExpressionBuilder$DefaultImpls public static fun greaterEq (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp; public static fun greaterEq (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/GreaterEqOp; public static fun greaterEqEntityID (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp; + public static fun greaterEqSubQuery (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/GreaterEqSubQueryOp; + public static fun greaterSubQuery (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/GreaterSubQueryOp; public static fun hasFlag (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/EqOp; public static fun hasFlag (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/EqOp; public static fun inList (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Ljava/util/List;Ljava/lang/Iterable;)Lorg/jetbrains/exposed/sql/ops/InListOrNotInListBaseOp; @@ -1314,6 +1328,8 @@ public final class org/jetbrains/exposed/sql/ISqlExpressionBuilder$DefaultImpls public static fun lessEq (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessEqOp; public static fun lessEq (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/LessEqOp; public static fun lessEqEntityID (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessEqOp; + public static fun lessEqSubQuery (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/LessEqSubQueryOp; + public static fun lessSubQuery (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/LessSubQueryOp; public static fun like (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; public static fun like (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; public static fun like (Lorg/jetbrains/exposed/sql/ISqlExpressionBuilder;Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/LikePattern;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; @@ -1559,10 +1575,18 @@ public final class org/jetbrains/exposed/sql/LessEqOp : org/jetbrains/exposed/sq public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)V } +public final class org/jetbrains/exposed/sql/LessEqSubQueryOp : org/jetbrains/exposed/sql/SubQueryOp { + public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)V +} + public final class org/jetbrains/exposed/sql/LessOp : org/jetbrains/exposed/sql/ComparisonOp { public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;)V } +public final class org/jetbrains/exposed/sql/LessSubQueryOp : org/jetbrains/exposed/sql/SubQueryOp { + public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)V +} + public final class org/jetbrains/exposed/sql/LikeEscapeOp : org/jetbrains/exposed/sql/ComparisonOp { public fun (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/Expression;ZLjava/lang/Character;)V public final fun getEscapeChar ()Ljava/lang/Character; @@ -2356,6 +2380,8 @@ public final class org/jetbrains/exposed/sql/SqlExpressionBuilder : org/jetbrain public fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp; public fun greaterEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/GreaterEqOp; public fun greaterEqEntityID (Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/GreaterEqOp; + public fun greaterEqSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/GreaterEqSubQueryOp; + public fun greaterSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/GreaterSubQueryOp; public fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/EqOp; public fun hasFlag (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/EqOp; public fun inList (Ljava/util/List;Ljava/lang/Iterable;)Lorg/jetbrains/exposed/sql/ops/InListOrNotInListBaseOp; @@ -2394,6 +2420,8 @@ public final class org/jetbrains/exposed/sql/SqlExpressionBuilder : org/jetbrain public fun lessEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessEqOp; public fun lessEq (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/LessEqOp; public fun lessEqEntityID (Lorg/jetbrains/exposed/sql/Column;Ljava/lang/Comparable;)Lorg/jetbrains/exposed/sql/LessEqOp; + public fun lessEqSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/LessEqSubQueryOp; + public fun lessSubQuery (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/LessSubQueryOp; public fun like (Lorg/jetbrains/exposed/sql/Expression;Ljava/lang/String;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; public fun like (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; public fun like (Lorg/jetbrains/exposed/sql/Expression;Lorg/jetbrains/exposed/sql/LikePattern;)Lorg/jetbrains/exposed/sql/LikeEscapeOp; 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 7cb136c30c..cee07f6cdb 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 @@ -627,6 +627,26 @@ class EqSubQueryOp(expr: Expression, query: AbstractQuery<*>) : SubQueryOp */ class NotEqSubQueryOp(expr: Expression, query: AbstractQuery<*>) : SubQueryOp("!=", expr, query) +/** + * Represents an SQL operator that checks if [expr] is less than the single value returned from [query]. + */ +class LessSubQueryOp(expr: Expression, query: AbstractQuery<*>) : SubQueryOp("<", expr, query) + +/** + * Represents an SQL operator that checks if [expr] is less than or equal to the single value returned from [query]. + */ +class LessEqSubQueryOp(expr: Expression, query: AbstractQuery<*>) : SubQueryOp("<=", expr, query) + +/** + * Represents an SQL operator that checks if [expr] is greater than the single value returned from [query]. + */ +class GreaterSubQueryOp(expr: Expression, query: AbstractQuery<*>) : SubQueryOp(">", expr, query) + +/** + * Represents an SQL operator that checks if [expr] is greater than or equal to the single value returned from [query]. + */ +class GreaterEqSubQueryOp(expr: Expression, query: AbstractQuery<*>) : SubQueryOp(">=", expr, query) + // Literals /** 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 6a4cbc708f..517f77c91f 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 @@ -881,6 +881,18 @@ interface ISqlExpressionBuilder { /** Checks if this expression is not equals to single value returned from [query]. */ infix fun Expression.notEqSubQuery(query: AbstractQuery<*>): NotEqSubQueryOp = NotEqSubQueryOp(this, query) + /** Checks if this expression is less than the single value returned from [query]. */ + infix fun Expression.lessSubQuery(query: AbstractQuery<*>): LessSubQueryOp = LessSubQueryOp(this, query) + + /** Checks if this expression is less than or equal to the single value returned from [query]. */ + infix fun Expression.lessEqSubQuery(query: AbstractQuery<*>): LessEqSubQueryOp = LessEqSubQueryOp(this, query) + + /** Checks if this expression is greater than the single value returned from [query]. */ + infix fun Expression.greaterSubQuery(query: AbstractQuery<*>): GreaterSubQueryOp = GreaterSubQueryOp(this, query) + + /** Checks if this expression is greater than or equal to the single value returned from [query]. */ + infix fun Expression.greaterEqSubQuery(query: AbstractQuery<*>): GreaterEqSubQueryOp = GreaterEqSubQueryOp(this, query) + // Array Comparisons /** 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 2e53070cb0..c37dea3c8c 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 @@ -278,6 +278,46 @@ class SelectTests : DatabaseTestsBase() { } } + @Test + fun testLessSubQuery() { + withCitiesAndUsers { _, _, userData -> + val query = userData.selectAll().where { + userData.value lessSubQuery userData.select(userData.value).where { userData.user_id eq "sergey" } + } + assertEquals(3, query.count()) + } + } + + @Test + fun testLessEqSubQuery() { + withCitiesAndUsers { _, _, userData -> + val query = userData.selectAll().where { + userData.value lessEqSubQuery userData.select(userData.value).where { userData.user_id eq "eugene" } + } + assertEquals(3, query.count()) + } + } + + @Test + fun testGreaterSubQuery() { + withCitiesAndUsers { _, _, userData -> + val query = userData.selectAll().where { + userData.value greaterSubQuery userData.select(userData.value).where { userData.value eq 10 } + } + assertEquals(3, query.count()) + } + } + + @Test + fun testGreaterEqSubQuery() { + withCitiesAndUsers { _, _, userData -> + val query = userData.selectAll().where { + userData.value greaterEqSubQuery userData.select(userData.value).where { userData.value eq 10 } + } + assertEquals(4, query.count()) + } + } + private val testDBsSupportingInAnyAllFromTables = TestDB.ALL_POSTGRES + TestDB.ALL_H2 + TestDB.MYSQL_V8 @Test From 4464cb34ed24ce254c41c242b905b028c0f3bcc5 Mon Sep 17 00:00:00 2001 From: Jocelyne Date: Mon, 27 Jan 2025 12:13:44 +0100 Subject: [PATCH 2/2] test: Add tests for `eqSubQuery` and `notEqSubQuery` operators --- .../sql/tests/shared/dml/SelectTests.kt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) 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 c37dea3c8c..93caf16546 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 @@ -278,6 +278,26 @@ class SelectTests : DatabaseTestsBase() { } } + @Test + fun testEqSubQuery() { + withCitiesAndUsers { _, _, userData -> + val query = userData.selectAll().where { + userData.value eqSubQuery userData.select(userData.value).where { userData.user_id eq "eugene" } + } + assertEquals(2, query.count()) + } + } + + @Test + fun testNotEqSubQuery() { + withCitiesAndUsers { _, _, userData -> + val query = userData.selectAll().where { + userData.value notEqSubQuery userData.select(userData.value).where { userData.user_id eq "sergey" } + } + assertEquals(3, query.count()) + } + } + @Test fun testLessSubQuery() { withCitiesAndUsers { _, _, userData ->