Skip to content

Commit

Permalink
feat: EXPOSED-290 Support ANY and ALL operators using array column ex…
Browse files Browse the repository at this point in the history
…pressions (#1988)

Support providing an array column or expression as an argument for existing
anyFrom() and allFrom() functions.
  • Loading branch information
bog-walk authored Feb 13, 2024
1 parent a67549c commit 6ccb996
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
8 changes: 8 additions & 0 deletions exposed-core/api/exposed-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1790,9 +1790,11 @@ public final class org/jetbrains/exposed/sql/SQLExpressionBuilderKt {
public static final fun CustomLongFunction (Ljava/lang/String;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/CustomFunction;
public static final fun CustomStringFunction (Ljava/lang/String;[Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/CustomFunction;
public static final fun allFrom (Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/Op;
public static final fun allFrom (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Op;
public static final fun allFrom (Lorg/jetbrains/exposed/sql/Table;)Lorg/jetbrains/exposed/sql/Op;
public static final fun allFrom ([Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/Op;
public static final fun anyFrom (Lorg/jetbrains/exposed/sql/AbstractQuery;)Lorg/jetbrains/exposed/sql/Op;
public static final fun anyFrom (Lorg/jetbrains/exposed/sql/Expression;)Lorg/jetbrains/exposed/sql/Op;
public static final fun anyFrom (Lorg/jetbrains/exposed/sql/Table;)Lorg/jetbrains/exposed/sql/Op;
public static final fun anyFrom ([Ljava/lang/Object;)Lorg/jetbrains/exposed/sql/Op;
public static final fun avg (Lorg/jetbrains/exposed/sql/ExpressionWithColumnType;I)Lorg/jetbrains/exposed/sql/Avg;
Expand Down Expand Up @@ -2691,6 +2693,12 @@ public abstract class org/jetbrains/exposed/sql/ops/AllAnyFromBaseOp : org/jetbr
public fun toQueryBuilder (Lorg/jetbrains/exposed/sql/QueryBuilder;)V
}

public final class org/jetbrains/exposed/sql/ops/AllAnyFromExpressionOp : org/jetbrains/exposed/sql/ops/AllAnyFromBaseOp {
public fun <init> (ZLorg/jetbrains/exposed/sql/Expression;)V
public synthetic fun registerSubSearchArgument (Lorg/jetbrains/exposed/sql/QueryBuilder;Ljava/lang/Object;)V
public fun registerSubSearchArgument (Lorg/jetbrains/exposed/sql/QueryBuilder;Lorg/jetbrains/exposed/sql/Expression;)V
}

public final class org/jetbrains/exposed/sql/ops/AllAnyFromSubQueryOp : org/jetbrains/exposed/sql/ops/AllAnyFromBaseOp {
public fun <init> (ZLorg/jetbrains/exposed/sql/AbstractQuery;)V
public synthetic fun registerSubSearchArgument (Lorg/jetbrains/exposed/sql/QueryBuilder;Ljava/lang/Object;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ fun <T> anyFrom(array: Array<T>): Op<T> = AllAnyFromArrayOp(true, array)
/** Returns this table wrapped in the `ANY` operator. This function is only supported by MySQL, PostgreSQL, and H2 dialects. */
fun <T> anyFrom(table: Table): Op<T> = AllAnyFromTableOp(true, table)

/** Returns this expression wrapped in the `ANY` operator. This function is only supported by PostgreSQL and H2 dialects. */
fun <E, T : List<E>?> anyFrom(expression: Expression<T>): Op<E> = AllAnyFromExpressionOp(true, expression)

/** Returns this subquery wrapped in the `ALL` operator. This function is not supported by the SQLite dialect. */
fun <T> allFrom(subQuery: AbstractQuery<*>): Op<T> = AllAnyFromSubQueryOp(false, subQuery)

Expand All @@ -131,6 +134,9 @@ fun <T> allFrom(array: Array<T>): Op<T> = AllAnyFromArrayOp(false, array)
/** Returns this table wrapped in the `ALL` operator. This function is only supported by MySQL, PostgreSQL, and H2 dialects. */
fun <T> allFrom(table: Table): Op<T> = AllAnyFromTableOp(false, table)

/** Returns this expression wrapped in the `ALL` operator. This function is only supported by PostgreSQL and H2 dialects. */
fun <E, T : List<E>?> allFrom(expression: Expression<T>): Op<E> = AllAnyFromExpressionOp(false, expression)

/**
* Returns the array element stored at the one-based [index] position, or `null` if the stored array itself is null.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.jetbrains.exposed.sql.ops

import org.jetbrains.exposed.sql.AbstractQuery
import org.jetbrains.exposed.sql.Expression
import org.jetbrains.exposed.sql.Op
import org.jetbrains.exposed.sql.QueryBuilder
import org.jetbrains.exposed.sql.Table
Expand Down Expand Up @@ -63,3 +64,18 @@ class AllAnyFromTableOp<T>(isAny: Boolean, table: Table) : AllAnyFromBaseOp<T, T
+subSearch.tableName
}
}

/**
* Represents an SQL operator that checks a value, based on the preceding comparison operator,
* against a collection of values returned by the provided expression.
*
* **Note** This operation is only supported by PostgreSQL and H2 dialects.
*/
class AllAnyFromExpressionOp<E, T : List<E>?>(
isAny: Boolean,
expression: Expression<T>
) : AllAnyFromBaseOp<E, Expression<T>>(isAny, expression) {
override fun QueryBuilder.registerSubSearchArgument(subSearch: Expression<T>) {
append(subSearch)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -258,4 +258,30 @@ class ArrayColumnTypeTests : DatabaseTestsBase() {
assertContentEquals(doublesInput, ArrayTestDao.all().single().doubles)
}
}

@Test
fun testArrayColumnWithAllAnyOps() {
withTables(excludeSettings = arrayTypeUnsupportedDb, ArrayTestTable) {
val numInput = listOf(1, 2, 3)
val id1 = ArrayTestTable.insertAndGetId {
it[numbers] = numInput
it[doubles] = null
}

val result1 = ArrayTestTable.select(ArrayTestTable.id).where {
ArrayTestTable.id eq anyFrom(ArrayTestTable.numbers)
}
assertEquals(id1, result1.single()[ArrayTestTable.id])

val result2 = ArrayTestTable.select(ArrayTestTable.id).where {
ArrayTestTable.id eq anyFrom(ArrayTestTable.numbers.slice(2, 3))
}
assertTrue(result2.toList().isEmpty())

val result3 = ArrayTestTable.select(ArrayTestTable.id).where {
ArrayTestTable.id lessEq allFrom(ArrayTestTable.numbers)
}
assertEquals(id1, result3.single()[ArrayTestTable.id])
}
}
}

0 comments on commit 6ccb996

Please sign in to comment.