From b70b683e347a1b80ef0bcb1829325bf64eb0c10f Mon Sep 17 00:00:00 2001 From: Jocelyne Date: Wed, 28 Feb 2024 13:58:33 +0100 Subject: [PATCH] refactor: Make call to `registerArgument` function type-safe in AllAnyFromArrayOp.kt When calling the `registerArgument` function in the overriden `registerSubSearchArgument` function in `AllAnyFromArrayOp`, there is a type mismatch between `sqlType` and `argument`'s type because there is a compile-time guarantee that ArrayColumnType only receives a value of type `List` and not `Array`. This mismatch results in a compilation error when trying to guarantee type-safety with the refactor of IColumnType. Therefore, this is a necessary preparation step for the refactor of IColumnType to make it and its subclasses type-safe. To avoid introducing a breaking change, the functions `anyFrom` and `allFrom` in SQLExpressionBuilder.kt retain the same signature, but convert the `Array` to a `List`. In addition, these two functions were overloaded with ones that accept `List` instead of `Array`. --- exposed-core/api/exposed-core.api | 4 +-- .../exposed/sql/SQLExpressionBuilder.kt | 32 ++++++++++++++++++- .../jetbrains/exposed/sql/ops/AllAnyOps.kt | 6 ++-- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/exposed-core/api/exposed-core.api b/exposed-core/api/exposed-core.api index 20adcaeae1..6647990370 100644 --- a/exposed-core/api/exposed-core.api +++ b/exposed-core/api/exposed-core.api @@ -2696,9 +2696,9 @@ public final class org/jetbrains/exposed/sql/functions/math/TanFunction : org/je } public final class org/jetbrains/exposed/sql/ops/AllAnyFromArrayOp : org/jetbrains/exposed/sql/ops/AllAnyFromBaseOp { - public fun (Z[Ljava/lang/Object;Lorg/jetbrains/exposed/sql/ColumnType;)V + public fun (ZLjava/util/List;Lorg/jetbrains/exposed/sql/ColumnType;)V public synthetic fun registerSubSearchArgument (Lorg/jetbrains/exposed/sql/QueryBuilder;Ljava/lang/Object;)V - public fun registerSubSearchArgument (Lorg/jetbrains/exposed/sql/QueryBuilder;[Ljava/lang/Object;)V + public fun registerSubSearchArgument (Lorg/jetbrains/exposed/sql/QueryBuilder;Ljava/util/List;)V } public abstract class org/jetbrains/exposed/sql/ops/AllAnyFromBaseOp : org/jetbrains/exposed/sql/Op { 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 be9e9495b4..8b5312a626 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 @@ -128,6 +128,21 @@ inline fun anyFrom(array: Array, delegateType: ColumnType? // emptyArray() without type info generates ARRAY[] @OptIn(InternalApi::class) val columnType = delegateType ?: resolveColumnType(T::class, if (array.isEmpty()) TextColumnType() else null) + return AllAnyFromArrayOp(true, array.toList(), columnType) +} + +/** + * Returns this list of data wrapped in the `ANY` operator. This function is only supported by PostgreSQL and H2 dialects. + * + * **Note** If [delegateType] is left `null`, the base column type associated with storing elements of type [T] will be + * resolved according to the internal mapping of the element's type in [resolveColumnType]. + * + * @throws IllegalStateException If no column type mapping is found and a [delegateType] is not provided. + */ +inline fun anyFrom(array: List, delegateType: ColumnType? = null): Op { + // emptyList() without type info generates ARRAY[] + @OptIn(InternalApi::class) + val columnType = delegateType ?: resolveColumnType(T::class, if (array.isEmpty()) TextColumnType() else null) return AllAnyFromArrayOp(true, array, columnType) } @@ -152,6 +167,21 @@ inline fun allFrom(array: Array, delegateType: ColumnType? // emptyArray() without type info generates ARRAY[] @OptIn(InternalApi::class) val columnType = delegateType ?: resolveColumnType(T::class, if (array.isEmpty()) TextColumnType() else null) + return AllAnyFromArrayOp(false, array.toList(), columnType) +} + +/** + * Returns this list of data wrapped in the `ALL` operator. This function is only supported by PostgreSQL and H2 dialects. + * + * **Note** If [delegateType] is left `null`, the base column type associated with storing elements of type [T] will be + * resolved according to the internal mapping of the element's type in [resolveColumnType]. + * + * @throws IllegalStateException If no column type mapping is found and a [delegateType] is not provided. + */ +inline fun allFrom(array: List, delegateType: ColumnType? = null): Op { + // emptyList() without type info generates ARRAY[] + @OptIn(InternalApi::class) + val columnType = delegateType ?: resolveColumnType(T::class, if (array.isEmpty()) TextColumnType() else null) return AllAnyFromArrayOp(false, array, columnType) } @@ -177,7 +207,7 @@ infix operator fun ?> ExpressionWithColumnType.get(index: Int) * @sample org.jetbrains.exposed.sql.tests.shared.types.ArrayColumnTypeTests.testSelectUsingArraySlice */ fun ?> ExpressionWithColumnType.slice(lower: Int? = null, upper: Int? = null): ArraySlice = - ArraySlice(this, lower, upper, ArrayColumnType((this.columnType as ArrayColumnType).delegate)) + ArraySlice(this, lower, upper, this.columnType as ArrayColumnType) // Sequence Manipulation Functions diff --git a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/ops/AllAnyOps.kt b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/ops/AllAnyOps.kt index 3ddb2a7ebb..f04fbc7c11 100644 --- a/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/ops/AllAnyOps.kt +++ b/exposed-core/src/main/kotlin/org/jetbrains/exposed/sql/ops/AllAnyOps.kt @@ -44,10 +44,10 @@ class AllAnyFromSubQueryOp( */ class AllAnyFromArrayOp( isAny: Boolean, - array: Array, + array: List, private val delegateType: ColumnType -) : AllAnyFromBaseOp>(isAny, array) { - override fun QueryBuilder.registerSubSearchArgument(subSearch: Array) { +) : AllAnyFromBaseOp>(isAny, array) { + override fun QueryBuilder.registerSubSearchArgument(subSearch: List) { registerArgument(ArrayColumnType(delegateType), subSearch) } }